OPNsense Automation & Tooling Landscape¶
Initial research: 2026-02-09 Purpose: Evaluate tools for increasing IaC coverage and operational insight
Structural Challenge¶
The OPNsense REST API doesn't expose system-level settings (hostname, SSH config, interface assignments, certificates). This forces a two-tier approach:
- API-based tools for data-heavy subsystems (firewall, DHCP, DNS, IDS, etc.)
- SSH/config.xml tools for system plumbing (identity, interfaces, SSH hardening)
Every serious OPNsense automation project uses both methods.
Ansible Collections¶
oxlorg.opnsense (our primary collection)¶
- GitHub: O-X-L/ansible-opnsense (437 stars)
- Galaxy:
oxlorg.opnsense(formerlyansibleguy.opnsense, renamed Sep 2024) - Version: 25.7.8 (Nov 2024)
- Method: REST API via
httpx - Modules: ~90+ (we currently use ~15)
Module Categories¶
| Category | Modules | Our Usage |
|---|---|---|
| Base/General | list, reload, raw, service, system |
raw heavily |
| Firewall | alias, rule, rule_multi, rule_purge, savepoint |
alias, rule, savepoint |
| NAT | nat_source, nat_one_to_one |
Not used |
| Interfaces | interface_vlan, interface_vxlan, interface_vip, interface_lagg, interface_loopback, interface_gre, interface_bridge, interface_gif |
interface_gif |
| Routing | route, gateway |
Not used |
| FRR (Dynamic Routing) | 25+ modules (BGP, OSPF, RIP, BFD) | Not used |
| Unbound DNS | unbound_general, unbound_acl, unbound_forward, unbound_dot, unbound_host, unbound_host_alias, unbound_dnsbl |
unbound_forward, unbound_host |
| DHCP (KEA) | dhcp_general, dhcp_subnet, dhcp_reservation, dhcp_controlagent |
All used |
| VPN - WireGuard | wireguard_server, wireguard_peer, wireguard_show, wireguard_general |
Not used |
| VPN - OpenVPN | openvpn_client, openvpn_server, openvpn_static_key, openvpn_status |
Not used |
| VPN - IPSec | 11 modules | Not used |
| IDS/IPS | ids_action, ids_general, ids_ruleset, ids_rule, ids_user_rule, ids_policy |
Not used (using raw) |
| Traffic Shaper | shaper_pipe, shaper_queue, shaper_rule |
Not used |
| HAProxy | 16 modules | Not used |
| Monit | monit_service, monit_alert, monit_test |
Not used |
| ACME/Certs | acme_account, acme_action, acme_general, acme_validation, acme_certificate |
Not used |
| Users/Access | user, group, privilege |
Not used |
| Other | package, cron, syslog |
package used |
High-Value Unused Modules¶
| Module | Gap It Closes | Coverage Impact |
|---|---|---|
gateway |
Gateway definitions (WAN_GW, HE_TUNNELV6) | Tier 3 → Tier 1 |
user, group |
User/group management | Tier 3 → Tier 1 |
monit_service, monit_alert, monit_test |
Monit monitoring (4 services, 10 tests) | Tier 3 → Tier 1 |
nat_source |
Outbound NAT rules | Tier 3 → Tier 1 |
route |
Static routes | Tier 3 → Tier 1 |
ids_general, ids_ruleset |
Replace raw IDS calls with idempotent modules |
Better idempotency |
syslog |
Replace raw syslog calls |
Better idempotency |
cron |
Replace raw cron calls |
Better idempotency |
unbound_general |
Replace raw Unbound general/advanced calls |
Better idempotency |
unbound_dot |
Replace raw DoT upstream calls |
Better idempotency |
unbound_dnsbl |
Replace raw DNSBL calls |
Better idempotency |
Known Gaps (No Module Available)¶
- System identity (hostname, domain, timezone) — no API
- SSH configuration — no API
- Interface assignments — no API
- Port forwarding / DNAT — open issue, planned for v26.1
- Certificate management (non-ACME) — open issue
- NAT mode (automatic/hybrid/manual) — not managed
- Node Exporter — no dedicated module (using
raw) - SNMP (net-snmp) — no dedicated module (using
raw)
puzzle.opnsense (SSH/config.xml complement)¶
- GitHub: puzzle/puzzle.opnsense (39 stars)
- Version: 2.0.0 (Nov 2025)
- Method: SSH + direct config.xml manipulation via Python lxml
- Maintained by: Puzzle ITC (Swiss IT company)
Modules¶
| Module | Purpose | Status |
|---|---|---|
system_settings_general |
Hostname, domain, timezone | Stable |
system_settings_logging |
Logging configuration | Stable |
firewall_alias |
Firewall aliases | Stable |
interfaces_assignments |
Interface assignments | Stable |
system_access_users |
User management | Deprecated (3.0.0) |
system_high_availability_settings |
HA/CARP | Deprecated (3.0.0) |
firewall_rules |
Firewall rules | Deprecated (3.0.0) |
Key Value¶
Fills exactly the two gaps the API cannot:
system_settings_general→ hostname, domain, timezone (currently 0% coverage)interfaces_assignments→ interface-to-port mapping (currently 0% coverage)
Puzzle ITC themselves use both collections in production: puzzle.opnsense for system
settings, oxlorg.opnsense for everything else.
Rosa-Luxemburgstiftung-Berlin/ansible-opnsense (reference — do not adopt wholesale)¶
- GitHub: Rosa-Luxemburgstiftung-Berlin/ansible-opnsense (23 stars)
- Version: 26.1.0 (Jan 2026), active single-maintainer (Klaus Zerwes)
- Method: SSH + config.xml fetch-edit-push (Ansible role, not collection)
- Architecture: Fetches entire config.xml → patches via XPath (community.general.xml) → pushes entire file back + reloads all services
- Scope: Comprehensive — sysctl, interfaces, NAT, VLANs, users, gateways, VPN, certs, HA, cron, monit, UPS
- Risk: Full-file push conflicts with API-managed settings — designed as sole config tool, not a companion
Gap Coverage (what it can do that our API stack cannot)¶
| Our Gap | Covered? | XPath Pattern |
|---|---|---|
| Sysctl tunables | Yes | /opnsense/sysctl/item[tunable/text()='...']/value |
| Interface assignments | Yes | /opnsense/interfaces/{{ name }}/{{ key }} |
| NAT mode + rules | Yes | /opnsense/nat/... |
| NTP servers | Yes | system/timeservers in general settings |
| Certificate management | Yes | Base64 cert/key/CA, UUID-aware |
| radvd/DHCPv6 | No | DHCPv4 only |
| SSH hardening | No | Not in scope |
| powerd/amdtemp | No | NUT only (UPS, not CPU power) |
Strategic Value¶
Do not adopt the role — the full-file config.xml push would overwrite API-managed changes. Instead, mine the XPath patterns as reference for building our own surgical config.xml tasks using puzzle.opnsense SSH or community.general.xml within our existing role. The variable structures are clean and well-documented.
Proof of Concept (Validated)¶
We built a config.xml schema analyzer (scripts/opnsense-config-schema.py) and a
sample Ansible task file (roles/opnsense/tasks/config-xml-sysctl.yml) that demonstrate:
- Schema extraction — reads config.xml and maps XPath patterns for any section
- Ansible var generation — outputs ready-to-paste variable YAML from current config
- Task generation — produces Ansible task YAML using
community.general.xml - Schema diffing — compares two config.xml versions and flags changes (the "self-maintaining" mechanism)
Tested against Owl's production config.xml (42 sysctl items, 7 interfaces, 1 cert). The diff tool successfully detected all simulated upgrade changes (version bump, added/removed tunables, new system fields, new interfaces).
# Extract schema for a section
python3 scripts/opnsense-config-schema.py extract config.xml -s sysctl
# Generate Ansible vars from current config
python3 scripts/opnsense-config-schema.py generate config.xml -s sysctl
# Detect schema drift after OPNsense upgrade
python3 scripts/opnsense-config-schema.py diff old-config.xml new-config.xml
# Generate Ansible task YAML for a section
python3 scripts/opnsense-config-schema.py task -s sysctl
The sysctl task file uses Rosa-Luxemburg's with_nested × fields pattern within our
SSH play, keeping it safe alongside API-managed subsystems.
MCP Servers¶
Currently Using: vespo92/OPNSenseMCP¶
- v0.9.4 (latest as of Feb 2026, published Dec 8, 2025)
- 111 purpose-built tools, SSH access, auto-repair features
- Development slowed after Dec 2025 burst
Alternative: Pixelworlds/opnsense-mcp-server (evaluated — not adopting)¶
- GitHub: Pixelworlds/opnsense-mcp-server (23 stars)
- npm:
@richard-stovall/opnsense-mcp-serverv0.5.3 - 88 module tools wrapping 2,000+ API methods (752 core + 1,271 plugin)
- Last commit: Jun 2025 — stale for 8+ months
- No SSH access — API-only, so it has the same gaps as our oxlorg.opnsense stack
Why Not Adopt¶
- Poor AI ergonomics: Tools are thin wrappers around raw API methods (e.g.,
core_unbound_settings_get). Claude must already know the OPNsense API schema to use them effectively — the tool names don't describe what they do. - No domain logic: No auto-repair, no diagnostics, no compound operations. vespo92 has purpose-built tools like
routing_diagnosticsandnat_fix_dmzthat chain multiple API calls. - Stale development: No commits since Jun 2025 vs. vespo92's Dec 2025 activity.
- Massive tool surface: 88 tools pollute the MCP tool namespace. Most are never useful in a conversation.
When It Might Help¶
If we hit a specific API endpoint that vespo92 doesn't cover, the Pixelworlds source code is a good reference for the endpoint URL and parameter schema. But installing it as a running MCP server adds no value over using oxlorg.opnsense.raw in Ansible or the Python API client.
Monitoring MCP Servers¶
| Server | Stars | What It Enables |
|---|---|---|
| grafana/mcp-grafana (official) | 2,300 | Query dashboards, PromQL via Grafana, manage alerts. 40+ tools. |
| pab1it0/prometheus-mcp-server | ~200 | Direct PromQL queries, metric discovery. Docker-based. |
| kaznak/alertmanager-mcp | 8 | Alert retrieval, silence management. |
The Grafana MCP can proxy PromQL through Grafana's datasource, making a separate
Prometheus MCP optional. Point at http://192.168.194.131:3000.
Terraform Provider¶
browningluke/terraform-provider-opnsense¶
- GitHub: browningluke/terraform-provider-opnsense (141 stars)
- Version: 0.16.1 (Nov 2025) — pre-1.0, not production-ready
- Manages: firewall aliases/rules, NAT, VIPs, VLANs, IPsec, routes, gateways
- Partially implemented: DHCP (Kea), Unbound DNS, WireGuard
- Watch for 1.0 release before adopting
config.xml Analysis Tools¶
opnDossier¶
- GitHub: EvilBit-Labs/opnDossier (Go, 12 stars)
- Security analysis: insecure protocols, weak configs, credential exposure
- Dead rule detection: unreachable/duplicate firewall rules
- Unused resource detection: interfaces, aliases, services
- Export: JSON, YAML, Markdown
- Runs fully offline/airgapped
OPNReport¶
- GitHub: AndyX90/OPNReport (Python, 67 stars)
- Converts config.xml to readable Markdown/YAML documentation
Python API Client¶
O-X-L/opnsense-api-client¶
- Same maintainer as our Ansible collection
- 150+ modules, dry-run support, proper typing
pip install oxl-opnsense-client- Useful for one-off scripts outside Ansible's declarative model
Monitoring & Observability¶
Prometheus Exporters (already deployed)¶
- AthennaMind/opnsense-exporter (221 stars, v0.0.12, Jan 2026) — our standard
Log Analysis (future consideration)¶
| Tool | Stack | Fit for Us |
|---|---|---|
| LogSense2Loki | Syslog → JSON → Loki → Grafana | Best fit (lightweight, uses existing Grafana) |
| opnsense-grafana-loki | Alloy → Loki → Grafana geo maps | Alternative Loki path |
| pfelk (1,200 stars) | Full ELK stack | Gold standard but resource-heavy |
| OPNsense-Dashboard (655 stars) | InfluxDB + Grafana + Graylog | Full monitoring stack |
Action Plan¶
Quick Wins (use existing oxlorg.opnsense modules)¶
- Switch
raw→ dedicated modules for IDS, syslog, cron, Unbound — fixes idempotency - Add
gatewaymodule — manage WAN_GW, HE_TUNNELV6 - Add
user/groupmodules — manage admin accounts - Add
monit_*modules — manage service monitoring
Medium-Term¶
- Install
puzzle.opnsense— hostname/domain/timezone + interface assignments - Build surgical config.xml tasks — mine Rosa-Luxemburg XPath patterns for sysctl, NAT, certs
- Add
grafana/mcp-grafanaMCP server — monitoring queries in Claude sessions - Run opnDossier against Owl + Blue configs — automated security audit baseline
Watch List¶
- browningluke Terraform provider — monitor for 1.0
- LogSense2Loki — firewall log analysis in Grafana when ready