Uptime Kuma 电话告警:让手机在宕机时真正响起来

Uptime Kuma 内置 90 多种通知方式,却没有一种能让手机响铃。本文介绍如何用一个 Webhook 为宕机告警加上电话通知。

目录

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 TypeWebhook
Friendly NameEchobell — Down
Post URL你的 Echobell Webhook 地址
Request BodyCustom 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——设为 23。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 获取,先拿一个不重要的监控项接上,然后故意让它失败一次。在真正依赖它之前,先验证这条链路。


相关内容

相关文章