告别自建服务器:用Cloudflare Workers零成本搭建Bark推送服务

BarkCloudflare Workers消息推送
于 2026-10-01 02:33:53 修改
·本内容遵循CC 4.0 BY-SA版权协议

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 开发工具:

BASH
npm install -g wrangler

安装完成后登录你的 Cloudflare 账号:

BASH
wrangler login

浏览器会弹出一个授权页面,点击允许即可。登录成功后,创建一个新的 Workers 项目:

BASH
npm create cloudflare@latest bark-worker
cd bark-worker

创建过程中会问你几个问题,模板选 "Hello World" 示例即可,语言选 JavaScript 或 TypeScript 都行。我建议用 TypeScript,类型提示能帮你少犯很多低级错误。

接下来创建 KV 命名空间,用来存储设备令牌:

BASH
wrangler kv:namespace create BARK_KV

命令执行后会输出一个 ID,把这个 ID 记下来,待会儿要写进配置文件。

3.2 配置文件的关键字段说明

打开项目根目录下的 wrangler.toml,这是 Workers 的核心配置文件。你需要把 KV 命名空间的绑定信息加进去:

TOML
name = "bark-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"
 
kv_namespaces = [
{ binding = "BARK_KV", id = "你刚才获得的ID" }
]

这里有几个细节值得注意。compatibility_date 决定了 Workers 运行时使用哪个版本的 API 行为,建议设成比较近的日期,但不要超过当前日期。binding 的名字可以自定义,但代码里引用时要保持一致。

另外,如果你想让 Workers 绑定自定义域名,可以在 routes 字段里配置。不过对于 Bark 来说,Workers 默认提供的 *.workers.dev 域名已经够用了,而且自带 HTTPS,省去了证书配置的麻烦。

3.3 核心路由逻辑的代码实现

Bark 服务端的核心逻辑其实不复杂,主要处理三类请求:设备注册、消息推送、以及健康检查。下面是一个精简但可用的实现:

TYPESCRIPT
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const path = url.pathname;
 
// 健康检查
if (path === "/" || path === "/ping") {
return new Response("Bark Worker is running", { status: 200 });
}
 
// 设备注册
if (path === "/register") {
const deviceKey = url.searchParams.get("key");
const deviceToken = url.searchParams.get("token");
if (!deviceKey || !deviceToken) {
return new Response("Missing key or token", { status: 400 });
}
await env.BARK_KV.put(deviceKey, deviceToken);
return new Response("Registered", { status: 200 });
}
 
// 消息推送
if (path.startsWith("/push")) {
const deviceKey = path.split("/")[2];
if (!deviceKey) {
return new Response("Missing device key", { status: 400 });
}
const deviceToken = await env.BARK_KV.get(deviceKey);
if (!deviceToken) {
return new Response("Device not found", { status: 404 });
}
 
const title = url.searchParams.get("title") || "Notification";
const body = url.searchParams.get("body") || "";
const sound = url.searchParams.get("sound") || "default";
 
const result = await sendToAPNs(deviceToken, { title, body, sound });
return new Response(JSON.stringify(result), {
status: result.success ? 200 : 500,
headers: { "Content-Type": "application/json" },
});
}
 
return new Response("Not Found", { status: 404 });
},
};

这段代码的逻辑很直白:用 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 并发送推送:

TYPESCRIPT
async function sendToAPNs(token: string, payload: any) {
const jwt = await generateJWT();
const apnsUrl = `https://api.push.apple.com/3/device/${token}`;
 
const response = await fetch(apnsUrl, {
method: "POST",
headers: {
"authorization": `bearer ${jwt}`,
"apns-topic": "your.bundle.id",
"apns-push-type": "alert",
"apns-priority": "10",
},
body: JSON.stringify({
aps: {
alert: { title: payload.title, body: payload.body },
sound: payload.sound,
},
}),
});
 
return { success: response.ok, status: response.status };
}

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 部署命令与首次验证

代码写完后,部署只需要一条命令:

BASH
wrangler deploy

Wrangler 会把你的代码打包上传到 Cloudflare 的边缘网络,几秒钟后就会输出一个 *.workers.dev 的 URL。在浏览器里访问这个 URL,如果看到 "Bark Worker is running",说明部署成功。

接下来测试设备注册。打开 Bark App,在设置里找到服务器地址配置项,填入你的 Workers URL。有些版本的 Bark 需要手动输入设备令牌,你可以在 App 的关于页面找到 token,然后通过浏览器访问:

TEXT
https://你的workers域名/register?key=myphone&token=你的设备令牌

