monitor

配置

通知

hub 把节点掉线、流量将尽、即将到期和面板登录推送给你。渠道有两个:Telegram 机器人,以及请求体可以自定义的 Webhook。两个都配上时两边都发。

通知哪些事

事件什么时候发在哪开关
🔴 离线节点断开超过宽限期(默认 3 分钟)每个节点单独开,默认关
🟢 恢复在线发过离线通知的节点重新连上跟着离线走
⚠️ 流量提醒本期用量达到阈值(默认 80%)和 100% 时各一次节点填了每月额度就生效
⏳ 即将到期每天 9 点汇总一条,列出 7 天内到期的节点节点填了到期日就生效
🔁 已自动续期在线节点过了到期日,hub 把日期往后顺延时同上
🔑 面板登录应急密码或 GitHub 登录成功全局开关,默认开

几条规则:

  • 宽限期内断开又连上的,什么都不发。恢复通知只跟在离线通知后面,网络抖动不会刷屏。
  • 反复掉线的节点自动降噪。节点在最近 1 小时内有过一次超过宽限期的掉线,下一次掉线要持续 30 分钟才报;稳定在线满 1 小时后恢复正常宽限期。真掉线仍然会报,最多晚 30 分钟。一台「在线 1 分钟、掉线 4 分钟」来回反复的机器,模拟中一小时的通知从 23 条降到 2 条。几十秒的断开(比如重启 agent)不算。
  • 同时发生的事合并成一条。hub 每 30 秒检查一次,同一轮里新离线的、恢复的、流量超标的节点各合成一条。hub 自己断网时,40 台节点在模拟中是 2 条「N 台节点离线」,不是 40 条。
  • 重启 hub 不会重发。已报过离线的节点记在数据库里,hub 重启后不再重报,节点回来时照样发恢复。hub 停机期间掉线的节点,hub 起来后过了宽限期也会补报。
  • 流量按节点的计算方式和重置日算,和面板显示的是同一个数。进入新周期后重新计。
  • 只报登录成功,不报失败。失败的尝试谁都能发起,报失败等于让别人往你的 Telegram 里刷屏;失败由登录限流处理,见登录与安全。
  • 一条消息最多列 20 台节点,其余写成「……另外 N 台」。Discord 单条消息上限 2000 字符、企业微信 2048 字节,超出会被整条拒收。
  • 每条通知最多送一次。渠道暂时不通时会重试,重试完仍失败就丢弃,渠道恢复后不补发。
  • 不做 CPU、内存、磁盘这类负载告警,原因见设计哲学。

hub 自己停机或断网时,发不出任何通知。要监控 hub 本身,用外部拨测服务(UptimeRobot、Uptime Kuma 之类)定时访问 hub 的地址。

「每天 9 点」和消息里的时间都按 hub 所在机器的时区算。Docker 部署要设 TZ,否则是 UTC 的 9 点,见 Docker 部署。

配置

在面板的通知页填好渠道并保存,再点发送测试(测试用的是已保存的配置),每个渠道失败的原因会显示在面板上。企业微信、钉钉、飞书例外,见下文常见服务的写法。

然后在同一页的离线通知卡片里勾选要关注的节点,可以全选,也可以先按分组筛选再全选,点保存后生效;编辑节点里也有这个开关。流量和到期提醒不用单独开。

事件卡片里的三个数字:

设置默认范围
离线宽限期3 分钟1–30
流量提醒80%0–100,填 0 关闭
到期提醒7 天0–365,填 0 同时关闭到期和续期通知

宽限期从 hub 发现连接断开时算起,hub 每 30 秒检查一次,所以宽限期 3 分钟时,通知在断开后 3 到 3.5 分钟之间到达,和 agent 的上报间隔无关。agent 进程退出、机器正常重启时连接立即关闭;机器断电、断网时连接不会正常关闭,hub 最长 150 秒后才发现,通知相应推迟。

