目录
Uptime Kuma 支持 90 多种通知方式,但没有任何一种能让你的手机响铃。想在监控项宕机时接到电话,只需把 Uptime Kuma 的 Webhook 通知发送到一个通知类型设为来电铃声的 Echobell 频道。本文会给出确切的自定义请求体、如何把宕机告警和恢复告警分开,以及两个会悄悄让整套配置失效的坑。
Uptime Kuma 是目前最流行的自托管可用性监控工具——GitHub 上约 9 万星标,2.5.0 版本于 2026 年 8 月发布。它可以检查 HTTP 端点、TCP 端口、DNS 记录、Docker 容器等,探测宕机的能力确实出色。
它留下的缺口在最后一公里:把告警送达一个正在熟睡的人。
为什么 Uptime Kuma 自己打不了电话
Uptime Kuma 的通知列表很长——Telegram、Discord、Slack、邮件、Gotify、ntfy 等等——但它们送达的都是消息。消息会受手机静音开关、勿扰模式和 iOS 专注模式的约束。凌晨 3 点,这意味着告警到了,但什么都没发生。
它没有官方的「打电话给我」通知方式。人们通常会考虑这几条路:
- Twilio——你可以基于它实现语音呼叫,但 Uptime Kuma 的 Twilio 通道走的是短信接口。要打电话就得自己写一个中转服务、购买号码,并按次付费。
- PagerDuty、Zenduty、Spike.sh、Splunk On-Call——它们确实能打电话,同时也是完整的事件管理平台,价格按人头计算。如果你需要排班和升级策略,它们是对的选择;如果你只是想让手机响,就太重了。
- 短信网关——短信仍然是一条消息,而在 iOS 上,除非发件人在你的白名单里,否则短信不会突破专注模式。
Uptime Kuma 仓库里关于 VoIP 电话通知的需求已经开了很久。在此之前,通用的 Webhook 通道就是那个突破口——它能向任意 URL 发送任意内容,而这已经足够了。
你需要准备什么
- 一个运行中的 Uptime Kuma 实例(本文基于 2.x 编写;自定义请求体在 1.23+ 上同样适用)
- 安装好 Echobell(App Store / Google Play)
- 五分钟
你的 Uptime Kuma 实例需要能够向外访问 hook.echobell.one。它不需要能从公网访问——这是一个出站 Webhook,所以跑在家庭服务器或内网里的监控完全没问题。
第一步 —— 创建一个会打电话的频道
在 Echobell 中创建一个频道,命名为 生产环境宕机 之类。把订阅的通知类型设为来电铃声。这个设置才是关键:来电铃声类型的告警会以来电界面出现,能穿透 iOS 专注模式和勿扰模式,而普通推送做不到。
模板设置为:
标题:🔴 {{monitor}} 已宕机
内容:{{message}}
目标:{{target}}
然后复制该频道的 Webhook 地址,形如:
https://hook.echobell.one/t/<channel-token>
请把这个地址当作密钥对待——任何拿到它的人都能让你的手机响起来。
第二步 —— 把 Echobell 添加为 Webhook 通知
在 Uptime Kuma 中进入 Settings → Notifications → Setup Notification,填写:
| 字段 | 值 |
|---|---|
| Notification Type | Webhook |
| Friendly Name | Echobell — Down |
| Post URL | 你的 Echobell Webhook 地址 |
| Request Body | Custom Body |
Additional Headers 留空。
第三步 —— 发送一个可供过滤的载荷
这一步是多数教程会跳过的,也正是「告警系统」和「噪音制造机」之间的分水岭。
把下面的内容粘贴到 Custom Body 中:
{
"monitor": "{{name}}",
"target": "{{hostnameOrURL}}",
"message": "{{ msg | strip_newlines }}",
"up": "{{ heartbeatJSON['status'] }}"
}
Uptime Kuma 使用 Liquid 渲染自定义请求体,可用变量如下:
| 变量 | 含义 |
|---|---|
{{name}} | 监控项的友好名称 |
{{hostnameOrURL}} | 被检查的主机名或 URL |
{{status}} | 🔴 Down、✅ Up 或 ⚠️ Test |
{{msg}} | 可读的原因,例如 connect ECONNREFUSED 10.0.0.4:443 |
{{ monitorJSON['...'] }} | 完整的监控项对象 |
{{ heartbeatJSON['...'] }} | 完整的心跳对象 |
上面这个载荷里有两处是刻意为之的:
给 msg 加上 strip_newlines。 Uptime Kuma 的消息里经常带换行,而 JSON 字符串中出现裸换行就是非法 JSON。不加这个过滤器,你的 Webhook 会时不时失败——而且只在错误文本恰好换行时失败。如果你的 Uptime Kuma 版本支持 Liquid 的 json 过滤器,"message": {{ msg | json }}(注意:外面不加引号)会更安全,因为它连引号也会转义。
用 heartbeatJSON['status'] 而不是 {{status}}。 status 变量渲染出来是带表情符号的文本,很难用来做比较。心跳状态则是一个普通数字:
0—— 宕机1—— 正常2—— 待定3—— 维护中
给它加引号("up": "{{ ... }}")也很重要,原因见第五步。
第四步 —— 别让恢复通知也打电话给你
Uptime Kuma 的一条通知会在宕机和恢复时都触发。如果放着不管,这套配置会在服务挂掉时打给你,然后在它自己恢复时再打一次。正是第二个电话,让人学会了忽略第一个。
用 Echobell 的条件把它们分开,条件会在任何内容送达之前完成判断:
在 生产环境宕机 频道上(通知类型为来电铃声),把条件设为:
up == "0"
再创建一个频道,命名为 生产环境已恢复,通知类型设为普通,条件设为:
up == "1"
模板:
标题:✅ {{monitor}} 已恢复
内容:{{message}}
然后在 Uptime Kuma 里再加一条 Webhook 通知——自定义请求体相同、绑定的监控项相同,只是 URL 指向恢复频道。两条通知都会收到全部事件,各自的频道会丢弃自己不关心的那一半。
结果就是:宕机会响铃,恢复则是一条你第二天早上再看的安静推送。
第五步 —— 调整监控项,别做「狼来了」
如果一通电话最后发现只是两秒钟的网络抖动,那比不打还糟糕,因为下一通也会被无视。Uptime Kuma 监控项上的三个设置基本能解决这个问题:
- Retries——设为
2或3。Uptime Kuma 只有在连续失败这么多次之后才会把监控项标记为宕机,这样可以过滤掉单个丢包。 - Heartbeat Retry Interval——失败状态下的重查间隔。20–30 秒是个合理的平衡;配合 3 次重试,你大约在一分钟内就能发现真实故障。
- Resend Notification if Down X times consecutively——设成
10之类,如果再过十次检查服务仍未恢复,Uptime Kuma 会再次呼叫。这是一种粗糙的升级策略,但确实有效。
如果你希望未接来电立刻重试,而不是等到重发,可以在 Echobell 的应用设置里打开重试失败的通话。
只在工作时间之外响铃
工作时间里你多半已经盯着仪表盘了,一通响铃只是多余的打断。Echobell 的系统时间变量(全部为 UTC)可以让同一个频道按小时表现不同:
up == "0" && (hour >= 17 || hour < 9)
这个条件只在 UTC 09:00–17:00 之外呼叫你。再用一个「普通」类型的频道处理白天的推送,条件取反即可:
up == "0" && hour >= 9 && hour < 17
记得换算成你自己的时区——这些变量始终按 UTC 计算。更完整的说明见使用 UTC 条件实现时间窗口通知。
与团队共享告警
Echobell 频道可以通过订阅链接分享给同事,每位订阅者各自选择自己的通知类型。所以同一个监控项可以让值班工程师的手机响铃,同时对其他人只是一条普通推送——不按人头计费,也不需要在 Uptime Kuma 里配置额外的路由规则。
这也与自托管本身的隐私取向相契合:你的监控数据留在自己的基础设施上,而 Echobell 把通知内容和历史记录保存在设备本地,而非服务器上。
这套方案不能给你什么
把边界说清楚,能帮你避免日后一次糟糕的迁移。Echobell 是一个送达层,不是事件管理平台。它没有:
- 值班排班表或跟随日光的交接
- 自动呼叫第二个人的升级树
- 事件时间线、确认追踪或事后复盘工具
如果你的团队需要这些,那就需要 PagerDuty、Grafana Cloud IRM 或同类产品。这套方案填补的是 Uptime Kuma 留下的那个具体缺口:把探测到的故障变成一部真正响起来的手机。对于个人运维者、小团队和 homelab 来说,这通常就是全部需求。
排查
点 Test 按钮没有反应。 用上面这个载荷时这是预期行为,第一次都会被它搞糊涂。点击 Test 时,Uptime Kuma 没有可渲染的心跳,因此 {{ heartbeatJSON['status'] }} 会解析为空字符串,两个条件都不匹配。要真正测试,可以建一个临时的 TCP 监控项,指向一个没有服务监听的端口(127.0.0.1:9),让它自然失败。
Webhook 时好时坏。 几乎都是换行问题——检查 msg 是否经过了 strip_newlines。它只在错误消息恰好包含换行时才会失败,所以看上去很随机。
Echobell 返回 HTTP 200,但 success: false。 频道 token 有误,或频道已被删除。对于长度合法但不存在的 token,Echobell 仍会返回 200,所以要检查 JSON 响应体,而不是状态码。
HTTP 405。 频道开启了 POST Only,而请求方发的是 GET。Uptime Kuma 用的是 POST,所以这通常意味着你在浏览器里打开了这个地址。
通知到了,但手机不响。 该订阅的通知类型是「普通」或「时效性」,而不是「来电铃声」。通知类型是每个订阅者各自设置的,所以要在那台不响的设备上检查。
常见问题
Uptime Kuma 能原生打电话吗?
不能。Uptime Kuma 有 90 多种通知方式,但它们送达的都是消息。要打电话,需要把 Webhook 转给一个能拨号的服务(例如 Echobell),或者使用付费的事件管理平台。
防火墙后面的自托管 Uptime Kuma 能用吗?
可以。这个 Webhook 是从你的 Uptime Kuma 实例发出的出站 HTTPS 请求,只需要能访问 hook.echobell.one。你的实例不需要公网地址。
电话会绕过勿扰模式吗?
会。Echobell 的「来电铃声」通知类型以来电形式呈现,能够穿透 iOS 专注模式和勿扰模式。详情和相关设置见绕过 iOS 专注模式接收关键告警。
怎样避免服务恢复时也被呼叫?
用两个带条件的频道——来电频道用 up == "0",普通优先级的恢复频道用 up == "1"——然后各指向一条 Webhook 通知。上面第四步有完整步骤。
同一个监控项能呼叫多个人吗?
可以。把频道分享给同事,每位订阅者选择自己的通知类型。所有订阅了来电频道的人都会被呼叫。
小结
整套配置就是一个 Webhook、一段自定义请求体和两个条件。它完全不改动你现有的 Uptime Kuma 监控项、重试逻辑和状态页,却补上了「监控发现了」和「有人发现了」之间的那道缝。
在 iPhone 上下载 Echobell 或在 Google Play 获取,先拿一个不重要的监控项接上,然后故意让它失败一次。在真正依赖它之前,先验证这条链路。