多 VPS 统一监控(一):技术路线总览

手里 VPS 一多,麻烦事就来了:哪台机器磁盘快满了?哪个应用半夜挂了?哪个域名的证书还有几天过期?以前我是哪台出问题才去看哪台,直到 2026 年 10 月 12 日那天,一台 VPS 磁盘被日志写满、直接把网站服务拖垮,我才决定:必须搞一套统一监控。

这是系列文章的第一篇,先讲技术路线——我为什么选了 Beszel + Uptime Kuma + Portainer 这三个工具,它们各自负责什么,整体架构长什么样。后面五篇分别是每个工具的部署实录,跟着做就能复刻。

先说需求:我要监控什么

当时我的家底是 4 台 VPS(博客主机、RackNerd 1G、Bandwagon、Dedirock),每台上面都跑着几个 Docker 应用,还有好几个域名。需求拆开其实就四句话:

  • 服务挂了要第一时间知道(网站打不开了、SSH 连不上了);
  • 磁盘/内存/CPU出问题前能预警(别再重演磁盘写满拖垮服务);
  • HTTPS 证书、域名快到期了要提醒(过期了网站直接变红);
  • 容器要能统一看、统一管(哪台机器跑了什么容器,一眼看清)。

再加一个硬性要求:告警必须能推到手机上。监控配得再全,告警只躺在网页仪表盘里没人看,等于没配。

为什么是这三个工具

市面上的方案我捋了一遍,最后定了下面这个组合,理由是:全部开源免费、全部 Docker 一键部署、对只有几台机器的个人用户足够轻。

  • Beszel(https://github.com/henrygd/beszel)——看机器内部:每台 VPS 的 CPU、内存、磁盘、流量曲线,外加这台机器上跑了哪些容器。Agent 装到每台机器上,数据汇总到一个 Hub 里看。
  • Uptime Kuma(https://github.com/louislam/uptime-kuma)——从外部盯服务活没活:网站 HTTP 是否 200、服务器 22 端口通不通、证书还有几天到期、域名还有几天到期。挂了就告警。
  • Portainer CE(https://www.portainer.io)——管容器:四台机器的容器、镜像、日志、重启更新,在一个页面里点点鼠标就能操作,不用每台都 SSH 上去敲命令。版本建议用最新版,我部署时服务端是 2.45.2(2.45.2 及以上都行),注意 Agent 镜像的 tag 必须和服务端版本号对上。

三者分工一句话:Beszel 看机器 inside,Uptime Kuma 从外面敲门,Portainer 负责动手管。Prometheus + Grafana 那套也强,但对个人小集群来说太重了,配起来劝退小白,所以没选。

总体架构

三个服务全部装在博客主机(跑博客的那台 VPS)上,用一个 docker-compose 一把拉起。网络上做了关键隔离:

  • 三个容器只监听 127.0.0.1,端口不直接暴露到公网;
  • 用博客主机上现成的 LDNMP Nginx 做反代,对外只开三个子域名,全部 HTTPS:
    • monitor.nettodata.com → Beszel(本机 8090)
    • status.nettodata.com → Uptime Kuma(本机 3001)
    • manage.nettodata.com → Portainer(本机 9000)
  • 四个 VPS 上各装一个 Beszel Agent(systemd 服务,监听 45876),只和 Hub 单线联系;
  • 告警统一走 Bark 推送到 iPhone 通知栏(安卓可用 Server酱推微信,原理一样)。

画成图就是这样:

┌─────────────┐   Agent(45876)   ┌──────────────────────────────┐
│ VPS 2/3/4   │◄─────────────────│ 博客主机 (VPS 1)               │
│ (被监控)     │   只收指标       │  ┌─────────┐ ┌──────────────┐ │
└─────────────┘                  │  │ Beszel  │ │ Uptime Kuma  │ │
                                 │  │  Hub    │ │ (对外探测)    │ │
┌─────────────┐   HTTP/TCP探测   │  └─────────┘ └──────────────┘ │
│ 你的网站/服务 │◄────────────────│  ┌──────────┐                │
└─────────────┘                  │  │Portainer │                │
                                 │  └──────────┘                │
                                 │  ▲ Nginx 反代 (443 HTTPS)    │
                                 └──┼────────┬────────┬─────────┘
                                    │        │        │
                              monitor. status.  manage.
                              (Beszel) (Kuma) (Portainer)
                                    └────────┴────────┘
                                           │
                                    Bark 推送 → 手机

告警阈值是怎么定的

阈值太敏感会狼来了,太迟钝等于没有。我定的规则如下(括号里是理由):

  • 磁盘:使用率 > 80% 预警、> 90% 严重、> 95% 紧急(10 月 12 日那次就是磁盘 100% 引发的连锁故障,这项最敏感);
  • CPU / 内存:持续 10 分钟 > 90% 才告警(瞬时 spike 不告,避免误报);
  • 服务 Down:连续 2 次探测失败才告警(防网络抖动);
  • 证书:到期前 30 天 / 14 天 / 7 天三级提醒;
  • 域名:到期前 60 天 / 30 天 / 14 天 / 7 天提醒;
  • Agent 失联:超过 5 分钟按宕机处理。

两个安全设计

监控面板本身也是攻击面,部署时顺手做了两件事:

  • 面板不直接暴露端口:全部走 Nginx 反代 + HTTPS + 登录密码,容器端口只绑 127.0.0.1;
  • Agent 独立 Key:每台机器的 Beszel Agent 用独立密钥,Hub 的数据要备份——Hub 丢了,所有 Agent 得重新注册一遍。

还有一个单点风险要如实说明:监控和被监控跑在同一台 VPS 上。如果博客主机整台挂了,监控自己也发不出告警。所以还需要一个独立的免费外部哨兵,每隔几分钟 ping 一下监控域名、ping 不通就告警——这部分还没部署,列在待办里,后续单独写一篇。

下一篇

下一篇《多 VPS 统一监控(二):Beszel(一)Hub 部署》讲 Hub 的 Docker 部署、Nginx 反代 + HTTPS 的全过程。

发表评论