Telegram

  1. 找 @BotFather 发 /newbot,按提示起名,得到形如 123456:ABC-DEF… 的 token。
  2. 拿 Chat ID:
    • 发给自己:先给你的机器人随便发一句话,再打开 https://api.telegram.org/bot<token>/getUpdates,找 "chat":{"id":…} 里的数字。
    • 发到群组:把机器人拉进群,在群里发一句话,同样看 getUpdates。群组的 ID 是负数,通常以 -100 开头。
    • 发到公开频道:把机器人设为频道管理员,Chat ID 填 @频道名。
  3. 两项填进面板,保存,发送测试。

消息是纯文本,默认第一行是标题,下面是正文:

🔴 香港 · 甲商家 离线
最后上报 09-15 20:13 +08:00

改格式用消息模板,占位符见下文自定义内容。

hub 要能访问 api.telegram.org。访问不了时给 hub 设 HTTPS_PROXY 环境变量,hub 的所有出站请求(包括转发 agent 二进制、GitHub 登录、查询国家)都会走这个代理。一键脚本部署:

# 打开编辑器,写入下面两行后保存
systemctl edit monitor-hub
bash
[Service]
Environment=HTTPS_PROXY=http://127.0.0.1:7890
ini
systemctl restart monitor-hub
bash

Docker 部署在 docker run 里加 -e HTTPS_PROXY=http://…。

自定义内容

Telegram 的消息模板和 Webhook 的请求体各一个,所有事件共用。每类事件的标题和正文由 hub 生成,模板只决定怎么排列、加什么前后缀。输入框下方会用一条离线通知实时预览。

占位符内容
{{title}}标题,如 🔴 香港 · 甲商家 离线、⚠️ 香港 · 甲商家 流量提醒
{{message}}正文,如 最后上报 09-15 20:13 +08:00;多台节点时一行一台
{{node}}涉及的节点名,多台用 , 隔开;登录和测试为空
{{event}}offline online traffic expiry renew login test 之一
{{site}}设置页里的站点名称,默认 Monitor
{{time}}通知产生的时间,如 09-15 20:16 +08:00;离线通知比断开晚一个宽限期

不认识的 {{…}} 原样保留。模板清空后保存,恢复默认。

有多个 hub 时,把站点名称设成能区分的名字,模板里加上 {{site}}:

[{{site}}] {{title}}
{{message}}

钉钉、飞书要求消息包含关键词时,把关键词固定写在模板开头,每条消息才都带着它,见下文常见服务的写法。

Webhook

hub 以 POST 发送,Content-Type: application/json,请求体按模板生成。请求头里写了 Content-Type 时替换默认值。

URL 要填最终地址。hub 不跟随跳转:http:// 被跳到 https://、或少了末尾的 / 时,发送测试直接报 301 Moved Permanently,把 URL 改成它跳转的目标即可。跟随跳转的话,POST 会变成不带内容的 GET,对方照样回 200,面板显示发送成功而消息没有送到;请求头里的凭证也会被带到跳转后的主机。

请求体里的占位符会按 JSON 字符串转义(引号、反斜杠、换行),所以必须写在引号里。写错时预览会提示;保存时 hub 也会代入一组带引号和换行的样本,结果不是合法 JSON 就拒绝保存。

默认请求体:

{
  "event": "{{event}}",
  "node": "{{node}}",
  "title": "{{title}}",
  "message": "{{message}}"
}
json

请求头可选,一行一个,写成 Name: value,用于鉴权。

常见服务的写法

Discord:URL 填频道的 Webhook 地址。

{"content":"{{title}}\n{{message}}"}
json

Slack:URL 填 Incoming Webhook 地址。

{"text":"{{title}}\n{{message}}"}
json

企业微信群机器人:URL 填 https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=…。

{"msgtype":"text","text":{"content":"{{title}}\n{{message}}"}}
json

