告别自建服务器:用Cloudflare Workers零成本搭建Bark推送服务
1. 为什么我放弃了自建推送服务器,转向 Cloudflare 托管方案
做运维或者写过自动化脚本的人,大概率都经历过这样一个阶段:脚本跑在服务器上,任务成功失败自己完全不知道,直到某天登录机器一看,定时任务已经挂了一周。于是开始琢磨消息推送——邮件太慢、短信要钱、企业微信和钉钉虽然能用但配置繁琐,而且很多场景下你只是想给自己发一条通知,不想牵扯一整个组织架构。
Bark 这个项目就是在这种需求下进入视野的。它是一个轻量级的 iOS 消息推送工具,原理很简单:你部署一个服务端,手机装一个 App,服务端收到请求后通过苹果推送通道把消息送到手机上。整个链路干净利落,没有多余的东西。但问题也随之而来——服务端部署在哪里?用一台云主机跑一个只用来转发推送的服务,成本上不划算,维护上也是负担。一台最低配的云服务器一年也要几百块,而且还要考虑系统更新、证书续期、进程守护这些琐事。
Cloudflare Workers 的出现让这件事有了另一种解法。它提供免费的边缘计算额度,每天十万次请求,对于个人推送场景来说绰绰有余。更重要的是,你不需要管理任何服务器,不需要操心证书,不需要配置反向代理,代码推上去就能用。把 Bark 的服务端逻辑搬到 Cloudflare Workers 上,配合 KV 存储做设备令牌管理,整套方案零成本、零维护、全球可用。
这篇文章适合几类人看:一是有服务器或脚本告警需求但不想为此专门买机器的开发者;二是已经在用 Bark 但服务端跑在 VPS 上、想迁移到更省心方案的人;三是对 Cloudflare Workers 感兴趣、想找一个真实项目练手的同学。我会从原理讲到实操,把部署过程中容易踩的坑都摊开说清楚。
2. Bark 的工作机制与 Cloudflare Workers 的契合点
2.1 Bark 推送链路拆解
要理解为什么 Cloudflare Workers 适合跑 Bark,得先搞清楚 Bark 的推送流程。Bark 的整体架构分三段:客户端(你的脚本或服务器)、Bark 服务端、苹果推送服务(APNs)。
当你向 Bark 服务端发送一个 HTTP 请求时,请求里包含设备令牌(device token)、推送标题、推送内容、铃声等参数。服务端收到后,把这些信息组装成 APNs 要求的格式,再通过 HTTP/2 连接发送给苹果的推送网关。苹果再把消息投递到对应设备上,Bark App 收到后展示通知。
这里有一个关键点:Bark 服务端本身不存储消息内容,它只是一个转发器。设备令牌是 App 首次启动时向苹果注册获得的,然后用户手动或通过 App 内操作把这个令牌配置到服务端。服务端需要维护一个令牌列表,知道哪些设备可以接收推送。
传统的 Bark 服务端实现是用 Go 写的,跑在一台常驻服务器上,令牌存在本地文件或数据库里。这个架构没问题,但要求你有一台 7x24 小时在线的机器。
2.2 Workers 的运行模型为什么刚好够用
Cloudflare Workers 的运行模型和传统服务器有本质区别。它不是常驻进程,而是事件驱动的无状态函数。每次有请求进来,Workers 启动一个隔离环境执行你的代码,执行完就销毁。这意味着你没法在内存里保存状态,也没法维持长连接。
乍一看这似乎不适合做推送服务,但仔细想想 Bark 的需求:每次推送都是独立的 HTTP 请求,请求之间不需要共享内存状态,唯一需要持久化的就是设备令牌列表。而 Cloudflare 提供了 KV 存储,正好用来存令牌。至于 APNs 连接,Workers 支持发起 HTTPS 请求,而 APNs 的 HTTP/2 接口本质上就是 HTTPS 请求,所以完全可行。
另一个契合点是延迟。Workers 在全球有几百个边缘节点,你的脚本发请求时会被路由到最近的节点执行,然后从那里连苹果的推送网关。相比把服务端放在某个固定区域的 VPS 上,边缘执行的延迟反而更低。
2.3 免费额度算一笔账
Cloudflare Workers 免费版每天十万次请求,KV 存储免费版每天十万次读、一千次写、一千次删除。对于个人使用来说,你一天能发多少条推送?就算每个脚本每分钟报一次警,一天也就一千多条。设备令牌的读写更是低频操作,只在注册和更新时发生。所以免费额度不仅够用,而且绰绰有余。
对比一下自建方案:一台最低配 VPS 按年付大概两三百块,加上域名(如果用 HTTPS 的话)每年几十块,再加上你花在维护上的时间成本。Cloudflare 方案把这些全部省掉了,而且可用性由 Cloudflare 的基础设施保证,比你自己维护一台小机器靠谱得多。
3. 从零开始:Workers 项目搭建与核心代码实现
3.1 环境准备与项目初始化
开始之前你需要准备几样东西:一个 Cloudflare 账号(免费注册)、Node.js 环境(建议 18 以上)、以及一个 iOS 设备上安装好的 Bark App。Bark App 在 App Store 可以搜到,免费版就够用。
首先安装 Wrangler CLI,这是 Cloudflare 官方的 Workers 开发工具:
安装完成后登录你的 Cloudflare 账号:
浏览器会弹出一个授权页面,点击允许即可。登录成功后,创建一个新的 Workers 项目:
创建过程中会问你几个问题,模板选 "Hello World" 示例即可,语言选 JavaScript 或 TypeScript 都行。我建议用 TypeScript,类型提示能帮你少犯很多低级错误。
接下来创建 KV 命名空间,用来存储设备令牌:
命令执行后会输出一个 ID,把这个 ID 记下来,待会儿要写进配置文件。
3.2 配置文件的关键字段说明
打开项目根目录下的 wrangler.toml,这是 Workers 的核心配置文件。你需要把 KV 命名空间的绑定信息加进去:
这里有几个细节值得注意。compatibility_date 决定了 Workers 运行时使用哪个版本的 API 行为,建议设成比较近的日期,但不要超过当前日期。binding 的名字可以自定义,但代码里引用时要保持一致。
另外,如果你想让 Workers 绑定自定义域名,可以在 routes 字段里配置。不过对于 Bark 来说,Workers 默认提供的 *.workers.dev 域名已经够用了,而且自带 HTTPS,省去了证书配置的麻烦。
3.3 核心路由逻辑的代码实现
Bark 服务端的核心逻辑其实不复杂,主要处理三类请求:设备注册、消息推送、以及健康检查。下面是一个精简但可用的实现:
这段代码的逻辑很直白:用 URL 路径区分操作类型,设备注册时把 key-token 对写入 KV,推送时根据 key 查出 token 再发给苹果。实际部署时你还需要补充 APNs 的 JWT 签名逻辑,这部分涉及苹果开发者账号的密钥配置,下面单独说。
3.4 APNs 鉴权:最容易卡住的一步
向 APNs 发送推送需要鉴权,苹果支持两种方式:证书和 Token。证书方式需要生成 p12 文件,有有效期限制,到期要重新生成。Token 方式用私钥签名 JWT,长期有效,更适合自动化场景。
Token 方式需要三个东西:Team ID、Key ID、以及一个 .p8 私钥文件。这些都在苹果开发者后台获取。登录 developer.apple.com,进入 Certificates, Identifiers & Profiles 页面,在 Keys 部分创建一个新的 Key,勾选 Apple Push Notifications service,下载 .p8 文件。注意这个文件只能下载一次,丢了就得重新创建。
拿到这些信息后,在 Workers 里生成 JWT 并发送推送:
apns-topic 填你 Bark App 的 Bundle ID,这个值在 Bark 的官方文档里能查到。apns-push-type 对于普通通知填 alert 即可。apns-priority 设为 10 表示立即发送。
JWT 的生成需要用到苹果的私钥,Workers 环境里可以用 Web Crypto API 做 ES256 签名。这部分代码稍微长一些,核心思路是把 .p8 文件的内容作为密钥导入,然后用它签名一个包含 iss(Team ID)和 kid(Key ID)的 JWT header 和 payload。
注意:
.p8私钥是敏感信息,不要直接硬编码在代码里。建议用wrangler secret put命令把它存成环境变量,代码里通过env对象读取。
4. 部署上线与手机端联调
4.1 部署命令与首次验证
代码写完后,部署只需要一条命令:
Wrangler 会把你的代码打包上传到 Cloudflare 的边缘网络,几秒钟后就会输出一个 *.workers.dev 的 URL。在浏览器里访问这个 URL,如果看到 "Bark Worker is running",说明部署成功。
接下来测试设备注册。打开 Bark App,在设置里找到服务器地址配置项,填入你的 Workers URL。有些版本的 Bark 需要手动输入设备令牌,你可以在 App 的关于页面找到 token,然后通过浏览器访问:
如果返回 "Registered",说明令牌已经存进 KV 了。你可以登录 Cloudflare 控制台,在 Workers KV 页面确认数据是否写入。
4.2 推送测试与常见错误码
注册完成后,试着发一条推送:
如果手机收到通知,恭喜你,整条链路通了。如果没有收到,根据返回的状态码排查:
| 状态码 | 含义 | 排查方向 |
|---|---|---|
| 400 | 请求参数缺失 | 检查 URL 里的 key 和 token 是否完整 |
| 404 | 设备未注册 | 确认 KV 里是否有对应的 key |
| 403 | APNs 鉴权失败 | 检查 JWT 的 Team ID、Key ID、私钥是否正确 |
| 410 | 设备令牌失效 | 设备可能卸载了 App,需要重新注册 |
| 500 | 服务端内部错误 | 查看 Workers 日志,通常是代码逻辑问题 |
410 这个错误值得单独说一下。当用户卸载 Bark App 后,苹果会把这个设备令牌标记为失效,你再往这个令牌推送就会返回 410。这时候应该把 KV 里对应的记录删掉,避免后续继续无效推送。可以在代码里加一个判断,收到 410 时自动清理。
4.3 自定义域名与访问控制
Workers 默认的 *.workers.dev 域名在国内部分网络环境下可能访问不稳定,如果你有自己的域名,建议绑定上去。在 Cloudflare 控制台的 Workers 设置里添加 Custom Domain,输入你的域名,Cloudflare 会自动配置 DNS 和证书。
绑定域名后还有一个好处:你可以通过 Cloudflare 的 WAF 规则限制访问来源。比如只允许你自己的服务器 IP 调用推送接口,其他来源一律拒绝。虽然 Bark 的接口本身不涉及敏感数据,但多一层防护总没坏处。
配置方法是在 Cloudflare 控制台的 Security > WAF 里创建自定义规则,匹配你的 Workers 域名,然后设置 IP 白名单。这样即使别人知道了你的接口地址,也没法滥用。
5. 把告警接入实际场景:脚本、服务器与定时任务
5.1 Shell 脚本中的推送封装
部署好服务之后,真正让它产生价值的是接入你的实际业务。最常见的是在 Shell 脚本里加推送通知。我习惯封装一个函数放在 .bashrc 或公共脚本里:
然后在脚本的关键节点调用:
这样每次备份任务执行完,你都能在手机上收到结果。成功时心里有数,失败时第一时间知道。
5.2 服务器监控与定时任务集成
如果你用 cron 跑定时任务,可以把推送逻辑直接嵌进去。比如监控磁盘使用率:
把这个脚本加到 crontab 里每小时跑一次,就能在磁盘快满的时候提前收到通知。类似的还有内存监控、进程存活检测、证书到期提醒等等。
对于用 systemd 管理的服务,可以写一个简单的健康检查脚本,配合 timer 定期执行。如果服务挂了,脚本检测到后立即推送,比等到用户反馈再处理要主动得多。
5.3 与 CI/CD 流水线结合
如果你用 GitHub Actions 做持续集成,也可以在流水线里加推送步骤。比如构建失败时通知自己:
这样你不需要一直盯着 CI 页面,构建结果会直接推到手机上。对于个人项目来说,这个体验提升非常明显。
提示:在 CI 环境里调用推送接口时,注意不要把 Workers 域名和设备 key 硬编码在公开仓库里。用 GitHub Secrets 存储这些值,通过环境变量传入。
6. 踩过的坑与稳定性优化经验
6.1 KV 最终一致性带来的注册延迟
Cloudflare KV 是最终一致性存储,写入后在全球边缘节点同步需要时间,通常几十秒到几分钟不等。这意味着你刚注册完设备,立刻发推送可能会返回 404,因为请求落到的边缘节点还没拿到最新的 KV 数据。
我一开始遇到这个问题时以为是代码写错了,反复检查逻辑都没问题,后来才意识到是 KV 的同步延迟。解决办法有两个:一是注册后等一两分钟再测试;二是在代码里加一个 fallback,如果 KV 查不到,返回一个明确的提示而不是直接 404,方便区分是没注册还是同步没完成。
对于生产环境,如果你对一致性要求高,可以考虑用 Durable Objects 替代 KV,它提供强一致性。但 Durable Objects 的免费额度比 KV 少,个人使用的话 KV 的延迟完全可以接受。
6.2 APNs 连接超时的处理
Workers 里发 fetch 请求默认有超时限制,虽然 APNs 的响应通常很快,但偶尔也会遇到网络抖动导致超时。如果不处理,用户侧看到的就是推送失败,但实际上可能只是这一次请求超时了。
我的做法是在推送逻辑里加一次重试:
注意 410 错误不要重试,因为令牌已经失效了,重试多少次都没用。其他错误可以重试一到两次,大部分偶发问题都能通过重试解决。
6.3 免费额度的监控与告警
虽然十万次请求对个人来说很难用完,但如果你把接口暴露在公网上,有可能被扫描到并滥用。建议在 Cloudflare 控制台设置用量告警,当请求量接近阈值时发邮件通知。
另外,Workers 的日志功能可以帮你排查问题。在控制台的 Workers 页面点击你的项目,进入 Logs 标签页,可以实时看到请求日志和错误信息。调试阶段这个功能非常有用,能看到每次请求的路径、状态码、执行时间。
6.4 设备令牌管理的几个细节
实际使用中我发现几个关于令牌管理的问题值得注意。第一,同一个设备重新安装 App 后令牌会变,旧令牌就失效了。如果你用固定的 key 存储,重新注册会覆盖旧值,这没问题。但如果你用多个 key 对应同一设备,就需要手动清理。
第二,Bark App 支持多设备,每台设备的令牌不同。你可以用不同的 key 区分,比如 phone、ipad、watch,推送时指定对应的 key 就能发到特定设备。
第三,定期检查 KV 里的令牌是否还有效是个好习惯。可以写一个定时任务,遍历所有令牌发一条静默推送,收到 410 的就清理掉。不过这个操作会消耗请求额度,频率不用太高,一个月一次足够了。
7. 关于这套方案我的一些真实体会
这套方案我用了大半年,从最初的测试到后来接入各种脚本和监控,整体稳定性超出预期。Cloudflare 的边缘网络确实靠谱,大半年里没有遇到过服务不可用的情况,推送到达率也很高,基本是秒级送达。
有一点需要提醒:Bark 的推送依赖苹果的 APNs,所以如果你的手机网络环境对苹果推送服务不友好,可能会影响到达速度。这跟 Workers 无关,是 APNs 本身的问题。我在国内使用时偶尔会遇到延迟,但绝大多数情况下都是即时到达。
另外,如果你对推送内容有格式要求,Bark 支持 Markdown 渲染,可以在 body 里用简单的 Markdown 语法让通知更易读。比如用 **加粗** 突出关键信息,用 - 列要点。这个细节在告警场景下很实用,一眼就能看到重点。
最后说一个扩展思路:Workers 除了处理推送,还可以顺便做一些轻量的数据处理。比如你的脚本把原始数据发过来,Workers 做一层格式化再推送,这样脚本端就不用关心展示逻辑了。这种分工在实际项目里很常见,能让整体架构更清晰。