NAS 上搭个通知服务,手机 1 秒收到!

如果教程对您有帮助可以"关注"、 "点赞"支持一下!!👍
本文由「NAS研习社」整理发布,欢迎转发分享~
你有没有过这种经历:凌晨三点,NAS 上的某个容器悄悄崩了,你睡得正香。第二天早上打开照片同步,发现昨晚的照片全没同步上去,翻日志才发现服务凌晨就挂了。又或者,定时备份脚本每天凌晨跑,某天磁盘满了备份失败,可你连着三天都没发现——等注意到的时候,最新的数据已经补不回来了。
这些场景的共同问题,不是服务挂了,而是挂了没人通知你。今天的方案,就是给 NAS 装一个「通知传话员」:ntfy。它的工作很简单——把你的 NAS、脚本、监控工具发出的消息,实时推到手机上。
ntfy 是什么
ntfy(读作 notify)是一个开源、自托管的推送通知服务,用 Go 写的。GitHub 上约 3.4 万 star,Apache-2.0 协议,官方 Docker 镜像同时支持 x86_64 和 ARM64,主流 NAS 都能跑。
它的工作方式叫发布/订阅(pub-sub):你给一个主题(topic)发一条消息,所有订阅了这个主题的手机、浏览器、桌面端都会立刻收到。不需要注册账号,主题名就是地址——比如给 nas-alerts 这个主题发消息,任何订阅了 nas-alerts 的设备都能收到。
官方还提供了免费公共服务器 ntfy.sh,不部署也能先体验;但公共服务器上主题是所有人共享的,所以自己 NAS 上搭一个私有实例才是正经用法。
一句话总结:ntfy = 自托管的手机推送服务,一条命令发消息,手机秒收到。
核心特性
📨 一条命令发通知: 用 curl 的 POST/PUT 就能发消息,标题、优先级、标签都能带,任何脚本、定时任务、监控工具都能直接调用。
📱 手机、浏览器都能收: Android 有官方 App(Google Play / F-Droid 都能下),iPhone 在 App Store 搜 ntfy 即可,浏览器也能订阅(还支持加到主屏幕当 App 用)。
🔔 标题、优先级、标签样样有: 紧急消息高优先级弹窗提醒,配 emoji 标签一眼看清类型(⚠️ 告警、✅ 成功、❌ 失败)。
🔗 和现有工具打通: Uptime Kuma、Home Assistant、Apprise、Grafana、changedetection.io 等几十个工具都原生支持 ntfy 通知,官方 integrations 页面有完整列表。
🔒 可加访问控制: 自建实例默认全员可读写,可以开启用户认证、给主题单独设权限,防止陌生人往你的主题里发消息。
💾 轻量到几乎无感: Go 写的单二进制,镜像下载体积只有约 30MB,消息缓存用 SQLite,NAS 上跑起来几乎不占资源。
Docker Compose 部署
先在你的 NAS 存储上建一个目录放 compose 文件,这里以群晖为例:
# 群晖示例路径;其它 NAS 换成你自己的存储目录
mkdir -p /volume1/docker/ntfy
cd /volume1/docker/ntfy新建 docker-compose.yml,内容如下(完整可复制):
services:
ntfy:
image: binwiederhier/ntfy:latest
container_name: ntfy-demo
command:
- serve
environment:
- TZ=Asia/Shanghai
# 消息持久化关键:不设置则消息仅内存缓存(重启即丢)
- NTFY_CACHE_FILE=/var/lib/ntfy/cache.db
volumes:
- ./data:/var/lib/ntfy
ports:
- "8084:80"
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost/v1/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 5s几个关键点解释一下:
image 用官方镜像 binwiederhier/ntfy,默认跟随 latest 标签;当前最新稳定版 2.27.0,想固定版本可以改成 binwiederhier/ntfy:2.27.0。
ports 把容器内的 80 端口映射到宿主机 8084。注意 ntfy 容器内部用的是 80,而很多 NAS 系统服务(群晖、飞牛)自己也占 80 端口,所以这里特意映射到 8084,避免冲突。
NTFY_CACHE_FILE 指定消息缓存文件,这是消息持久化的关键。ntfy 默认把消息只放在内存里,容器一重启就全丢;加上这一行后,消息会写入 SQLite 数据库文件(./data/cache.db),重启容器消息还在。首次部署最容易漏的就是这一行。
./data:/var/lib/ntfy 是数据卷,消息缓存(cache.db)、用户数据都存在这里,容器删了数据还在,备份就是拷走这个目录。
TZ=Asia/Shanghai 设置时区,让消息时间显示成北京时间。
healthcheck 用 wget 探测 /v1/health,容器健康了会显示 Up (healthy),有问题自动标记异常。
保存后启动:
docker compose up -d首次拉取镜像需要一点时间,取决于你的网速。容器起来后,浏览器打开 http://你的NAS地址:8084 就能看到 ntfy 的网页界面。
首次体验:订阅一个主题
打开网页,默认是一个空首页,中间有个订阅框——直接在输入框里填一个主题名,比如 nas-alerts,点 Subscribe:

