
一个站点最容易出的事故,不是服务器崩了,是崩了三天你才发现。监控的价值不在采集数据,在于「坏了以后多久你知道」这个时间差。
这篇写一套能自己跑起来的方案:一台 2 核 2G 的小机器,Docker 部署 Uptime Kuma,监控五个站点,出问题通过邮件通知。全部配置给出完整值,版本号写死,照着抄能跑。
1. 先想清楚监控哪五个点
监控项不是越多越好。一个站点挂掉,通常只会在一个地方先露出来,抓错了地方,报警就成了噪音。五个点覆盖五条不同的失败路径,比五十个点盯同一个首页有用。
下面这五类是我用了两年之后留下的组合,任何一类都可以换成你自己的,但不要全都设成 HTTP 200 检查。五条路径互不重叠,才叫覆盖;五条盯同一个首页,只是重复。
- 首页可访问:最基础的一条,只能证明进程活着。
- 带关键字的页面:抓一个必然出现的标题词,能发现「200 但内容是错误页」。
- 后台登录页:确认数据库连接正常,很多故障在这里才现形。
- 证书到期天数:提前 14 天报,别等浏览器弹红。
- 外部 API 探针:返回 JSON 的接口,用 JSON 查询判断具体字段。
2. 目录结构与版本
全部文件放在 /opt/uptime-kuma,一个目录装完,备份就是打一个包。不要把数据卷放到 /tmp 下,容器重启后配置会一起消失。
/opt/uptime-kuma
├── docker-compose.yml
├── Caddyfile
└── data/
├── kuma.db
├── upload/
└── screenshots/
镜像版本固定为 1.23.16。写 latest 的代价是某天自动重启之后界面全变,监控项和通知配置的字段位置也一起变。监控系统本身不应该成为不确定性的来源。
services:
uptime-kuma:
image: louislam/uptime-kuma:1.23.16
container_name: uptime-kuma
restart: unless-stopped
ports:
- "127.0.0.1:3001:3001"
volumes:
- ./data:/app/data
environment:
- UPTIME_KUMA_DISABLE_STATS=true
端口绑在 127.0.0.1 上,外面进不来,只能通过反向代理。监控面板暴露在公网 3001 端口,等于把「哪个站什么时候挂过」公开给了所有人。
启动命令是 docker compose up -d。第一次起来会初始化数据库,大约 20 秒,日志里出现 Listening on 3001 之后才能访问。如果 20 秒后日志还在报错,先看卷的权限,不要急着重装。
3. 反向代理与证书
用 Caddy 两行解决 HTTPS,它会自动申请证书并处理续期。Uptime Kuma 的实时状态靠 WebSocket 推送,Caddy 默认会透传 Upgrade 头,不需要额外写配置。
monitor.example.com {
reverse_proxy 127.0.0.1:3001
encode gzip
}
如果前面还有一层 CDN,记得把 WebSocket 也放行,否则页面上的心跳一直转圈,看不到实时状态。这种情况监控数据其实在正常采集,只是你盯着一块不动的屏幕。
4. 五个监控项的完整参数
间隔、重试、超时三个值要一起调。间隔 60 秒、重试 2 次、超时 20 秒,意味着一次真实故障最多 100 秒后触发通知。间隔压到 20 秒不会让你更快知道,只会让误报翻三倍。
| 监控项 | 类型 | 间隔 | 重试 | 判定条件 |
|---|---|---|---|---|
| 首页 | HTTP(s) | 60 秒 | 2 | 状态码 200 |
| 文章页 | HTTP(s) 关键字 | 120 秒 | 2 | 含站点标题词 |
| 后台登录页 | HTTP(s) 关键字 | 300 秒 | 1 | 含「登录」且状态 200 |
| 证书到期 | HTTP(s) 证书 | 12 小时 | 1 | 剩余少于 14 天报红 |
| 统计接口 | HTTP(s) JSON 查询 | 300 秒 | 2 | 字段 status 等于 ok |
证书那一项要单独说。默认的「证书过期」检查在自签证书的站上会立刻报红,如果你监控的是内网设备,先把这一项关掉,否则第一天就满屏红色。
JSON 查询的写法是 status 这样的字段路径,嵌套用点号。它比关键字匹配可靠,因为返回结构不会因为改文案而变。能查结构就别查文本,文本是给人看的,结构是给程序看的。
5. 通知:一条通道就够
先用邮件打通,SMTP 在「设置 → 通知」里填六项:服务器、端口 465、安全方式 SSL、发件账号、授权码、收件地址。填完一定要点测试,测试通过不等于真报警能到,还要手动停一个服务验一次。
多个监控项共用一条通知,在每一项的「通知」里勾选同一个对象即可。默认开启「重要事件才通知」之后,恢复消息也会发一封,这两封要成对出现,否则你会在半夜醒来却不知道事情已经好了。
如果邮件经常进垃圾箱,加一条 Webhook 到手机上的推送工具,两条通道并行,任何一条到达都算成功。通知这件事不怕重复,怕的是只有一条通道,而那一条正好在维护。
6. 四个必然踩到的坑
坑一:数据目录的属主不对。手工 mkdir data 建出来的是 root:root,容器内的进程写不进去,启动日志里报 SQLITE_CANTOPEN。正确做法是先启动一次让容器自己建目录,或者执行 chown -R 1000:1000 data。
坑二:只备份配置,不备份数据库。「导出监控列表」导出的 JSON 不含历史心跳,恢复之后所有可用率都是空的。真正的备份是打包整个 data 目录。
cd /opt/uptime-kuma
docker compose stop
tar czf /backup/kuma-latest.tar.gz data
docker compose start
停服务再打包是为了避免 SQLite 写入过程中的不一致。几秒钟的监控中断,换一份能直接恢复的备份,这个交换划算。
坑三:只检查 200。首页由静态缓存返回 200,而后端数据库已经挂了,这种状态可以持续几个小时。加一条关键字检查就能发现。
坑四:监控系统自己挂了没人知道。Uptime Kuma 跑在同一台机器上,机器宕机时它也是哑的。解法是在另一台设备上放一个极简的外部探针,或者用第三方的免费心跳服务,每天给你发一条「我还活着」。监控的盲区永远在监控自己身上。
7. 验收:三步,缺一不可
第一步,五个监控项全部变绿,且「上次检查」的时间在滚动。只要有一项的时间停住,说明调度线程卡了,重启容器。
第二步,做一次假故障。把 nginx 停掉 90 秒,看是否收到告警邮件;再启动,看是否收到恢复邮件。这一步不做,等于没装监控。演练过的告警才叫告警,没演练过的只是一份配置。
第三步,重启整台机器,确认容器自动拉起、历史数据还在、状态页没有断档。能扛过一次重启的监控,才算装完了。
写在最后
装监控这件事,本质上是在为「你不在场的时候」做准备。它不会让故障变少,只会让故障变得可见。可见本身就是一种成本,因为你从此不能再假装不知道。
很多人装完监控的第一周就把通知关掉了,因为太吵。这不是监控的问题,是阈值没调。真正有用的告警应该少到每次响都值得看一眼。一天响二十次的系统,等于没有系统。
一套只响过三次、三次都是真事的监控,比一套每天响二十次的系统可靠得多。告警的可信度是用沉默换来的。
你现在靠什么发现站点挂了?上一次是别人告诉你,还是系统告诉你?

评论 (0)