剪藏#NAS研习社#剪藏

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

2026 年 8 月 22 日1 分钟
分享Twitter / XTelegram微博
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 文件,这里以群晖为例:

JAVASCRIPT
# 群晖示例路径;其它 NAS 换成你自己的存储目录
mkdir -p /volume1/docker/ntfy
cd /volume1/docker/ntfy

新建 docker-compose.yml,内容如下(完整可复制):

JAVASCRIPT
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),有问题自动标记异常。

保存后启动:

JAVASCRIPT
docker compose up -d

首次拉取镜像需要一点时间,取决于你的网速。容器起来后,浏览器打开 http://你的NAS地址:8084 就能看到 ntfy 的网页界面。

首次体验:订阅一个主题

打开网页,默认是一个空首页,中间有个订阅框——直接在输入框里填一个主题名,比如 nas-alerts,点 Subscribe:

Notion image

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

Notion image

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

Notion image

到这里,你的手机推送通道就建好了。接下来试试怎么发消息。

发布第一条消息

回到终端,用 curl 往这个主题发一条消息。注意 ntfy 2.27 之后,发消息推荐用 POST 根路径 + JSON 的姿势(主题名写在 JSON 的 topic 字段里),比旧的裸文本方式更稳:

JAVASCRIPT
curl -H "Content-Type: application/json" \
  -d '{"topic":"nas-alerts","message":"NAS 温度过高!","title":"温度告警","priority":3,"tags":["thermometer"]}' \
  http://你的NAS地址:8084

命令执行后,网页里 nas-alerts 主题的消息列表顶部,立刻会出现这条消息——标题、优先级、标签全都渲染好了:

Notion image

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

Notion image

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

Notion image

消息的格式:标题、优先级、标签

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

Notion image

这里说一下消息的优先级:默认消息只是普通通知,高优先级(4/5)会弹窗提醒、持续响铃,适合真正紧急的告警;普通消息静默推送就行。标签(tags)字段支持 emoji,发消息时带上,通知栏里一眼就能分辨类型。

设置页与收件箱

点开设置页,可以调通知声音、最小优先级、消息保留时长、外观主题,还能管理用户:

Notion image

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

Notion image

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

Notion image

验证服务

回到终端,先看容器状态:

JAVASCRIPT
docker ps --filter name=ntfy
# ntfy-demo   Up 45 seconds (healthy)   0.0.0.0:8084->80/tcp

再查健康接口:

JAVASCRIPT
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(最高):

Notion image

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

Notion image

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

Notion image

从此以后,NAS 上任何服务宕机,你的手机都能第一时间收到推送,不用再等第二天早上手动翻日志了。

避坑指南

  1. 消息持久化:光挂数据卷不够,必须设 NTFY_CACHE_FILE。 这是最容易踩的坑:只挂载 ./data:/var/lib/ntfy 而没设 NTFY_CACHE_FILE,消息只存在内存里,docker restart 一下之前收到的消息全没了。第一次部署就是栽在这里,补上 NTFY_CACHE_FILE=/var/lib/ntfy/cache.db 后重启,消息完整保留。本文的 compose 已包含这一行,别删。

  2. 发布消息用 POST 根路径 + JSON,别用旧版裸文本姿势。 新版 ntfy 对 curl -d "xxx" 这种无 Content-Type 的裸文本请求可能返回 40014 错误;把主题名放进 JSON 的 topic 字段、POST 到根地址是最稳的姿势,本文代码块里就是这个写法。

  3. 主题名要起得难猜一点。 默认配置下,任何知道主题名的人都能订阅和发布——不知道主题名就没法订阅,但主题名太简单(比如 test、123)容易被别人扫到。个人使用建议用带随机后缀的主题名,比如 nas-alerts-8f2k9;要更稳的话,打开认证(设置 auth-file + 创建用户)给主题单独设权限。

  4. Kuma 联动有两个容易漏的细节。 一是通知建好后必须在监控项编辑页勾选,否则监控项不会用这个通知;二是 Kuma 只在状态变化(UP→DOWN、DOWN→UP)时发通知,第一次探测失败不会通知(因为没有基线)。

  5. 端口别和已有服务撞车。 ntfy 容器内部用 80,映射到宿主机时建议避开常见的 3000/8080 和 NAS 系统占用的端口,本文用 8084 就是演示环境避让的结果。

  6. iOS 即时通知需要额外配置。 苹果系统不允许 App 长时间后台运行,所以自建实例想实现 iOS 即时推送,需要按官方文档配置 upstream-base-url 把消息转发给 ntfy.sh 做 APNs 推送;不配置的话 iOS 端通知可能延迟。Android 没这个问题:App 走常驻连接,F-Droid 版和自建实例都是即时送达。

  7. 数据目录记得备份。 消息缓存(cache.db)、用户、访问控制全在 ./data 目录里,定期把整个目录备份走,恢复时放回原位启动容器即可。

  8. latest 标签是滚动更新的。 当前最新稳定版 2.27.0;想固定版本把 image 改成 binwiederhier/ntfy:2.27.0,升级前先备份 ./data。

  9. 镜像大小看口径。 Docker Hub 上显示的约 30MB 是压缩后的下载体积;本地 docker images 里看到的约 121MB 是解压后的实际占用,两个都对,别被吓到。

使用场景

服务宕机告警: 配合 Uptime Kuma 监控,NAS 上任何服务挂了,手机立刻收到通知。

备份结果通知: 定时备份脚本跑完,成功发 ✅、失败发 ❌,再也不用第二天手动查日志确认。

长任务完成提醒: rsync 同步、视频转码、下载任务做完,发一条消息到手机,不用一直守着。

系统更新提醒: 检测到新版本、安全更新,推送到手机再决定什么时候动手。

智能家居联动: Home Assistant 等平台原生支持,门锁、传感器事件也能推到手机。

定时/延迟提醒: 官方支持延迟消息和定时发送,配合脚本可以做任意形式的提醒。

小结

推送通知这件事,核心就一句话:服务该告诉你的事,不能等你主动去看。ntfy 把 NAS、脚本、监控工具和你的手机连成一条线——部署只需要一个 compose 文件、镜像下载体积只有约 30MB,却是把「被动发现故障」变成「主动收到通知」的关键一环。和 Uptime Kuma 搭配起来,你的 NAS 才真正算得上「有人值班」。

有任何问题欢迎私信或留言与我们互动!

个人观点,不喜勿喷~

原文地址: https://mp.weixin.qq.com/s?__biz=MzYyMzI4NzQ2Mg==&mid=2247484484&idx=1&sn=b8c75c778c097171624b27d027b7176c&chksm=fe34165c31da8f2feb35dc65741afb0be13223f85b479364643aa19db2a6b4d3884e2a444749&mpshare=1&scene=1&srcid=0821wfVky60HqCknE5DqhHSg&sharer_shareinfo=5b7d4db1911632e2398aece1976f1a52&sharer_shareinfo_first=5b7d4db1911632e2398aece1976f1a52#rd

相关文章