告警邮件在垃圾箱睡了一整晚?ntfy自建统一推送中心实战,把哪吒、Uptime Kuma、备份任务的通知全收进一个APP


导读:本站监控体系三层早就齐了:哪吒盯机器活着、Uptime Kuma盯服务应答、Healthchecks盯任务真的在跑——但所有告警的最后一公里,其实都堵在同一个地方:邮件。邮件慢、邮件会进垃圾箱(发信篇的痛大家都懂)、Telegram要全程代理、微信推送要注册企业微信或者用Server酱吃免费额度,各家监控各自为政,通知散落在三四个渠道里。这篇把通知层正面讲透:ntfy的发布订阅原理、二进制和Docker两种部署姿势、手机APP的订阅差异、一条curl接入全部监控三件套、账号与限速的安全加固、防轰炸的优先级策略,以及最后那层哲学问题——ntfy自己挂了,谁来喊你。

一、最后一公里:告警渠道的散装困境

先盘点一下一个典型自托管玩家的通知现状,看看有多少种"散装":哪吒的告警走邮件或Telegram,Uptime Kuma单独配了企业微信应用,Healthchecks的死人开关通知(cron篇接的那批心跳任务)依赖发信篇搭的Postfix,备份脚本成功与否看心情翻日志,证书快到期了靠证书商的提醒邮件——五套体系,五个渠道,手机上三个APP加一个邮箱,哪个响了都要先想想"这是谁在喊我"。更糟的是可靠性:邮件从Postfix发出去,路过Gmail的垃圾箱判定全凭缘分,发信篇里SPF、DKIM、DMARC一条龙配完也只能保证"大概率不进垃圾箱";Telegram的推送在国内网络环境下能不能收到取决于代理的稳定性——你的告警体系居然依赖你的代理不挂,这是个冷笑话。真正的问题是:告警是低频高价值的信息,一次没收到,前面整套监控体系的投入就归零。所以通知层值得单独建设,而且要自托管——监控全家桶都在自己机器上,通知中心凭什么还在别人手里。

二、ntfy是什么:基于主题的极简发布订阅

ntfy(读作notify)的模型简单到一句话讲完:服务器上有一堆"主题"(topic),谁都可以往主题里POST一条消息,订阅了这个主题的设备就会收到推送——没有账号体系、没有应用注册、没有API Key,一个URL就是全部接口。发布消息就是一条curl:

curl -d "备份任务完成,共写入1.2G" https://ntfy.example.com/vps-backup

对,就这么一行,服务器、主题名、消息体,齐了。订阅端:手机APP里填上你的服务器地址和主题名,消息即推即到。这种极简设计对小鸡玩家是降维打击:通知不再需要"接入某个平台",只需要"知道一个URL"——任何能发HTTP请求的东西都能发通知,cron脚本、Docker容器、监控面板、甚至路由器上的定时任务。当然,"谁都能发"是双刃剑,安全问题后面单独讲,先把架构跑通。消息支持标题、优先级、标签(会渲染成表情)、点击跳转链接,富文本一应俱全,服务端默认保留12小时消息(可配置),APP晚上线也能拉到错过的历史通知。

三、部署:二进制直装或Docker,五分钟的事

ntfy用Go写的,单个二进制零依赖,两种姿势任选。二进制直装(apt仓库或GitHub Releases下载),配好之后:

systemctl enable --now ntfy

配置文件在/etc/ntfy/server.yml,个人玩家最少要动三行:base-url填最终对外域名(反代篇的域名规划直接复用),cache-file指定SQLite缓存文件路径(消息留存的载体),auth-file开启用户认证后指定账号库位置。Docker姿势(Compose篇的栈再添一员):

services:
  ntfy:
    image: binwiederhier/ntfy
    command: serve
    ports:
      - "80:80"
    volumes:
      - ./ntfy/cache:/var/cache/ntfy
      - ./ntfy/auth:/etc/ntfy
    restart: unless-stopped

生产环境的标准姿势是挂在Nginx后面:ntfy自己监听内网端口,对外走反代加HTTPS。这里有个必须单独说的坑:ntfy的实时推送走WebSocket和HTTP流式长连接,反代配置里除了常规的Upgrade头,还要把proxy_read_timeout调大(默认60秒会把长连接掐断,APP就会反复掉线重连,表现为"消息时灵时不灵"),加一行proxy_read_timeout 300s基本就稳了。这是ntfy部署环节的第一大坑,症状很迷惑,记住"时灵时不灵先查超时"这句口诀。

四、手机端:iOS和Android的订阅姿势与差异

APP两端都有官方出品,订阅操作一模一样:添加服务器地址,填主题名,完成。但推送机制有个平台级差异必须提前知道,不然会误以为搭坏了:Android版用WebSocket维持长连接,消息秒到,和微信的及时性一个级别;iOS版受系统限制,自托管服务器没有苹果推送通道可用,靠后台刷新拉取,延迟从几秒到十几分钟不等——这是个平台税,不是你的配置问题,官方文档写得明明白白。实操建议:Android设备当主力告警终端,iOS用户把重要告警再叠加一个邮件通道兜底(多通道告警本来就是最佳实践)。订阅的主题按用途拆分:vps-alerts收监控告警、vps-backup收备份回执、vps-cron收任务心跳,一台手机一个APP,分门别类,谁在喊、喊的什么,看一眼主题就知道。通知的优先级和标签在发布时指定:

curl -H "Title: 备份失败" -H "Priority: urgent" -H "Tags: warning,skull" \
  -d "vps1数据库备份失败,退出码1,速查" https://ntfy.example.com/vps-backup

