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.

Fact Detail
Maturity Production
Gold-standard contract DG ✓ CB ✓ RR ✓ TS ✓ SSRF ✓ RG ✓
Feature domains 13
Domain Capabilities
Firewall rules Rule CRUD, reorder, alias management
NAT Port-forward, outbound NAT, 1:1 NAT
DHCP Scopes, reservations, static mappings
DNS Unbound resolver config, overrides
VPN OpenVPN server/client CRUD, IPsec phase-1/phase-2 tunnels, WireGuard peers and interfaces
Cron / Scheduled tasks Job CRUD (create, update, delete), staging
Routing Static routes, routing table (read), gateway health (read)
IDS/IPS Suricata rule-set config, enable/disable, alert reads
Traffic shaper Pipe and queue management
Services HAProxy, DHCP relay, NTP
Diagnostics ARP/NDP tables, gateway monitoring, live log tail
Interfaces Interface list, IP assignments, VLAN sub-interfaces, ARP/NDP tables
System System 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.
Field Value
credential_type api_key
api_key The key string from OPNsense
password The 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.

All product names, logos, and brands are property of their respective owners. FreeSDN is an independent project and is not affiliated with or endorsed by the vendors it integrates with. See Trademarks.