填好主题名点订阅,页面会弹出确认框,不用注册、不用密码:

订阅成功后进入这个主题的消息页,目前是空的,上面有主题名和订阅状态:

到这里,你的手机推送通道就建好了。接下来试试怎么发消息。
发布第一条消息
回到终端,用 curl 往这个主题发一条消息。注意 ntfy 2.27 之后,发消息推荐用 POST 根路径 + JSON 的姿势(主题名写在 JSON 的 topic 字段里),比旧的裸文本方式更稳:
curl -H "Content-Type: application/json" \
-d '{"topic":"nas-alerts","message":"NAS 温度过高!","title":"温度告警","priority":3,"tags":["thermometer"]}' \
http://你的NAS地址:8084命令执行后,网页里 nas-alerts 主题的消息列表顶部,立刻会出现这条消息——标题、优先级、标签全都渲染好了:

再换两个主题试试。比如给 nas-backup 发备份结果,成功一条、失败一条,网页端实时收到:

nas-updates 主题发系统更新提醒,同样秒到:

消息的格式:标题、优先级、标签
如果不想记命令行,网页里也有发布表单。点右上角 Publish notification,填主题、标题、正文,还能选优先级——消息格式和 curl 发出来的一模一样:

这里说一下消息的优先级:默认消息只是普通通知,高优先级(4/5)会弹窗提醒、持续响铃,适合真正紧急的告警;普通消息静默推送就行。标签(tags)字段支持 emoji,发消息时带上,通知栏里一眼就能分辨类型。
设置页与收件箱
点开设置页,可以调通知声音、最小优先级、消息保留时长、外观主题,还能管理用户:

订阅了多个主题之后,顶部的 All notifications 会把所有主题的消息聚合到一个收件箱里,不用一个个主题切换着看:

手机浏览器打开同一个地址,是适配好的移动端布局——iPhone 上可以直接把这个页面加到主屏幕,当 App 用:

验证服务
回到终端,先看容器状态:
docker ps --filter name=ntfy
# ntfy-demo Up 45 seconds (healthy) 0.0.0.0:8084->80/tcp再查健康接口:
curl http://你的NAS地址:8084/v1/health
# {"healthy":true}看到 Up (healthy) 和 {"healthy":true},说明服务正常。
和 Uptime Kuma 联动:真正的亮点
前几篇我们部署了 Uptime Kuma 部署教程,给全家服务装了「千里眼」——但 Kuma 的告警默认只在网页上看,人不盯着还是不知道。现在有了 ntfy,这条链路就完整了:Kuma 负责盯,ntfy 负责喊。
在 Uptime Kuma 里,打开「设置 → 通知」,新增一个 Ntfy 通知:服务器 URL 填你的 ntfy 地址,主题填 uptime-alerts,优先级填 5(最高):

保存后,记得回到监控项编辑页,把这个通知勾选上——不勾选的话,监控项不会真正发通知。然后给监控项设置合适的探测间隔(比如 20 秒):