Priority支持min到urgent五档,urgent会穿透手机的勿扰模式——半夜机器失联这种事,就值得穿透勿扰。

五、接入全家桶:一条curl打天下

现在把散装的通知收编。第一个,Uptime Kuma:通知设置里原生支持ntfy类型,填服务器URL和主题名,两分钟搞定,不用碰任何Webhook模板——这也是为什么选ntfy而不是自建Bark或者Gotify的重要理由,主流监控面板的原生支持意味着零胶水代码。第二个,Healthchecks:通知渠道加一个Webhook,把POST地址指向ntfy的接口,请求体里带上$STATUS、$NAME这些占位符,任务超时、失败、恢复的通知就进了同一个主题。第三个,哪吒探针:告警通知走自定义Webhook,POST到ntfy的URL,机器掉线告警即刻到手。第四个,也是最自由的——备份脚本(备份篇的restic流水线):脚本结尾加一行curl,把备份大小、耗时、目标仓库都塞进通知体,从此备份不再是"配完就忘的黑盒",每天一条回执,像心跳一样确认它真的在干活。第五个,证书到期检查、磁盘水位检查(磁盘爆满篇的巡检脚本)、安全扫描——所有能输出一行文本的脚本,都能变成一条推送。到这里你会发现一个质变:通知不再是各家监控的"配置项",而是你自己掌控的基础设施——渠道统一、格式统一、优先级统一,想加新的信息源就是加一行curl的事。

六、安全:通知通道不能裸奔

默认状态下ntfy的"无账号设计"意味着:知道你主题名的人,既能订阅偷看你的通知(告警内容往往包含机器名、域名、故障细节,本身就是敏感信息),也能往你的主题里发垃圾消息。所以对外运营的ntfy必须上认证,两步走。第一步,建账号:ntfy user add --role=admin admin给自己开管理员;第二步,配访问控制:在server.yml的auth-default-access设为deny-all(默认拒绝,白名单放行),再给监控组件们单独建只写账号:

ntfy access uptime-kuma vps-alerts write-only

write-only的意思是只能往这个主题发、不能订阅读——Uptime Kuma那边配通知时带上这个账号的Basic Auth即可,就算通知配置泄露,别人也顶多能发假告警,读不走你的历史消息。手机APP订阅用你自己的账号密码,能读所有主题。再加两道保险:反代层上HTTPS是底线(通知明文过公网等于把家底广播出去,这和Healthchecks篇说的ping URL一个道理);server.yml里配置visitor-request-limit限速,防止有人拿你的服务器当免费的垃圾推送中继——小鸡的CPU和带宽经不起扫。

七、防轰炸:优先级、标签与告警分级

通知中心建成后要防的第二个问题是自己:告警太吵,三天就把你训练成"通知免疫",狼来了的故事在运维圈天天上演。三个治理手段:第一,优先级纪律——urgent只留给"需要现在就处理"的事(机器失联、备份失败、磁盘超过90%),普通信息一律默认级,日常回执用min级(APP里折叠显示,不打扰)。分级标准自己定,但定完要守住。第二,善用标签:warning、skull、white_check_mark这些标签会渲染成表情,扫一眼通知列表不用读字就知道严重程度,配合标题里的机器名前缀(vps1-、vps2-),多机玩家一眼定位是谁在喊。第三,静默窗口:APP端对非urgent主题开勿扰时段,凌晨只放行最高优先级——机器的事九成可以等到早上八点,urgent级才配得上半夜叫醒你。还有个进阶玩法:把同一台机器的通知收敛到一个主题,用标签区分类型,手机通知自动按主题分组,一台机器一条聚合通知而不是十条轰炸。

八、套娃补完:ntfy挂了谁来喊

Healthchecks篇结尾问过"监控监控者",这里同样要问:通知中心自己挂了,谁来通知你"通知中心挂了"?答案是套娃的最后一层——用外部服务反查。两个方案:其一,用免费的ntfy.sh官方服务建一个"看家"主题,你的服务器上跑个cron(cron篇再就业),每十分钟探测自建ntfy的存活,探测失败就往官方服务的主题发一条——自建的挂了,官方的那条兜底消息照常到达手机;其二,Uptime Kuma本来就盯着一堆服务,把ntfy加进监控列表就是顺手的事——但注意,Uptime Kuma的告警通道恰恰就是ntfy自己,等于让被监控者给监控者报丧,逻辑闭环但没用。所以正确姿势是:Uptime Kuma发告警到ntfy的同时,给自己留一个邮件副通道;而盯ntfy本身存活的探测,走ntfy.sh或者另一台机器。绕是绕了点,但这就是自托管的终极觉悟:任何一个环节都不能是"没人看着的单点"——你建的最后一块基础设施,也要有人替它站岗。

结语

监控的三层(哪吒、Uptime Kuma、Healthchecks)解决的是"知道出事了",这篇解决的是"出事的消息能到达你"——后者听着不起眼,但一次深夜宕机没收到通知,损失可能超过前面所有自托管服务的月付总和。ntfy用极简的发布订阅模型,把散装在各处的告警收编成一条统一通道:一条curl接入一切,一个APP收尽全部,优先级分层不打扰,认证限速保安全。今晚花二十分钟部署起来,先把Uptime Kuma的通知切过去试试水,明早手机收到第一条"一切正常"的定时心跳时,你会理解为什么通知层也值得自托管——那四个字背后,是你对自己每一台小鸡的确定感。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

Nginx配置写到头秃?Caddy自动HTTPS实战:两行配置上线网站,证书申请续期彻底撒手不管

API按token计费肉疼?Ollama+Open WebUI私有化部署实战,小鸡也能跑起自己的AI大模型

评 论
更换验证码