钉钉群机器人:URL 填 https://oapi.dingtalk.com/robot/send?access_token=…。安全设置选自定义关键词,只填一个固定的词(比如 探针),再把它写在模板开头。不要选只出现在部分消息里的词:「通知」只在测试消息里有,「节点」只在多台汇总里有,测试能收到,单台节点的离线、恢复却会被拒收。加签需要按时间戳实时计算签名,这里不支持。

{"msgtype":"text","text":{"content":"【探针】{{title}}\n{{message}}"}}
json

飞书群机器人:同样不能开签名校验,安全设置用自定义关键词,做法和钉钉相同。

{"msg_type":"text","content":{"text":"【探针】{{title}}\n{{message}}"}}
json

企业微信、钉钉、飞书拒收消息时(key 或 token 填错、关键词不匹配)仍返回 HTTP 200,错误码写在响应内容里,hub 分辨不出,发送测试照样显示已发送。配这三家时,以群里真正收到测试消息为准。

Bark:URL 填 https://api.day.app/push。

{"device_key":"你的 key","title":"{{title}}","body":"{{message}}"}
json

ntfy:URL 填 https://ntfy.sh(或自建地址),需要鉴权时请求头加 Authorization: Bearer …。

{"topic":"你的 topic","title":"{{title}}","message":"{{message}}"}
json

Gotify:URL 填 https://gotify.example.com/message,请求头加 X-Gotify-Key: 应用 token。

{"title":"{{title}}","message":"{{message}}"}
json

凭证不回读

Bot Token、Webhook URL、Webhook 请求头这三项保存后读不回来,面板只显示「已设置」。输入框留空保存表示不改;停用一个渠道点那张卡片上的清除,只删请求头点清除请求头。

Webhook URL 也算凭证:Discord、Slack、企业微信、钉钉、Bark 的地址本身就是密钥,拿到就能往你的频道里发消息。数据库备份里包含这些凭证,见数据与备份。

收不到通知

先点发送测试,各渠道失败的原因会直接显示在面板上(企业微信、钉钉、飞书除外,看群里有没有收到)。常见的:

面板上的提示原因
Telegram:Bot Token 不对(HTTP 401)token 填错,或者机器人被删了
Telegram:Chat ID 不对,或者 bot 还没有加入这个会话(HTTP 400)Chat ID 不对,或者你还没给机器人发过消息、机器人不在群里
Telegram:bot 被这个会话移除或屏蔽了(HTTP 403)你屏蔽了机器人,或者机器人被移出了群
Webhook:地址发生了跳转,请填写跳转后的地址(HTTP 301)URL 会跳转,改成它跳去的地址,见上面 Webhook 一节
Webhook:对方拒收了这条消息,检查请求体格式(HTTP 400)服务端拒收,多半是请求体不合它的格式
连不上对方服务器、请求超时hub 连不上那个地址

对方服务自己返回的错误信息写在 hub 日志里:

# 一键脚本
journalctl -u monitor-hub | grep 'not delivered'
# Docker
docker logs monitor 2>&1 | grep 'not delivered'
bash

测试能收到、真实事件收不到:

  • 离线通知要在离线通知卡片里打开对应节点,默认是关的。
  • 离线通知来得晚:节点最近 1 小时内有过一次超过宽限期的掉线,这次要掉满 30 分钟才报,见上文「反复掉线的节点自动降噪」。
  • 流量提醒要节点填了每月额度,到期提醒要节点填了到期时间。
  • 钉钉、飞书只收到一部分:关键词没有出现在每条消息里,见上文钉钉群机器人。
  • 看 hub 日志。连不上、对方 5xx 或限流(429)时隔 10 秒重试,最多 3 次;token 错误、地址跳转这类重试也没用的错误不重试。最终没送出去的每条记一行:
# 一键脚本
journalctl -u monitor-hub | grep 'not delivered'
# Docker
docker logs monitor 2>&1 | grep 'not delivered'
bash
在 GitHub 上修改这一页最后更新 2026-09-29