当被监控的服务真的挂了,ntfy 会立刻收到这样一条告警,标题、图标、失败原因一应俱全;服务恢复后还会收到一条 Up 通知:

从此以后,NAS 上任何服务宕机,你的手机都能第一时间收到推送,不用再等第二天早上手动翻日志了。
避坑指南
-
消息持久化:光挂数据卷不够,必须设 NTFY_CACHE_FILE。 这是最容易踩的坑:只挂载 ./data:/var/lib/ntfy 而没设 NTFY_CACHE_FILE,消息只存在内存里,docker restart 一下之前收到的消息全没了。第一次部署就是栽在这里,补上 NTFY_CACHE_FILE=/var/lib/ntfy/cache.db 后重启,消息完整保留。本文的 compose 已包含这一行,别删。
-
发布消息用 POST 根路径 + JSON,别用旧版裸文本姿势。 新版 ntfy 对 curl -d "xxx" 这种无 Content-Type 的裸文本请求可能返回 40014 错误;把主题名放进 JSON 的 topic 字段、POST 到根地址是最稳的姿势,本文代码块里就是这个写法。
-
主题名要起得难猜一点。 默认配置下,任何知道主题名的人都能订阅和发布——不知道主题名就没法订阅,但主题名太简单(比如 test、123)容易被别人扫到。个人使用建议用带随机后缀的主题名,比如 nas-alerts-8f2k9;要更稳的话,打开认证(设置 auth-file + 创建用户)给主题单独设权限。
-
Kuma 联动有两个容易漏的细节。 一是通知建好后必须在监控项编辑页勾选,否则监控项不会用这个通知;二是 Kuma 只在状态变化(UP→DOWN、DOWN→UP)时发通知,第一次探测失败不会通知(因为没有基线)。
-
端口别和已有服务撞车。 ntfy 容器内部用 80,映射到宿主机时建议避开常见的 3000/8080 和 NAS 系统占用的端口,本文用 8084 就是演示环境避让的结果。
-
iOS 即时通知需要额外配置。 苹果系统不允许 App 长时间后台运行,所以自建实例想实现 iOS 即时推送,需要按官方文档配置 upstream-base-url 把消息转发给 ntfy.sh 做 APNs 推送;不配置的话 iOS 端通知可能延迟。Android 没这个问题:App 走常驻连接,F-Droid 版和自建实例都是即时送达。
-
数据目录记得备份。 消息缓存(cache.db)、用户、访问控制全在 ./data 目录里,定期把整个目录备份走,恢复时放回原位启动容器即可。
-
latest 标签是滚动更新的。 当前最新稳定版 2.27.0;想固定版本把 image 改成 binwiederhier/ntfy:2.27.0,升级前先备份 ./data。
-
镜像大小看口径。 Docker Hub 上显示的约 30MB 是压缩后的下载体积;本地 docker images 里看到的约 121MB 是解压后的实际占用,两个都对,别被吓到。
使用场景
服务宕机告警: 配合 Uptime Kuma 监控,NAS 上任何服务挂了,手机立刻收到通知。
备份结果通知: 定时备份脚本跑完,成功发 ✅、失败发 ❌,再也不用第二天手动查日志确认。
长任务完成提醒: rsync 同步、视频转码、下载任务做完,发一条消息到手机,不用一直守着。
系统更新提醒: 检测到新版本、安全更新,推送到手机再决定什么时候动手。
智能家居联动: Home Assistant 等平台原生支持,门锁、传感器事件也能推到手机。
定时/延迟提醒: 官方支持延迟消息和定时发送,配合脚本可以做任意形式的提醒。
小结
推送通知这件事,核心就一句话:服务该告诉你的事,不能等你主动去看。ntfy 把 NAS、脚本、监控工具和你的手机连成一条线——部署只需要一个 compose 文件、镜像下载体积只有约 30MB,却是把「被动发现故障」变成「主动收到通知」的关键一环。和 Uptime Kuma 搭配起来,你的 NAS 才真正算得上「有人值班」。
有任何问题欢迎私信或留言与我们互动!
个人观点,不喜勿喷~