pfSense
The pfSense adapter manages pfSense firewall/gateway devices. It uses its own REST client (PfSenseClient) targeting the pfSense REST API package endpoints under /api/v2/, with Authorization: {api_key} {api_secret} header authentication - there is no form-token handling or XML config marshalling. It shares the same dual-gate write contract and audit-logging patterns as the OPNsense adapter, but the two clients are completely independent. If you are deciding between pfSense and OPNsense, both adapters are production-grade; OPNsense has broader domain coverage (13 vs 10 domains).
| Fact | Detail |
|---|---|
| Maturity | Production |
| Gold-standard contract | DG ✓ CB ✓ RR ✓ TS ✓ SSRF ✓ RG ✓ |
| Feature domains | 10 |
What it manages
Section titled “What it manages”| Domain | Capabilities |
|---|---|
| Firewall | Rule CRUD, alias management |
| NAT | Port-forward, outbound NAT |
| DHCP | Scopes and static mappings |
| DNS | Resolver config, overrides |
| VPN | IPsec + OpenVPN + WireGuard tunnel CRUD |
| Routing | Static routes, gateway list, gateway status monitoring |
| Services | System service list + start/stop/restart (unbound, dhcpd, openvpn, etc.) |
| Diagnostics | ARP table, system/firewall log tail, ping/traceroute/DNS-lookup probes |
| Interfaces | Interface list and config read |
| System | Config backup/restore, system info |
Eight domains support the full read + stage + apply cycle via the dual-gate. Two domains differ: Diagnostics (ping / traceroute / DNS-lookup) are direct non-staged probes - there is no /changes/{feature} endpoint for this domain, as none of the operations are genuinely state-changing. Routing staging is wired for shape-parity with OPNsense, but apply returns 501 because the pfSense client does not yet expose static-route writes.
Frontend pages
Section titled “Frontend pages”GatewayDetailPage renders 18 tabs when the controller vendor is pfsense (same tab set as OPNsense - features not present for a given domain gracefully show an empty state rather than an error).
Backend route prefixes
Section titled “Backend route prefixes”/api/v1/gateway-pfsense-firewall//api/v1/gateway-pfsense-nat//api/v1/gateway-pfsense-dhcp//api/v1/gateway-pfsense-dns//api/v1/gateway-pfsense-vpn//api/v1/gateway-pfsense-routing//api/v1/gateway-pfsense-services//api/v1/gateway-pfsense-diagnostics//api/v1/gateway-pfsense-interfaces//api/v1/gateway-pfsense-system/Connection requirements
Section titled “Connection requirements”The pfSense adapter connects via the pfSense REST API package (endpoints under /api/v2/). It authenticates with an API key and secret sent as an Authorization header - no web-UI session or form-token handling is required.
Connection credentials
Section titled “Connection credentials”pfSense does not use FreeSDN’s generic Credential store. The API key and secret are passed directly in the gateway creation body and stored (encrypted) on the GatewayConnection record:
| Field on gateway body | Value |
|---|---|
api_key | pfSense REST API key (generated in System → API Keys) |
api_secret | Corresponding API secret |
No separate POST /api/v1/credentials step is needed.
Controller URL
Section titled “Controller URL”Point host at the base HTTPS URL of your pfSense instance:
https://pfsense.example.comAdding the controller
Section titled “Adding the controller”# Create the controller record - credentials are passed inline (no separate credential-store step)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": "pfsense-prod", "controller_type": "pfsense", "host": "https://pfsense.example.com", "port": 443, "site_id": "<site-id>", "username": "<pfsense-api-key>", "password": "<pfsense-api-secret>" }'
# Trigger discoverycurl -X POST https://<freesdn-host>/api/v1/discovery/controllers/<controller-id> \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>"Enabling write operations
Section titled “Enabling write operations”Firewall writes change live network policy. Use the staged pipeline deliberately.
- Set
ADAPTER_READ_ONLY=falsein your environment file. - Restart the API:
docker compose --env-file .env.pro up -d api. - Stage a change in the FreeSDN UI. The pending row is created in the database; no call is made to pfSense yet.
- Review and approve the change in Pending Changes with
force: true.
Known limitations
Section titled “Known limitations”- pfBlockerNG package management is out of scope (only base pfSense covered).
- Suricata package management (via pfBlockerNG/Suricata GUI) is not covered.
- HA XML-RPC sync orchestration is not supported (pfSense handles its own sync).
- The pfSense adapter covers fewer domains (10) than OPNsense (13); specifically, OSPF/BGP routing, IDS/IPS, and traffic shaping are not exposed.
pfSense vs OPNsense
Section titled “pfSense vs OPNsense”Both adapters are production-grade and follow the same dual-gate write contract and audit-logging patterns, but their HTTP clients are completely independent implementations. Key differences:
| pfSense | OPNsense | |
|---|---|---|
| Domains | 10 | 13 |
| OSPF/BGP routing | No | No (MikroTik only) |
| IDS/IPS (Suricata) | No | Yes (rule-set config) |
| Traffic shaper | No | Yes |
| Authentication | API key + secret (Authorization: key secret header) | API key + secret (HTTP Basic Auth) |
| API style | REST API (JSON, /api/v2/) | REST API (JSON, /api/{module}/{controller}/{action}) |
If both firewalls are available in your environment and you need IDS management from FreeSDN, prefer OPNsense. For OSPF/BGP dynamic routing, use the MikroTik adapter.
See also
Section titled “See also”- Adapter Overview - maturity tiers and the full vendor matrix
- OPNsense - broader domain coverage (13 vs 10 domains); same dual-gate contract, independent client implementation
- MikroTik RouterOS - alternative firewall brain