家里那台 NAS 每隔一阵就会在半夜出点事:备份任务失败、硬盘温度报警、UPS 掉电。以前靠邮件通知,第二天早上才看见;后来试过微信推送,免费额度用得快,接口还得看第三方脸色。我真正想要的其实很简单——服务器上一条命令,手机立刻响一下,标题写什么、点进去跳到哪个页面,都由我自己说了算。
用了大半年 Bark,它基本就是干这个的。它不是又一个要注册账号的推送平台,而是「iOS 客户端 + 你自己的服务端」:客户端把通知交给苹果的 APNs,服务端只负责拼 APNs 那一层请求,中间没有第二家公司能读到你的消息。
免费、无广告,还肯把 iOS 的能力交出来
App Store 直接搜得到,无广告、无内购、不用注册账号,唯一的身份凭证是一串设备 key。更关键的是它把 iOS 原生通知几乎全暴露了:时效性通知能在专注模式下穿透、critical 级别可以无视静音、能设角标数字、能指定铃声、能让通知连响 30 秒、还能给通知配一个远程图标。这些东西在别的推送方案里通常要写原生代码才能碰到。
我数了一下接口文档,除了正文之外还有 18 个字段可调,够用了。
自建服务端:18MB 单文件,17.8MB 内存
这是我最在意的一段实测。我用官方 v2.3.9 的 Windows 预编译版在本机跑了一遍:可执行文件 18.2MB,双击到 /ping 返回 pong 一共 862 毫秒(含进程拉起和 50 毫秒一次的轮询粒度),稳定后常驻内存 17.8MB、私有内存 53.1MB、10 个线程。
数据落在哪?默认是数据目录下的 bbolt 单文件,注册第一个设备后整个目录只有 32KB——bbolt 按页预分配,设备数量涨到几十个也基本感觉不到体积变化。这意味着备份它就是拷一个文件,扔到 NAS 的定时任务里完事;设备真上到几百个,再换 -dsn 接 MySQL。
部署就两条路。有 Docker 的话:
docker run -dt --name bark -p 8080:8080 -v $(pwd)/bark-data:/data finab/bark-server
不想装 Docker 就直接下二进制:
./bark-server --addr 0.0.0.0:8080 --data ./bark-data
两种方式跑起来是同一个东西,剩下的就是拿 Nginx 或 Caddy 套一层域名和证书。
推一条通知长什么样
服务端起来后,注册设备拿到 key,然后一条 POST 就够:
curl -X POST "https://你的域名/push" \
-H 'Content-Type: application/json; charset=utf-8' \
-d '{"device_key":"你的key","title":"NAS 备份失败","body":"volume1 增量备份在 03:12 中断","group":"NAS","level":"timeSensitive","badge":1,"url":"https://nas.local/logs"}'
group 让同类通知叠在一起,url 决定点进去跳到哪,level 选 timeSensitive 就能在专注模式下漏进来,真要炸醒自己就换 critical 再配 call=1。device_keys 是数组,一次推给多台设备;isArchive 加 ttl 能让通知在 App 里存一段时间,回头翻记录。脚本里就是一个 curl,塞进备份脚本的失败分支、Zabbix 的告警动作、或者容器的 healthcheck,都不用额外依赖。
四个我实际踩过的坑
第一,也是最多人中招的:装了自建服务端,App 里却没改地址,通知一直走官方服务器,等于白折腾。iOS 端设置里手动填 https://你的域名,填完记得发一条测试。
第二,设备 key 只能真机注册。我随手编了个假 token 调 /push,服务端直接回 400——它确实是拿这个 token 去跟 APNs 对话的,糊弄不过去。
第三,自建地址老老实实上 https。明文 http 在 iOS 那边容易被拦,为了省一张证书把整条链路搞成玄学不值得,Caddy 两行配置就有证书了。
第四,icon 参数必须是公网能打开的图片地址,填本地路径不会显示任何东西。
和同类比,它适合谁
ntfy 跨平台更全面,安卓、桌面、网页都覆盖,但 iOS 端自建的步骤明显更多;Server酱 走微信、不用装 App,可免费额度有限而且不能自建;PushDeer 同样能自建,客户端更新节奏慢一些。如果你的场景就是「服务器有事,iPhone 必须马上知道」,Bark 的参数最贴 iOS 原生,代价是它只伺候苹果设备。
你们那边服务器出问题是靠什么通知到人的?还是跟我以前一样,第二天翻邮件才发现?