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.
buyenne
Homelab logs and metrics with Grafana Alloy: journald to Loki, metrics to Prometheus
My homelab has grown to a good dozen Linux hosts: Proxmox nodes, Docker VMs, a few VPSs. For a while every host had something different collecting logs and metrics: an old OpenTelemetry Collector here, a Docker Loki logging driver there, nothing at all somewhere else. Now every host runs Grafana Alloy with almost the same config:
- Logs: journald → Loki
- Host metrics: built-in node exporter → Prometheus
- Container metrics (Docker hosts only): built-in cAdvisor → Prometheus
Everything is pushed. Prometheus doesn’t need a scrape job per host and the hosts don’t need any open ports. And no, you don’t need Mimir for that: Prometheus can receive remote writes itself.
UPS shutdown with NUT over SNMP – Part 2: TrueNAS SCALE
This is the second half of a two-host setup on one shared UPS (APC Smart-UPS SMT1500RMI2U with an AP9630 network card). Part 1 explains the design and the Proxmox side. In short:
- Every host polls the UPS card directly over SNMP and shuts itself down. No NUT master that everyone depends on.
- Proxmox goes down at 50%, TrueNAS at 40%. The VMs that write to the NAS are stopped before the NAS itself shuts down.
- A read-only SNMP community means no host can cut power to the shared UPS.
Tested on TrueNAS SCALE 24.10 (Electric Eel), NUT 2.8.0. Everything here is done in the web UI, no shell editing needed.
UPS shutdown with NUT over SNMP – Part 1: Proxmox VE
My Proxmox host and my TrueNAS share one UPS: an APC Smart-UPS SMT1500RMI2U with an AP9630 (NMC2) network management card. No USB cable, just Ethernet/SNMP.
Until now NUT ran as a container on the Proxmox host and served everything else. That’s a classic single point of failure: if Proxmox goes down first, the NUT server goes with it and nobody else gets told anything.
The design
- No master/slave. Each host polls the UPS card itself over SNMP and shuts itself down.
- Staggered thresholds: Proxmox shuts down at 50% battery, TrueNAS only at 40%. That way every VM/container writing to NAS shares is already stopped cleanly before the NAS goes down (consumer before provider).
- Read-only SNMP community. No host can accidentally cut power to the shared UPS, even though NUT runs locally as
primary.
Part 2 covers the TrueNAS side. This part is about Proxmox VE 8 (Debian 12, NUT 2.8.0).
Running SeAT 5 in Docker: every problem I hit and how I fixed it
I run SeAT, the EVE Online corporation management tool, for our corp in Docker on a Proxmox LXC, managed with Dockge. Getting it from SeAT 4 to SeAT 5 and then keeping it healthy turned into a long series of problems. This post collects all of them in one place, with the fixes that actually worked, so the next person (or future me) doesn’t have to dig through logs again.
The stack is a split compose setup, so every command needs the full -f chain:
|
1 2 |
cd /opt/stacks/seat-exop docker compose -f docker-compose.yml -f docker-compose.mariadb.yml -f docker-compose.proxy.yml up -d |
Services are front, worker, scheduler, cache (Redis) and mariadb.
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.
Fixing “OSError: image file is truncated” in Paperless-ngx while keeping PDF/A
Paperless-ngx installation done by ttecks Helperscripts. Getting every now and then those errors. Changing scanners didn’t help. (Brother xxx -> Fujitsu FI-8150)
|
1 |
OSError: image file is truncated |
one solution mentioned on Github was to set the output format from PDF/A to plain PDF as a workaround. But I decided to keep PDF/A.
Hello world!
Welcome to WordPress. Few things broken after a migration. Fixing in progress!