Skip to content

OPNsense

The OPNsense adapter is FreeSDN’s primary firewall brain - it manages an OPNsense firewall/gateway over the OPNsense REST API. It covers 13 feature domains end-to-end and is the recommended choice when you need a fully orchestrated Layer 2/3 gateway alongside Omada or MikroTik limbs.

FactDetail
MaturityProduction
Gold-standard contractDG ✓ CB ✓ RR ✓ TS ✓ SSRF ✓ RG ✓
Feature domains13
DomainCapabilities
Firewall rulesRule CRUD, reorder, alias management
NATPort-forward, outbound NAT, 1:1 NAT
DHCPScopes, reservations, static mappings
DNSUnbound resolver config, overrides
VPNOpenVPN server/client CRUD, IPsec phase-1/phase-2 tunnels, WireGuard peers and interfaces
Cron / Scheduled tasksJob CRUD (create, update, delete), staging
RoutingStatic routes, routing table (read), gateway health (read)
IDS/IPSSuricata rule-set config, enable/disable, alert reads
Traffic shaperPipe and queue management
ServicesHAProxy, DHCP relay, NTP
DiagnosticsARP/NDP tables, gateway monitoring, live log tail
InterfacesInterface list, IP assignments, VLAN sub-interfaces, ARP/NDP tables
SystemSystem info, firmware status, CARP status (read-only), backup/restore of config.xml

Twelve of the 13 domains support read + stage + apply via the dual-gate pipeline. The Diagnostics domain exposes live direct-action endpoints (ping, traceroute, DNS lookup) that execute immediately rather than staging - nothing in that domain is genuinely state-changing, so the staging machinery would add latency and audit-log noise with no benefit.

GatewayDetailPage renders 18 tabs when the controller vendor is opnsense:

overview, interfaces, rules, NAT, aliases, DHCP, DNS, VPN, routing, services, IDS, shaper, diagnostics, logs, monitoring, sync, backups, system.

The adapter mounts 13 separate routers - one per feature domain:

/api/v1/gateway-opnsense-firewall/
/api/v1/gateway-opnsense-nat/
/api/v1/gateway-opnsense-dhcp/
/api/v1/gateway-opnsense-dns/
/api/v1/gateway-opnsense-vpn/
/api/v1/gateway-opnsense-routing/
/api/v1/gateway-opnsense-ids/
/api/v1/gateway-opnsense-shaper/
/api/v1/gateway-opnsense-services/
/api/v1/gateway-opnsense-diagnostics/
/api/v1/gateway-opnsense-system/
/api/v1/gateway-opnsense-interfaces/
/api/v1/gateway-opnsense-cron/

Staged changes are applied via the shared POST /api/v1/gateway-vpn/changes/{change_id}/apply endpoint using opnsense.* feature prefixes - the apply path dispatches to the correct OPNsense service based on the feature prefix (e.g., opnsense.firewall.*GatewayOpnsenseFirewallService). The /api/v1/gateway-firewall/ routes are Omada-only and never dispatch to OPNsense.

The OPNsense adapter authenticates with an API key + secret pair generated on the OPNsense firewall.

  1. Log in to OPNsense → System → Users → Edit the admin user (or create a dedicated freesdn user).
  2. Under API keys, click + to generate a new key.
  3. Copy the Key and Secret - the secret is shown only once.
  4. Ensure the user has the API privilege and, for write operations, the relevant service privileges.
FieldValue
credential_typeapi_key
api_keyThe key string from OPNsense
passwordThe secret string from OPNsense

Point host at the base HTTPS URL of your OPNsense instance:

https://opnsense.example.com

OPNsense defaults to port 443; include a port only if you have changed it (e.g., https://opnsense.example.com:4443).

Terminal window
# Create the controller record (credentials are stored inline; there is no credential_id parameter)
curl -X POST https://<freesdn-host>/api/v1/controllers \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>" \
-H "Content-Type: application/json" \
-d '{
"name": "opnsense-prod",
"controller_type": "opnsense",
"host": "https://opnsense.example.com",
"port": 443,
"site_id": "<site-uuid>",
"username": "<opnsense-api-key>",
"password": "<opnsense-api-secret>"
}'
# Trigger discovery
curl -X POST https://<freesdn-host>/api/v1/discovery/controllers/<controller-id> \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>"

OPNsense is typically the firewall protecting your environment - treat writes with care.

  1. Set ADAPTER_READ_ONLY=false in your environment file (.env.pro, .env.max, etc.).
  2. Restart the API: docker compose --env-file .env.pro up -d api.
  3. Stage a change in the FreeSDN UI (e.g., add a firewall rule). The change is persisted to the pending-changes table and nothing is sent to OPNsense yet.
  4. Navigate to Pending Changes, review the staged row, and confirm with force: true.

Both conditions must be satisfied simultaneously. A staged change sitting in pending will remain there indefinitely until you explicitly apply it.

OPNsense is the recommended brain in the FreeSDN layered network architecture. In this role it:

  • Holds the authoritative canonical VLAN list for the site.
  • Distributes VLANs to connected limbs (Omada switches, MikroTik access ports) via the POST /api/v1/network/vlans/distribute endpoint.
  • Exposes drift detection - compare the desired canonical VLAN state against what is running on each limb at GET /api/v1/network/vlans/alignment.
  • CARP HA pair status is readable; orchestrated failover promotion is not supported.
  • pfBlockerNG and Suricata package management beyond built-in IDS rule-set config is out of scope.