如果返回 "Registered",说明令牌已经存进 KV 了。你可以登录 Cloudflare 控制台,在 Workers KV 页面确认数据是否写入。

4.2 推送测试与常见错误码

注册完成后,试着发一条推送:

TEXT
https://你的workers域名/push/myphone?title=测试&body=这是一条测试消息

如果手机收到通知,恭喜你,整条链路通了。如果没有收到,根据返回的状态码排查:

状态码 含义 排查方向
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 或公共脚本里:

BASH
bark_push() {
local title="$1"
local body="$2"
curl -s "https://你的workers域名/push/myphone?title=${title}&body=${body}" > /dev/null
}

然后在脚本的关键节点调用:

BASH
# !/bin/bash
if backup_database; then
bark_push "备份成功" "数据库备份已完成,大小 $(du -h backup.sql | cut -f1)"
else
bark_push "备份失败" "数据库备份异常,请立即检查"
fi

这样每次备份任务执行完,你都能在手机上收到结果。成功时心里有数,失败时第一时间知道。

5.2 服务器监控与定时任务集成

如果你用 cron 跑定时任务,可以把推送逻辑直接嵌进去。比如监控磁盘使用率:

BASH
# !/bin/bash
THRESHOLD=85
USAGE=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
bark_push "磁盘告警" "根分区使用率已达 ${USAGE}%,请及时清理"
fi

把这个脚本加到 crontab 里每小时跑一次,就能在磁盘快满的时候提前收到通知。类似的还有内存监控、进程存活检测、证书到期提醒等等。

对于用 systemd 管理的服务,可以写一个简单的健康检查脚本,配合 timer 定期执行。如果服务挂了,脚本检测到后立即推送,比等到用户反馈再处理要主动得多。

5.3 与 CI/CD 流水线结合

如果你用 GitHub Actions 做持续集成,也可以在流水线里加推送步骤。比如构建失败时通知自己:

YAML
- name: Notify on failure
if: failure()
run: |
curl -s "https://你的workers域名/push/myphone?title=构建失败&body=仓库 ${{ github.repository }} 的构建任务失败"

这样你不需要一直盯着 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 的响应通常很快,但偶尔也会遇到网络抖动导致超时。如果不处理,用户侧看到的就是推送失败,但实际上可能只是这一次请求超时了。

我的做法是在推送逻辑里加一次重试:

TYPESCRIPT
async function sendWithRetry(token: string, payload: any, retries = 2) {
for (let i = 0; i <= retries; i++) {
try {
const result = await sendToAPNs(token, payload);
if (result.success) return result;
if (result.status === 410) return result; // 令牌失效不重试
} catch (e) {
if (i === retries) throw e;
}
}
}

注意 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 做一层格式化再推送,这样脚本端就不用关心展示逻辑了。这种分工在实际项目里很常见,能让整体架构更清晰。

免费玩转Cloudflare-05:CF部署「智能挪车码」,扫码一键通知车主秒回
本文介绍如何利用Cloudflare Workers和KV存储零成本部署隐私保护型智能挪车系统。方案支持扫码留言、Bark/企业微信等推送通知、双向实时定位共享,全程不暴露手机号。依托Cloudflare边缘网络实现全球低延迟、Serverless免费额度内运行,并提供5步部署流程及避坑指南。
星哥玩云
604
Bark 推送隐私安全指南:链路泄露风险、自部署与端到端加密、开源可验证构建
本文深入剖析Bark推送链路中的两大隐私风险点:发送端与服务端间的明文传输及日志留存、App二进制是否真实源自开源代码。提出三项关键技术方案:自部署HTTPS后端杜绝中间窥探;AES端到端加密确保仅终端可解密;利用GitHub Run Id实现构建溯源验证,保障二进制可复现性与完整性。所有方案均基于开源代码与可验证流程,聚焦移动端推送场景下的信息安全实践。
葛微娥Ross
481
告别官方服务器:用Bark+Cloudflare Tunnel打造完全私有的iOS消息推送链路
宁静致远敏
基于 Cloudflare Workers 的智能挪车通知系统源代码+使用说明,扫码即可通知车主,保护双方隐私,支持实时位置共享和多推送服务
不暴露电话号码 - 通过推送通知联系,保护隐私双向位置共享 - 车主可确认请求者确实在车旁无位置延迟 30 秒 - 降低恶意骚扰的动力免费部署 - Cloudflare Worker
程序员柳
9
inkrss:从任何地方订阅 RSS 提要,从任何地方接收通知
INK RSS 管理订阅,接收通知 · 示例群组 · 介绍INK RSS 提供及时且多样的 rss 通知服务,借助现有的接口你可以在任意位置订阅,并
王萌昊
15