服务器报警了不用我爬起来查,一个 Hermes 应用案例
注:系列前文用的是 OpenClaw,后来的告警诊断换成了 hermes-agent,两者不是同一个项目。这篇讲的是 Hermes 现在能做的事。
凌晨三点,手机震了一下。Telegram 弹出来一条告警:某台 VPS 的 SSH 端口探测失败。
以前碰到这种,我得爬起来开电脑、SSH 进去、查服务状态、看日志,判断是真挂了还是网络抖了一下。现在这条告警由 Hermes 接住:它自己 SSH 进那台机器查完,把结论发回 Telegram,我醒了直接看结论。
这篇记录这条链路是怎么搭的。重点在 Hermes 怎么替我把值班流程跑完,Kuma 和 Beszel 本身怎么配置就不展开了。
1. 告警来源
入口是两套监控系统。
Kuma 跑在香港 VPS 的 Docker 里,盯服务存活。当时配了 11 个 monitor,覆盖 HTTP、TCP 端口和 ping。某个目标从 UP 翻转到 DOWN 时,它发出一条 webhook。
Beszel 的 hub 在家里的 N1 上,几台 agent 上报 CPU、内存、磁盘、温度,超阈值时告警。
这两套都能把告警直发 Telegram,秒级到达。但纯通知只告诉我“出了事”,说不出“出了什么事”。SSH 端口探测失败,可能是 sshd 挂了,可能是网络抖了一下,可能是防火墙规则变了,也可能只是探针自己抽风。要分清,得进机器看。
进去看这一步交给 Hermes。中间有个障碍:验签。
2. 95 行的 signer
Hermes 的 webhook 入口绑在 *:8644。为了防止外部乱发请求伪造告警,它要求每个请求带一个动态签名:X-Hub-Signature-256: sha256=HMAC(密钥, 请求体)。这是 GitHub webhook 的标准做法,Hermes 用同一把密钥重新算一遍,对得上才处理。
Kuma 和 Beszel 都不会算这个 HMAC。Kuma 的 webhook 通知只能发固定的 header 和 body,Beszel 走 Shoutrrr 的通知格式,两边都没有“对 body 算 HMAC 再塞进 header”的能力。
所以中间加了一层签名转换服务。signer 跑在 Mac mini 上,和 Hermes 同机,监听 8646,95 行纯标准库 Python,launchd 常驻。它只做一件事:
收任何 POST 请求
→ 用预设密钥对请求体算 HMAC-SHA256
→ 拼成 sha256=xxx 塞进 X-Hub-Signature-256 头
→ 原样转发到 127.0.0.1:8644/webhooks/infra-alert
2026 年 8 月 30 日我在 Mac mini 上核对过一遍现场:Hermes 主网关监听 8644,signer 监听 8646,默认转发目标就是上面这个地址,签名算法和请求头格式与 Hermes 的验签逻辑一致。
8646 本身不验签,会给任何收到的请求签名,谁连上它,谁就能借它伪造一条“合法”告警,所以部署时不得向不可信网络开放。
signer 挂了也不影响 Kuma 和 Beszel 直发 Telegram 的那条路,告警不会丢。
3. infra-alert 路由和 SSH
验签通过后,请求落到 Hermes 的 webhook 路由。我配了一条叫 infra-alert 的路由,做三件事:
- 把告警的完整 payload 塞进 prompt 模板。模板里用
{__raw__}占位符把 JSON 原样转储进去,agent 能看到 monitor 名、状态、msg 这些原始字段。 - 附上设备别名映射表:告警里的设备名对应到哪个 SSH 的 Tailscale 别名,agent 据此决定去查哪台机器。
- 指定投递目标:分析结论发到 Telegram 的指定会话。
这个 prompt 作为一条消息进入 Hermes 的主循环,交给 LLM。模型读到告警后自己判断需要哪些信息:SSH 探测失败,就得看 sshd 现在的状态、最近的登录日志、端口是否真的在监听。没有写死的规则,告警是磁盘满它就去查 df,告警是负载高它就去查进程列表。
查靠的是 SSH 工具,Hermes 能真的登进设备跑命令。这一步依赖前面那篇为什么 ping 通了但 SSH 连不上搭好的链路:agent 用映射表里的别名 ssh vps-hk 连进去,跑诊断命令,输出回到它的上下文里,再继续分析。
4. 双路通知
整个告警体系是两条路并行:
即时通知:Kuma 和 Beszel 直发 Telegram,秒级,只说“出了事”。这条路不经过 Hermes,Hermes 挂了也照常工作。
分析诊断:经 signer 到 Hermes,慢,要一两分钟,但说清“出了什么事、要不要管”。
两条路各管一段。真正紧急的事即时通知先顶上,Hermes 负责让我醒了之后不用再花十分钟手动排查。
5. 一次 143 秒、7 次调用的记录
一次真实告警。Kuma 报 vps-hk 的 SSH 端口探测失败(connect ECONNREFUSED),经 signer 签名后进入 Hermes。
143 秒后,Telegram 收到这条结论:
Kuma 端口监控告警。
- 受影响设备/服务:vps-hk,SSH 端口 22022
- 诊断:sshd 当前正常运行,0.0.0.0:22022 和 IPv6 均在监听;告警时间附近有成功 SSH 登录记录,当前端口探测也显示 open。资源正常:load 0.29,内存可用约 1.1 GiB,磁盘使用 41%。
- 判断:没有持续宕机,更像一次短暂连接拒绝或 Kuma 探针抖动。
- 处理:暂时无需动作;若反复出现,再查 Kuma 探测端和 Tailscale 网络。
它做了几件事:真 SSH 进去验证了 sshd 在跑、端口在监听;查了告警时间附近的登录日志,用那段时间的正常登录反证“端口完全不通”;给了判断和处理建议,没有复读告警原文。
这 143 秒里 Hermes 发了 7 次 LLM 调用,走的是多轮循环:先判断要查什么,SSH 进去查,拿到结果再分析,必要时补查,最后组织结论。中间结果会改变后面的动作,比如看到负载正常就跳过进程排查,这是它和单次问答的区别。
6. 适用范围
成本是真实的。每条告警都要触发一次完整推理加多次 SSH 往返。上面那次 143 秒、7 次 API 调用只是这一次告警的记录,不代表每条告警的固定成本。个人基础设施告警频率低,这个开销可以接受;告警量大的话,这套会又慢又贵。
它适合“偶尔来一条、来了要认真看”的场景,不适合高频告警的流水线处理。半夜被吵醒、要爬起来排查这种事是重复劳动,正好交给 agent 去做,这是我愿意花力气搭这条链路的原因。