Skip to content

OPNsense monitoring

The firewall is monitored over the LAN by two exporters that feed the Prometheus stack in monitoring/:

  • os-node-exporter plugin on OPNsense. CPU, RAM, load, uptime, filesystem, swap, and NIC counters (node_*) under the opnsense-node job.
  • opnsense-exporter container (monitoring/compose.yaml). Gateways, API health, firmware, services, and interface counters pulled from the OPNsense API (job opnsense-api). Its LAN endpoint is supplied through the private monitoring environment rather than repeated in public documentation.

Dashboard: OPNsense Firewall (uid: opnsense). Alerts: monitoring/prometheus/rules/opnsense.yml.

One-time GUI setup

SSH to OPNsense is read-only, so do all of this in the web UI.

  1. Install the node-exporter plugin. System > Firmware > Plugins, install os-node-exporter. Then Services > Node Exporter: enable it, listen on the LAN interface, port 9100, and turn on these collectors:

  2. CPU Statistics

  3. Filesystem Statistics
  4. Memory Statistics
  5. Network Interface Statistics

CPU supplies utilization and Filesystem supplies root-capacity monitoring. Uptime is exported automatically. The dashboard does not use the EXEC, NTP, Device, or ZFS collectors. Confirm from the server that the configured LAN scrape endpoint returns metrics. 2. Create a read-only monitoring user and API key. System > Access > Users, add a dedicated monitoring user (no shell, no GUI). Give it a group whose privileges are limited to exactly these 8 pages (using the exact OPNsense privilege names): System: Gateways, System: Status, System: Firmware, Status: Services, Reporting: Traffic, Diagnostics: ARP Table, Diagnostics: Firewall statistics, Diagnostics: Netstat. Do not grant the Unbound, VPN, Kea, or Cron pages: the corresponding exporters are outside this dashboard's scope and are disabled in Compose. Generate an API key, paste the key and secret into monitoring/.env on the server as OPNSENSE_EXPORTER_OPS_API_KEY and _SECRET. 3. Firewall rule. Confirm the monitoring host can reach the node-exporter endpoint over the LAN. The default LAN-to-firewall allow usually covers this.

What is monitored

The dashboard shows current WAN status, RTT, jitter, loss, and throughput plus their 24-hour history; API health; host CPU, memory, normalized load, filesystem, swap, and uptime; firmware and reboot state; interface traffic and errors in both directions; service history; and actionable API endpoint errors.

opnsense-exporter v0.0.16 cannot parse one very large protocol-statistics counter that this firewall returns. The resulting api/diagnostics/interface/get_protocol_statistics error is a known upstream limitation (AthennaMind/opnsense-exporter#112), so it is excluded from the actionable-error panel and its alert. Every other endpoint error stays visible and alerts after repeated failures. This dashboard does not use the protocol statistics.

Two more v0.0.16 quirks are handled explicitly:

  • OPNsense 26.1 omits metadata.Firewall from api/core/system/status, which makes the exporter's opnsense_firewall_status falsely report 0. The dashboard and alerts use the reliable opnsense_up API-health metric instead.
  • The exporter reports a zero gateway high-latency threshold on this installation, so the latency alert and graph fall back to 100 ms when no positive configured threshold is available.

The OPNsense node-exporter exposes no temperature metric on this hardware, so normalized one-minute load fills the panel and alert that would otherwise track temperature.

After deploying, confirm the new series exist before trusting the panels:

curl -s 'http://localhost:9090/api/v1/query?query=node_load1%7Bjob%3D%22opnsense-node%22%7D'
curl -s 'http://localhost:9090/api/v1/query?query=node_filesystem_size_bytes%7Bjob%3D%22opnsense-node%22%2Cmountpoint%3D%22%2F%22%7D'
curl -s 'http://localhost:9090/api/v1/query?query=opnsense_exporter_endpoint_errors_total%7Bjob%3D%22opnsense-api%22%7D'

Deploy

Deploy the four Compose projects through Ansible:

cd /opt/homelab
git pull
cd ansible
ansible-playbook -c local playbooks/deploy.yml

Run deploy.yml first so it renders the tracked rule or scrape-config change into .generated/monitoring, then reload Prometheus:

docker exec prometheus wget -qO- --post-data= http://localhost:9090/-/reload

If Alertmanager configuration changed, reload it without restarting the container:

docker kill --signal HUP alertmanager

Grafana normally reloads provisioned dashboards within 30 seconds.