目录

通知推送服务方案

Bark 与 ntfy 两款可自建的通知推送服务对比

在服务端开发与运维场景中,常常需要把监控告警、构建结果、定时任务状态等信息以推送通知的形式实时发送到手机或桌面。直接接入各厂商的推送通道(APNs、FCM)成本较高,而第三方 SaaS 又涉及数据出境和付费问题。此时,自建通知推送服务成为一种兼顾可控性与简洁性的选择。

本文介绍两款主流的开源推送服务——Bark 与 ntfy,并给出对比与选型建议。两者都支持自建,但定位差异明显:Bark 偏向 iOS 个人用户的轻量推送,ntfy 则是一个跨平台的 pub/sub 通知系统。

Bark 是一款 iOS 端的自定义推送工具,主打「免费、简单、安全」,借助苹果 APNs(Apple Push Notification service)下发,不在后台常驻进程,因此不会额外耗电。需要注意:Bark 客户端仅有 iOS 版本,没有官方 Android 实现。

Bark 的链路非常简单:

  1. 在 iOS 设备上安装 Bark App,App 启动后会向 APNs 注册并获得一个唯一的 key;
  2. 服务调用方把这个 key 与自定义的标题、正文等内容发往 bark-server;
  3. bark-server 转发给 APNs,再由 APNs 投递到 iPhone。

整个过程中,设备本身不暴露公网地址,推送也能在锁屏、息屏状态下到达。

bark-server 使用 Go 编写,以 MIT 协议开源。默认使用内嵌的 Bbolt 文件数据库存储数据,数据目录默认为 /data;如果数据量较大或需要共享存储,可通过 -dsn 参数切换到 MySQL:

# 使用 Docker Hub 镜像启动
docker run -dt --name bark \
  -p 8080:8080 \
  -v "$(pwd)/bark-data:/data" \
  finab/bark-server

二进制部署时常用的启动参数:

bark-server \
  --addr 0.0.0.0:8080 \
  --data ./bark-data
# 切换到 MySQL:
# bark-server -dsn=user:pass@tcp(mysql_host)/bark

Bark 的接口非常直观,URL 路径本身就承载了内容,最低成本的调用方式是直接 GET 一个 URL:

# 最简形式:key/body
curl https://api.day.app/YOUR_KEY/这是正文

# 带标题:key/title/body
curl https://api.day.app/YOUR_KEY/告警/CPU使用率超过90%

# POST JSON 方式(更灵活,推荐)
curl -X POST https://api.day.app/YOUR_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "title": "构建结果",
    "body": "main 分支构建成功",
    "group": "ci",
    "sound": "bell",
    "level": "timeSensitive",
    "url": "https://ci.example.com/job/1234"
  }'

URL 路径的完整形态为 /:key/:title/:subtitle/:body,POST JSON 时则可携带更多参数。

  • 分组(group):按业务线把通知聚合到一组,避免通知中心被刷屏。
  • 自定义图标与声音:图标支持在 iOS 15+ 上自定义;声音可指定音效,也支持 30 秒循环的「电话来电」提醒模式。
  • 中断级别(level):active(默认,亮屏)、timeSensitive(可在专注模式下穿透)、passive(仅加入通知列表,不亮屏)。
  • 严重告警(critical):忽略静音与勿扰模式,适合无人值守的告警。
  • 端到端加密:通过 ciphertext 参数推送加密内容,密钥仅客户端持有。
  • 点击跳转(url):点击通知后打开指定 URL,常用于跳转到告警详情页。

ntfy(读音同 “notify”)是一个基于 HTTP 的发布订阅(pub/sub)通知服务。与 Bark 不同,ntfy 跨平台:Android、iOS、Web、桌面 PWA、CLI 全部支持,且同时提供免费公共实例 ntfy.sh 与可自建的私有部署。采用 Apache 2.0 与 GPLv2 双协议开源,作者为 Philipp C. Heckel。

ntfy 采用 topic(主题)模型:

  • 发布方把消息以 PUT/POST 发到 ntfy.sh/<topic>;
  • 订阅了该 topic 的客户端(Android/iOS App、Web、CLI、WebSocket、MQTT 等)即时收到推送;
  • topic 无需显式创建,任意命名即可,文档建议选择不可猜测的长名字以避免被他人订阅。

公共实例底层用 Firebase Cloud Messaging(FCM)和 Web Push 进行实际下发,自建实例同样依赖这些通道。消息缓存默认写入 SQLite。

官方提供 Docker 镜像与 docker-compose.yml:

docker run -d \
  --name ntfy \
  --restart=unless-stopped \
  -p 80:80 \
  -v /var/lib/ntfy:/var/lib/ntfy \
  -v /etc/ntfy:/etc/ntfy \
  binwiederhier/ntfy serve

自建实例可通过配置文件开启访问控制(ACL)、消息持久化、附件大小限制、速率限制等。对于需要严格权限控制的内部环境,通常配合反向代理(Traefik、Nginx)做 TLS 与鉴权。

最小调用只要一行 curl:

# 发送一条普通消息到 mytopic
curl -d "数据库备份完成" ntfy.sh/mytopic

# 带标题、优先级、标签(emoji)和点击动作
curl -H "Title: 生产环境告警" \
     -H "Priority: high" \
     -H "Tags: warning,skull" \
     -H "Click: https://grafana.example.com" \
     -d "订单服务 5xx 错误率超过 5%" \
     ntfy.sh/prod-alerts

也可以在脚本里用 Python、Go、JavaScript 等任意 HTTP 客户端发送,或使用官方 ntfy CLI。

  • 无需注册:公共实例开箱即用,自建实例也只关心 topic 名。
  • 多客户端:Android(Google Play 与 F-Droid)、iOS、Web、PWA、CLI,覆盖桌面与移动端。
  • 富通知:支持优先级、tag(emoji 图标)、标题、点击跳转、动作按钮(Action Buttons)。
  • 附件:可在通知中携带文件,小文件直传,大文件可作为链接。
  • 多种传输:HTTP、WebSocket、MQTT、邮件(SMTP),方便集成遗留系统。
  • 访问控制:基于用户/角色的 ACL,可精细化限制谁能发布或订阅。
  • 消息持久化与调度:支持消息缓存与延迟/定时发送(At、Every)。
维度Barkntfy
客户端平台仅 iOSAndroid、iOS、Web、桌面、CLI
协议自有 HTTP API(V2)HTTP pub/sub
后端语言GoGo + React
数据存储Bbolt(默认)/ MySQLSQLite
推送通道APNsFCM + Web Push
加密推送支持(ciphertext)支持(自建可启用 TLS + ACL)
公共实例无官方公共服务提供 ntfy.sh 公共实例
部署复杂度低(单二进制/Docker)中(配置项较多)
适用场景个人 iOS 设备的轻量告警团队/多端订阅、复杂通知需求

实操建议:

  • 只有 iPhone、只需要给自己推告警:用 Bark,部署最简单,API 也最直观,加密推送可以避免敏感内容经过服务器明文留存。
  • 需要同时通知 Android/iOS/桌面,或要做团队订阅、带附件、带动作按钮:用 ntfy。它的 pub/sub 模型天然适合「一个事件、多端订阅」的场景,公共实例还能让外部协作者直接订阅。

两者并不互斥:很多团队会以 ntfy 作为主通道,同时用 Bark 给值班的 iOS 设备做兜底告警,把延迟敏感的 critical 推送单独走 Bark,绕开 FCM 在国内网络的可达性问题。

相关内容