My OPNsense firewall was still on 25.7.11_9, while the firmware page offered 26.7.7. That is two major releases in one go: 26.1 moved ISC DHCP out of the core, and 26.7 switched the base system from FreeBSD 14.3 to 15.1 and OpenSSL from 3.0 to 3.5. To make it more interesting, the box was installed on UFS years ago, so there was no ZFS boot environment or snapshot to roll back to. This post covers what changed, what I cleaned up beforehand, how the upgrade went and what the logs said afterwards.
OPNsense
Isolating a guest VLAN on OPNsense with a Ruckus AP: no sneaking through to the main network
My Ruckus access point broadcasts a dedicated guest SSID and tags that traffic with a separate VLAN before handing it to OPNsense. The AP side is easy – Ruckus does the tagging reliably. The router side is where things go wrong if the firewall rules are in the wrong order or a step gets skipped. Here is the full setup I use to make sure a guest really cannot reach anything on the internal network.
Split-Horizon DNS with Technitium and OPNsense: Resolving Internal Hosts Locally (plus Let’s Encrypt via DNS-01)
My home network uses Technitium DNS as the primary DNS server and OPNsense as the router. I own a public domain (in this post I’ll use domain.com as a placeholder), and I wanted truenascale.domain.com to point to my TrueNAS SCALE box on the LAN instead of being resolved somewhere on the internet. On top of that, I wanted a proper TLS certificate for it without exposing the NAS to the outside world.
Network Monitoring with Prometheus & SNMP Exporter in the Homelab
Why SNMP Exporter instead of LibreNMS?
Anyone who’s done network monitoring before knows the usual suspects: Nagios, Zabbix, LibreNMS. These tools come with everything — SNMP discovery, device inventory, maps, alerting — but also their own database, their own visualization layer, and their own operational overhead.
In a homelab that already runs Prometheus, Grafana, and Loki, there’s little reason to add LibreNMS on top. The Prometheus SNMP Exporter fits seamlessly into an existing stack: it’s a single container that accepts SNMP queries and returns them as Prometheus metrics.
In this post I’ll walk through how I’m monitoring OPNsense, a Ruckus R720 AP, managed switches, Proxmox nodes, and a Brother printer with it.
Preparing devices: enabling SNMP
OPNsense
Go to Services → SNMP: enable the service, set a community string (e.g. homelab), bind to the LAN interface.
Ruckus R720
In the web UI under System → SNMP: enable SNMPv2c, enter the community string.
Proxmox nodes
On each node in the shell:
|
1 |
apt install snmpd -y |
Edit /etc/snmp/snmpd.conf:
|
1 2 |
rocommunity homelab 10.0.0.0/24 agentAddress udp:161 |
|
1 |
systemctl enable --now snmpd |
Managed switch & Brother printer
Varies by vendor — enable SNMP in the management UI and set the community string. On the Brother DCP-L8410CDW the option is under Network → Protocol → SNMP.
Docker Compose (Dockge)
|
1 2 3 4 5 6 7 8 9 10 11 |
services: snmp-exporter: image: prom/snmp-exporter:latest container_name: snmp-exporter restart: unless-stopped ports: - "9116:9116" volumes: - ./snmp.yml:/etc/snmp_exporter/snmp.yml:ro command: - '--config.file=/etc/snmp_exporter/snmp.yml' |
Place snmp.yml in the same directory as the compose file.
snmp.yml — configuration
The official snmp.yml from the repository ships with ready-made modules for hundreds of device types and is the recommended starting point:
|
1 2 |
curl -Lo snmp.yml \ https://raw.githubusercontent.com/prometheus/snmp_exporter/main/snmp.yml |
For a leaner custom config (compatible with snmp_exporter v0.26+):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# snmp.yml auths: homelab_v2: community: homelab # replace with your community string version: 2 modules: # Standard IF-MIB — works for OPNsense, switches, Proxmox, Ruckus if_mib: walk: - 1.3.6.1.2.1.2 # interfaces - 1.3.6.1.2.1.31.1.1 # ifXTable metrics: - name: ifOperStatus oid: 1.3.6.1.2.1.2.2.1.8 type: gauge indexes: - labelname: ifIndex type: Integer lookups: - labels: [ifIndex] labelname: ifDescr oid: 1.3.6.1.2.1.2.2.1.2 type: DisplayString - name: ifHCInOctets oid: 1.3.6.1.2.1.31.1.1.1.6 type: counter indexes: - labelname: ifIndex type: Integer lookups: - labels: [ifIndex] labelname: ifName oid: 1.3.6.1.2.1.31.1.1.1.1 type: DisplayString - name: ifHCOutOctets oid: 1.3.6.1.2.1.31.1.1.1.10 type: counter indexes: - labelname: ifIndex type: Integer lookups: - labels: [ifIndex] labelname: ifName oid: 1.3.6.1.2.1.31.1.1.1.1 type: DisplayString # System info — uptime, description system: walk: - 1.3.6.1.2.1.1 metrics: - name: sysUpTime oid: 1.3.6.1.2.1.1.3 type: gauge - name: sysDescr oid: 1.3.6.1.2.1.1.1 type: DisplayString # Brother printer — toner levels, status, page count brother_printer: walk: - 1.3.6.1.2.1.43 # Printer-MIB (standard) - 1.3.6.1.4.1.2435 # Brother enterprise OID metrics: - name: printerStatus oid: 1.3.6.1.2.1.25.3.5.1.1 type: gauge indexes: - labelname: hrDeviceIndex type: Integer - name: tonerRemaining oid: 1.3.6.1.2.1.43.11.1.1.9 type: gauge indexes: - labelname: markerColorantIndex type: Integer lookups: - labels: [markerColorantIndex] labelname: tonerColor oid: 1.3.6.1.2.1.43.12.1.1.4 type: DisplayString |
Note on the Brother page counter: OIDs under 1.3.6.1.4.1.2435 are model-specific. The best way to find the right one for your printer is to run snmpwalk -v2c -c homelab <IP> 1.3.6.1.4.1.2435 and look for a counter that increments with each print job. The standard Printer-MIB (1.3.6.1.2.1.43) is model-independent and reliably covers toner levels.
Prometheus scrape config
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
scrape_configs: - job_name: snmp_opnsense static_configs: - targets: ['10.0.0.1'] # OPNsense IP metrics_path: /snmp params: module: [if_mib] auth: [homelab_v2] relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: snmp-exporter:9116 - job_name: snmp_ruckus static_configs: - targets: ['10.0.0.x'] # Ruckus R720 IP metrics_path: /snmp params: module: [if_mib] auth: [homelab_v2] relabel_configs: &snmp_relabel - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: snmp-exporter:9116 - job_name: snmp_proxmox_nodes static_configs: - targets: - '10.0.0.x' - '10.0.0.y' metrics_path: /snmp params: module: [if_mib, system] auth: [homelab_v2] relabel_configs: *snmp_relabel - job_name: snmp_switch static_configs: - targets: ['10.0.0.x'] metrics_path: /snmp params: module: [if_mib] auth: [homelab_v2] relabel_configs: *snmp_relabel - job_name: snmp_brother static_configs: - targets: ['10.0.0.x'] # printer IP metrics_path: /snmp params: module: [brother_printer] auth: [homelab_v2] relabel_configs: *snmp_relabel |
Testing it
Once the container is running, query a device directly to verify everything works:
|
1 |
curl "http://localhost:9116/snmp?target=10.0.0.1&module=if_mib&auth=homelab_v2" |
You should see Prometheus-formatted metrics. An empty response usually means a firewall issue — UDP 161 needs to be open from the exporter host to the target devices.
Grafana dashboards
Ready-made dashboards on grafana.com that work with these metrics out of the box:
- 11169 — SNMP interface monitoring (generic)
- 21491 — OPNsense
- 10347 — Proxmox (SNMP)
For the printer, a simple hand-built dashboard works well — toner colors come through as labels directly from the SNMP walk.
Wrap-up
The SNMP Exporter is the leanest way to bring network devices into an existing Prometheus/Grafana stack. No extra database backend, no separate web UI — just one exporter container and a few lines of config. If you already have the stack running, it’s a much cleaner solution than standing up LibreNMS or Zabbix alongside it.