Monitor NAS (or any SNMP device) that can't run the Beszel agent by making them appear as normal systems in your existing Beszel hub, with real metrics: CPU %, RAM %, disk %, temperature, up/down, network bandwidth, load average, disk I/O, a disk-alive / RAID-degraded health signal, and per-disk entries in Beszel's native S.M.A.R.T. table (model, capacity, health, temperature over SNMP — plus power-on hours & cycles and the full attribute table read over SSH, no agent installed on the NAS).
Built for two NAS specifically:
- QNAP TS-851 (SNMP works well — net-snmp based)
- Buffalo TeraStation TS5400D (older; SNMP is more limited — see its doc)
One container polls the NAS over SNMP v2c and talks to the hub over the same WebSocket + CBOR protocol the official Beszel agent uses. Your hub stays unmodified.
The bridge builds on the chaugan/beszel-snmp
fork, which reuses Beszel's own protocol code to speak to the hub. We pin it
to a known commit and apply a single patch that teaches it to report
CPU/RAM/disk/temperature, bandwidth, load, disk I/O and full S.M.A.R.T. and to
stay wire-compatible with a stock hub (the upstream fork targeted a modified
hub and only did environmental sensors).
Full details: docs/architecture.md.
QNAP ─┐ SNMP/161
├─► baszel-snmp-bridge ──WebSocket(CBOR, X-Token)──► Beszel hub :8090
Buffalo─┘ (this repo) (unchanged)
🇫🇷 Guide pas-à-pas personnalisé (IP réelles, token, alertes) : SETUP-FR.md
On your Linux / Proxmox LXC host (Docker required):
# 1. Secrets + hub connection
cp .env.example .env
$EDITOR .env # BESZEL_HUB_URL, universal token, hub public key
# 2. Devices + OIDs
cp config/snmp-monitor.example.json config/snmp-monitor.json
$EDITOR config/snmp-monitor.json # NAS IPs, community, verify OID indexes
# 3. Build & run
docker compose up -d --build
docker compose logs -fThen:
- Bridge status/OID editor UI →
http://<host>:6655 - Your two NAS appear in the Beszel hub within a poll or two.
Before that works you must:
- Enable SNMP on each NAS — QNAP · Buffalo.
- Create a universal token on the hub and copy the hub public key into
.env(both explained in.env.example). - Verify/adjust the OIDs for your firmware — docs/oid-reference.md.
Full acceptance checklist: docs/verification.md.
.
├── Dockerfile # clones pinned fork, applies patch, builds snmp-monitor
├── docker-compose.yml # the one service
├── .env.example # hub URL / universal token / hub key / tuning
├── patches/
│ └── 0001-snmp-nas-metrics-and-stock-hub-compat.patch # our change to the fork
├── config/
│ └── snmp-monitor.example.json # the two NAS, with starter OIDs to verify
└── docs/
├── architecture.md # design, protocol, CBOR compat, up/down, limits
├── oid-reference.md # category→metric mapping, discovery recipe
├── enable-snmp-qnap.md
├── enable-snmp-buffalo.md
└── verification.md # build/run/verify + troubleshooting
The bridge binary itself is not vendored here — the Dockerfile fetches the
pinned upstream fork and applies patches/0001-…. That keeps this repo small and
the change we maintain to a single, reviewable diff.
| Approach | NAS in Beszel? | Robustness | Effort / maintenance |
|---|---|---|---|
A. Extend beszel-snmp fork ← chosen |
✅ native systems | Protocol handled by Beszel's own code | Patch a pinned Go fork |
| B. From-scratch fake agent (Python) | ✅ | High, ongoing | |
| C. Fork the official agent, swap gopsutil→SNMP | ✅ | ✅ | Invasive Go rewrite, 1 process/NAS — dominated by A |
D. snmp_exporter + Grafana / LibreNMS / Zabbix |
❌ separate dashboard | ✅✅ purpose-built | Low, but not in Beszel |
A was chosen because the goal is single pane of glass in Beszel, and A gets the robustness of Beszel's real transport while limiting our own code to the easy, low-stakes SNMP→metric mapping.
If keeping the NAS inside Beszel is not a hard requirement — or if the Buffalo turns out to expose too little over SNMP — option D is the sturdier road. That trade-off is discussed in architecture.md.
Running on the Proxmox host at /opt/stack/baszel-snmp, against a Beszel
0.18.7 hub. End-to-end verified:
- Both NAS registered and stably "up", zero connection churn.
- Real metrics flowing (QNAP CPU/RAM/temps/volume + per-disk temp & status; Buffalo CPU/RAM/array + per-disk status).
- Bandwidth & load average on both NAS — bandwidth from IF-MIB counters
(QNAP eth0+eth1 summed, Buffalo eth0); load from SSH
/procon the QNAP and SNMPlaLoadInton the Buffalo. Disk I/O on the QNAP (SSH/proc/diskstats, e.g.1.07 MB/sread). Confirmed decoded by the stock hub (QNAPb:[…],dio:[…],la:[…]; Buffalob:[418,372],la:[0.09,0.07,0.1]). - Disk I/O not available on the Buffalo — no UCD
diskIOmodule and SSH is closed; no temperature over SNMP either. Everything else works SNMP-pure. - Disk health: QNAP RAID 5
Ready, all 4 disksGood; Buffalo array healthy. - Native S.M.A.R.T. table populated: QNAP 4× Seagate 8 TB — model, serial, capacity, temp, power-on hours + cycles + full attribute table (read from QTS's own SMART cache over SSH, no install); Buffalo 4× Seagate 4 TB (PASSED). Refreshed every 5 min.
The bridge speaks the modern (0.13+) AgentResponse protocol with Id-correlated
responses, so the 0.18 hub keeps a persistent connection (no reconnect flapping)
and requests SMART on a SmartInterval we set. See
architecture.md.
Still depends on a small third-party fork and on Beszel's internal (non-public)
protocol; see
architecture.md.