🧭 局域网监控全家桶搭建笔记:NetAlertX + Uptime Kuma + Beszel + Grafana + ntfy

💡 设备一多,「谁挂了」就变成了玄学:NAS 上某个容器停了、软路由 DHCP 抽风、ESXi 里一台虚机失联——每次都是等发现不了网的时候才知道出事。这篇文章记录我把整个局域网的「设备、服务、指标、告警」四层监控补齐的过程。

0. 为什么要做监控

家里现在跑着的东西:25 台 LAN 设备(iStoreOS、fnOS NAS、Debian 宿主、ESXi、米家网关、各种盒子),56 条服务端口映射,7 台需要看系统指标的主机。

之前的痛点很典型:

  • 设备无账本:新设备接入没人知道,IP 被占了才想起来查
  • 服务黑盒:42 个 Web 服务全靠「打不开才发现」
  • 指标缺失:CPU/磁盘/带宽没有历史曲线,排查全凭感觉
  • 告警分散:有的发邮件、有的没告警,出事了都不知道

目标:设备有台账、服务有探测、主机有指标、告警走一个入口。

1. 总体架构

先看全貌:

局域网监控体系架构

分工原则是一个工具只干一件事:

组件 职责 部署位置
NetAlertX 设备发现与台账(双网段) .55 · :20211
Uptime Kuma 服务可用性探测(42 项) .51 · :3001
Beszel 主机系统指标(7 台) .55 · :3017
8789 控制台 端口探测 + 设备 JSON 出口 .51 · :8789
Grafana 12 设备清单/类型分布展示面板 .55 · :3023
ntfy 统一告警推送 .51

2. 探测层四件套

NetAlertX:设备台账

双网段扫描(31.x + 0.x)都能发现,新设备接入、设备离线都会推 ntfy。后来把 25 台设备全部补了可读名称(.50 iStoreOS、.51 fnOS、.55 Debian、.99 ESXi……),并把确认过的设备标记为非新设备——这步是靠它的 API 批量写入的,Token 从运行时环境注入,不落盘。

Uptime Kuma:服务探测

42 个监控项覆盖所有 Web 服务和关键端口。它还有一个彩蛋链路:Kuma → Home Assistant → 台灯,服务挂了台灯闪红,躺在沙发上也能知道出事了(后面告警链详说)。

Beszel:主机指标

7 台物理/虚拟主机接入,CPU、内存、磁盘、磁盘 I/O、上下行吞吐都有,通知同样接 ntfy。选它而不是 Node Exporter 全家桶的原因很简单:单容器部署,agent 够轻。

8789:自研总览控制台

这是整个体系里最关键的一块拼图——自己写的总览控制台,27 项探测全部正常,除了页面展示,它还提供带 CORS 的设备 JSON:http://192.168.31.51:8789/net/devices。这个接口后来成了 Grafana 面板和 3D 拓扑的数据源。

3. Grafana Infinity 设备面板

Grafana 用原生 systemd 部署(12.2.1,开机自启),通过 Infinity 插件直接读 8789 的 JSON,用 JSONata 做解析:

1
root_selector = $.devices

面板做了四块:统计卡(总设备 25 / 待确认 0 / 智能家居 14 / 服务器 4)、可排序设备清单、设备类型分布柱状图、四个监控入口的可点击直达。

Grafana 设备面板整页

设备清单表格

设备类型分布

Infinity 插件的坑

这个坑值得单独记:查询对象的数组字段写成 null 会直接报错。

Infinity 3.11.1 的前端会对 url_options.headers、params、body_form 做 .map(),写成 null 就是 Cannot read properties of null (reading 'map')。正确做法是省略这些字段,或写成空数组,不要写 null。

另外两个小处理:表格查询把空类型/空厂商补成「未分类/未知」;无法识别名称的新设备显示为「未知设备 · IP」,不再出现空白或 (name not found)。

4. 告警链:ntfy → Home Assistant → 台灯

所有告警走 ntfy 一个入口:

  • NetAlertX:新设备接入、设备离线
  • Uptime Kuma:服务探测失败
  • Beszel:主机指标越阈

再加一条物理链路:Kuma → Home Assistant → 台灯故障灯。深夜服务挂掉,手机推送可能被静音,但台灯闪红光不会。

5. 全平台汉化

监控面板是全家要看的,英文界面家庭接受度低,顺手全汉化了:

组件 方式
Grafana custom.ini 加 [users] default_language = zh-Hans
NetAlertX UI 语言 zh_cn + 设备名/类型改中文
Uptime Kuma 浏览器 zh-CN 自动生效,无需改服务端
Beszel 浏览器 zh-CN 自动生效,无需改服务端
8789 原生中文页面

NetAlertX 中文界面

Uptime Kuma 中文登录页

Beszel 中文登录页

8789 中文控制台

已知残留:Grafana 上游中文包有个别内置字符串(如 Last 15 minutes)未翻译,不影响业务内容。

6. 踩坑记录

  1. Infinity null.map 报错:数组字段写 null 必挂,省略或 [](见上文)
  2. Grafana 别用 Docker 和 systemd 混跑:早期 compose 部署升级麻烦,换成原生 grafana.service 后,旧 compose 文件改名停用、同名容器删除,避免再次抢占 3023 端口
  3. Dashboard 改前必备份:JSON 存本地 + 服务器双份(grafana-dashboard-before-2026-11-01.json),出问题秒回滚
  4. 批量改设备名前先备数据库:NetAlertX 的 app.db 改名前做了 .bak 备份,Token 不落盘

7. 验收标准

  • 6 个动态面板查询全部返回 200,统计卡无空数据
  • 设备表返回 25 行,类型汇总 5 类
  • 页面渲染无错误,浏览器控制台无 Infinity 异常
  • 27/27 端口探测正常,4 个监控入口可直达

本文首发于 ShallowRecall,转载请注明出处。