ntfy:极简开源消息推送服务,curl一条命令实现手机通知

发布时间:2026/9/8 3:02:40
ntfy:极简开源消息推送服务,curl一条命令实现手机通知 简介这是一份基于Go语言开发的开源推送通知工具 ntfy 的完整项目资源面向开发者、运维人员以及需要自建通知服务的用户。ntfy 通过简单的 PUT/POST 请求即可将消息推送到手机或桌面端适合系统告警、任务完成提醒、脚本执行反馈等场景省去对第三方推送平台的依赖。压缩包共415个文件大小约12.89MB内容以Go源码、前端JS/JSX、JSON配置和Markdown文档为主同时包含Docker构建与编译配置方便容器化部署。项目中还附带了png/jpg/svg图标、woff2字体以及少量mp3、mp4等媒体资源基本覆盖Web界面所需的静态素材。目前已有1658人学习或下载。对于希望快速搭建私有通知服务的用户可以直接参考Docker构建配置与项目目录对于想了解Go语言项目结构的前后端开发者也可从源码和文档中获得完整示例。整体目录组织清晰适合直接用于本地构建、二次开发或学习通知服务的实现方式。 直接说结论如果你一直在找一种“不依赖微信、不依赖企业微信、不依赖云厂商推送服务”的轻量通知方案ntfy 基本是目前最省事的答案。它本质上是一个开源的消息推送服务核心用法简单到离谱——用 curl 发一个 POST 请求手机就能收到通知。我把它接到服务器监控、定时任务、脚本告警之后跑了几个月最大的感受是这工具是真的把“推送通知”这四个字做到了极简。先给没听过的人一个定位。ntfy 的全称是 notify它实现了“一个 HTTP 请求触发一次推送”的完整闭环。公共服务器 ntfy.sh 可以直接用也可以在自己服务器上用 Docker 或 Go 二进制部署支持 Android、iOS、桌面浏览器、Web App。它的目标用户很明确开发者、运维、自托管爱好者以及任何一个“想让脚本在跑完时告诉我结果”的人。下面我会从原理、部署、进阶用法、排障四个维度把它们讲透。1. 为什么需要 ntfy推送通知的“最后一公里”问题1.1 传统推送方案的几个痛点先说背景。做技术的人几乎都会遇到一类场景cron 任务跑完了想收到通知、服务器磁盘快满了想收到告警、CI 构建失败想第一时间知道、家里的 NAS 备份完成想确认一下。这些场景的本质需求都差不多——“机器主动告诉我一件事”。传统方案里我见过不少人在用这些路数发邮件到自己的 QQ 邮箱或 Gmail靠邮箱 App 弹出通知。问题是延迟不确定配置 SMTP 麻烦而且很容易被丢进垃圾箱。用钉钉、飞书、企业微信的机器人 webhook。功能不差但需要注册组织、建群、绑定机器人过程非常重而且个人信息和这些平台绑定太深。写一个常驻脚本轮询某个接口发现变化再推送。成本高、不稳定还要考虑重连逻辑。用 Telegram Bot。能用但国内网络环境连接不稳且对很多人来说注册、保持在线本身就是一个门槛。这些方案不是不能用而是都太“重”了。我更希望有一个足够简单的通道一条命令发出去手机能响桌面能弹。不关心用户体系不关心协议细节不关心聊天会话只关心“通知”本身。ntfy 正好就是从这个角度切入的。1.2 ntfy 的核心思路Topic 即通道ntfy 的模型非常直观你订阅一个 Topic主题任何向这个 Topic 发送消息的客户端都会把消息推给所有订阅者。Topic 就是通道本身不需要注册账号不需要在客户端登录只要知道 Topic 名字就能收发。这个设计大大降低了使用门槛。公共服务器上默认的 Topic 是全局共享的你随手用一个随机字符串比如disk-alert-9f2a基本就不会和别人冲突自托管环境下Topic 只在自己服务器上可见完全可控。值得多说一句的是ntfy 的“推送”不是像聊天软件那样靠长连接长轮询硬扛而是使用了多种推送通道的组合。在手机端Android 客户端默认走 Firebase Cloud MessagingFCM来保证系统级送达如果自托管时不想依赖 FCM也可以通过客户端内置的“WebSocket 长连接 后台保活”机制实现。桌面端则是通过浏览器通知或 WebSocket 推送。这些细节在后续排障部分我会展开。2. 5 分钟快速上手从 curl 到手机响铃2.1 免部署方案直接使用公共服务器 ntfy.sh最快跑通的方式一条命令搞定在任意一台机器或手机浏览器上执行curl -d Hello from my terminal ntfy.sh/alert-test-9f2a然后在手机上安装 ntfy 应用Android 英文界面的应用商店里有iOS 则在 App Store 搜索 ntfy打开后点击“”号订阅 Topic 为alert-test-9f2a。稍等几秒就会在手机收到这条消息。为什么能这么简单核心就在于它用的就是一个普通的 HTTP POST 请求。ntfy.sh/alert-test-9f2a可以被理解为“门牌号”服务端收到请求体后会把它作为消息内容推送给所有订阅这个 Topic 的客户端。没有鉴权、没有签名、没有任何额外配置确实是“零门槛”。我觉得你可以在自己的电脑上多试一试这些变体# 带标题的消息 curl -H Title: 备份完成 -d 备份任务已成功执行耗时 3 分钟。 ntfy.sh/backup-notify # 带优先级urgent 为最高 curl -H Title: 磁盘告警 -H Priority: urgent -d /dev/sda1 使用率已超过 90% ntfy.sh/alert-test-9f2a # 带 Markdown 渲染 curl -H Markdown: yes -d **构建失败**\n\n 查看日志https://example.com/log ntfy.sh/ci-notify这里提醒一句公共服务器可以随意使用但 Topic 名字一定要够随机否则容易收到其他人的测试消息。这不是 ntfy 的 bug而是公网共享空间的天然特性。个人使用、日常脚本、临时测试用公共服务器完全够了。2.2 自托管部署数据落在自己手里公共服务器虽然方便但如果你对消息隐私有要求或者想把 Topic 做成内部专用自托管会是一个更好的选择。ntfy 的自托管部署非常简单官方提供了 Docker 镜像也支持直接下载二进制文件跑 systemd 服务。以 Docker 方式为例这是我在生产环境里实际用下来的方案docker run -d \ --name ntfy \ --restartunless-stopped \ -p 8080:80 \ -v /var/lib/ntfy:/var/lib/ntfy \ binwiederhier/ntfy serve \ --listen-addr :80这里做了一个端口映射把宿主机的 8080 映射到容器内的 80。为什么外面用 8080因为我不希望 ntfy 直接占用宿主机 80 端口尤其是当服务器上还有其他 Web 服务时。映射完成后访问http://服务器IP:8080就能看到 Web 界面。如果你希望像官方文档那样让 ntfy 直接暴露在标准 80 端口也不难把-p 8080:80改成-p 80:80即可。但这样需要确保 80 端口在系统防火墙里是放行的而且如果服务器前面套了 Nginx 反代还需要额外配置代理规则。自托管之后推送地址就变成了你自己的地址例如curl -d 服务启动成功 http://your-server.com:8080/status手机端订阅同样改成这个地址和对应 Topic 即可。另外一个容易被忽略的配置自托管最好开启用户认证。ntfy 支持简单的user add命令和 Bearer Token 方式官方文档里写得很清楚。我在实际部署时会先创建一个专用用户再生成一个只读或只写的 Token把它写成环境变量供脚本调用。这样做的好处是即使 Token 泄露也不会影响服务器本身的 SSH 或其他服务。2.3 客户端安装与 Topic 订阅细节客户端是使用体验中很重要的一环。我自己的主力手机是 Android装的是 F-Droid 版iOS 上则用 TestFlight 或 App Store 版。两者的基本逻辑一样添加服务器地址默认是ntfy.sh、输入 Topic 名称、完成订阅。订阅时有一个容易忽略的选项叫“Instant Delivery即时送达”。在 Android 上ntfy 默认通过 FCM 通道推送理论上息屏也能秒达。但如果你自托管且禁用了 FCM就必须依赖客户端自身的后台服务来维持连接。这时候需要在客户端设置里打开“Use built-in WebSocket”之类的选项并且把 ntfy 加入系统的电池优化白名单否则锁屏一段时间后可能收不到通知。桌面端也很实用。ntfy 官方提供 Web App直接用浏览器打开https://ntfy.sh/app或你的自托管地址用浏览器通知功能就能收订阅消息。macOS 上还可以用系统自带的通知中心配合网页推送接口实现类似原生 App 的体验。3. 进阶功能拆解让通知从“能收到”变成“愿意看”3.1 优先级、标签与 Markdown 渲染只发一条纯文本没问题但很快你就会发现纯文本通知在手机上很难快速分辨轻重缓急。ntfy 自带了几种通知增强能力我觉得最常用的是这三个Priority优先级、Tags标签和 Markdown 渲染。优先级范围是 1 到 5分别对应min、low、default、high、urgent。在 curl 里用X-Priority或PriorityHeader 控制。实际使用时我习惯这样约定default常规通知比如定时任务完成。high需要尽快关注但不至于叫醒我比如 CI 测试失败。urgent必须立刻处理比如服务器宕机或磁盘接近写满。设置urgent的消息在手机端默认会持续弹窗或播放声音甚至可以指定重试时间间隔。我做过一个磁盘监控脚本当剩余空间低于 5GB 时发送urgent级通知效果非常明显。标签功能也很有意思。通过在 Header 里加X-Tags可以给通知打上图标标记。例如curl -H X-Tags: warning -d CPU 温度过高 ntfy.sh/hw-monitorwarning会显示成一个警告图标。类似的还有error、ok、skull等你可以去官方文档看完整的图标列表。这些标签配合优先级能让通知列表一眼扫过去就很清晰。Markdown 渲染则解决了“通知里想带格式”的问题。加一个Markdown: yes的 Header 后消息正文里的**加粗**、[链接](url)、引用块等都会被正确渲染。我最常用的场景是 CI 构建通知构建失败时直接把失败的 commit、错误日志头部、查看链接统统塞进一条 Markdown 通知里。3.2 Action 按钮与点击跳转这应该是最容易被忽略但实际价值很高的功能。ntfy 支持在消息里定义“按钮”用户点按后可以触发 HTTP 请求或打开 URL。它的语义不是“通知我”而是“让我在通知里直接操作”。举个例子我写过一台下载服务器的监控脚本当种子下载完成时ntfy 会收到一条带有“打开网盘目录”按钮的通知点击后直接跳转到文件管理页面。实现方式是在 POST 请求里增加一个 JSON 格式的X-ActionsHeadercurl -H Actions: http, 打开网盘, http://nas.local/files, cleartrue \ -d 电影 《xxx》 下载完成 \ ntfy.sh/download-done这里的格式是类型, 按钮文案, 目标URL, 附加参数。支持的按钮类型有view打开 URL、http请求任意地址、broadcast发送 Android 广播。需要注意的是按钮 URL 在手机端打开时需要确保目标地址能在手机上访问否则按钮只是摆设。我觉得“点击跳转”是让 ntfy 从玩具变成生产力的一个重要分界点。单纯的“收到消息”只是入口真正解决问题的是按下按钮后能直接完成下一步动作。你可以根据自己的场景设计按钮比如“重启服务”“查看日志”“确认执行”等。3.3 脚本模板把 ntfy 写进自动化流程到了这个阶段ntfy 就不只是“curl 发一条消息”了而是成为自动化流程里的一个标准输出端。这里分享几个我用实际环境验证过的模板。一个是简单的 bash 函数放在~/.bashrc或脚本头部notify() { local topic$1 shift curl -s -H Title: $1 -d ${:2} https://ntfy.sh/${topic} } # 用法示例 notify backup-results 备份状态 备份成功耗时 12 分钟另一个是我实际在用的 cron 监控脚本模板#!/bin/bash DISK_USAGE$(df -h / | awk NR2 {print $5} | sed s/%//g) THRESHOLD85 if [ $DISK_USAGE -gt $THRESHOLD ]; then curl -s \ -H Title: 磁盘告警 \ -H Priority: urgent \ -H Tags: warning \ -d 根分区使用率已达 ${DISK_USAGE}%请及时清理。 \ https://ntfy.sh/server-alerts-9f2a fi这套模板我放在 crontab 里每 10 分钟执行一次。实际测试下来从脚本触发到手机收到通知公共服务器上耗时通常在 1 秒以内。自托管环境下如果客户端走 WebSocket 直连耗时也基本在毫秒级。如果你用 Python 写自动化也可以用 requests 简单的 POSTimport requests requests.post( https://ntfy.sh/my-topic, data任务完成共处理 1024 条记录.encode(utf-8), headers{ Title: 数据处理结果, Priority: low, Tags: tada } )如果你是 Home Assistant 用户ntfy 也有现成的集成方案直接把通知发到手机比很多高度依赖云端平台的组件要省心得多。把这类“反直觉但真的好用”的工具纳入自己的自动化体系是提升效率最快的方式之一。4. 常见问题与排障实录4.1 自托管场景下容易踩的坑第一个坑是端口被防火墙拦截。很多云服务器默认只放行 80、443、22 这几个端口你如果用 8080 端口部署 ntfy一定要记得在安全组和系统防火墙中同步放行否则手机端一直提示“无法连接”。我自己就因为改了 Docker 端口映射却忘记改安全组规则折腾了半个小时。第二个坑是 Topic 命名。如果你在自托管环境里也用很短的、常见的单词比如test、alert并且服务器暴露在公网很可能被扫到并打扰。更合理的做法是用一个前缀比如myapp-prod-随机数或者通过 nginx 加一层 Basic Auth。第三个坑是 Docker 的卷权限。我在某次升级 ntfy 版本后发现容器无法启动排查后发现是宿主机/var/lib/ntfy目录的属主变了。解决办法是在 docker run 时通过-e PUID1000 -e PGID1000之类的环境变量固定用户或用chown调整目录归属。这个坑不算 ntfy 独有但 Docker 部署时很常见值得留意。第四个坑是反向代理的 WebSocket 支持。如果你打算把 ntfy 放在 Nginx 后面还需要额外配置 Upgrades 头。我直接把这块配置贴出来备查location / { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Host $host; }如果不加这一段浏览器端 Web App 能加载但实时推送收不到。这个坑在所有基于 WebSocket 的推送服务里都一样ntfy 官方文档里也强调了这一点。4.2 移动客户端收不到通知的原因Android 上最常见的问题是自己部署 ntfy 后收不到推送但 iOS 正常。这个我排查了很久最后发现原因在于 Android 客户端默认使用 FCM 通道而 FCM 在中国大陆网络环境存在连通性不稳的问题。解决办法有两个方向一是关闭客户端的 FCM 选项强制使用内置 WebSocket 长连接二是给客户端开启“自启动”和“无电池限制”保证它在后台不会被系统杀掉。iOS 端则是另一个极端。由于系统限制iOS 上很难稳定维持长连接。为了让 iOS 能及时收到通知大多还是得靠 ntfy 官方公共服务器作为中转或者自己搭一个 APNs 转发层但这已经明显超出轻量使用的范畴了。我的建议是如果你主力是 iOS直接用公共服务器最省心。还有个低级但高频的错误客户端订阅的 Topic 和 curl 推送的 Topic 对应不上。如果 Topic 大小写不一致、多了或少了一个空格消息就传不到。尤其是当 Topic 里包含数字和连字符时手输很容易错。4.3 我对 ntfy 实际使用的一些心得几个月的使用下来我对 ntfy 的感受是它解决了一个非常具体、非常普遍的问题并且没有把这个问题变复杂。相比大厂的推送服务它更像是一个“螺丝刀”级别的工具体积小、毛病少、上手快。对我来说最有价值的使用方式是把它作为“所有脚本的统一出口”。不管是服务器监控、CI 通知、按时提醒还是下载完成提示只要在脚本里加一行 curl就能把信息送到手机和桌面。它不会为你解决所有问题但能把“机器主动通知人”这件事从繁琐变成顺手。如果你打算长期用我还是建议花 10 分钟把自托管方案跑起来。公共服务器适合体验但用自己的服务器才能真正控制消息内容和访问权限。最后再分享一个小技巧在写推送脚本时把 curl 包在一个带退避重试的函数里比如失败后 3 秒重试一次最多重试 3 次。这样即使推送服务短暂抖动脚本任务也不会丢消息。这个小细节在很多高可用告警场景里都帮到过我。本文还有配套的精品资源点击获取