UptimeFlare:不用自己备服务器的网站监控与状态页
服务半夜挂了,往往要等到用户在群里发消息才知道。这类问题的标准解法是一台 7x24 的监控机:自己租服务器跑 Uptime Kuma,或者依赖 SaaS 监控的免费档。UptimeFlare 走了另一条路——探活任务由 Cloudflare Workers 的定时触发器每分钟在全球边缘节点上执行,状态页是构建后托管在 Cloudflare Pages 的一组静态文件加一份 D1 数据库读数,两者都落在 Cloudflare 免费额度内。整个部署不需要本地安装任何东西:从模板生成自己的仓库、填一个 API Token、编辑仓库根目录的 uptime.config.ts,GitHub Actions 会把监控 Worker、状态页和数据库一次性建好。
按 README 的说法,这套方案可以承载 50 个每分钟检查的监控目标,探测可来自 310 多个 Cloudflare 城市节点,并保留 90 天可用性历史;这些数字是仓库对免费额度下可达规模的声明,本文未实际压测。
GitHub 仓库信息
| 信息 | 内容 |
|---|---|
| 项目标题 | UptimeFlare |
| 项目描述 | 运行在 Cloudflare Workers 上的免费无服务器网站可用性监控与状态页,支持按地区发起探测 |
| GitHub 仓库 | lyc8503/UptimeFlare |
| 官网地址 | 未知(已检索但未找到可靠官网;官方文档托管在 GitHub Wiki,作者维护的在线演示见 uptimeflare.pages.dev,核对日 2026-09-23 可访问) |
| 主要开发语言 | TypeScript 93.27%、JavaScript 2.52%、Python 2.21% |
| 开源许可证 | Apache-2.0 |
| 最近代码更新 | 2026-06-01(GitHub pushed_at,核对日期:2026-09-23) |
一份 TypeScript 文件管住所有配置
UptimeFlare 没有管理后台,也没有数据库里的设置表。监控对象、状态页标题、通知渠道、维护窗口,全部写在仓库根目录的 uptime.config.ts 里,由构建流程打包进 Worker 和状态页。改配置的动作就是改代码:提交、推送、等流水线跑完。
monitors 数组是核心。HTTP 监控除了 URL,还能指定请求方法、headers、body、可接受的 expectedCodes(默认 2xx),以及 responseKeyword / responseForbiddenKeyword 两种响应内容断言——网关返回 200 但页面里写着 "database error" 的情况可以被判为故障。TCP 监控把 method 设为 TCP_PING、target 写成 host:port,用来盯数据库或 SSH 端口是否可连。状态页一侧,pageConfig 负责标题、头部链接和分组展示,passwordProtection 可以给整个页面加一层 HTTP Basic 认证,maintenances 数组声明的计划内维护会在页面上挂横幅,并在维护期间跳过对应的宕机通知。
仓库里同时提供 uptime.config.full.ts 作为全量参考:包括用 IIFE 生成每月循环维护窗口这类 TypeScript 才玩得动的写法,也提醒这种动态生成可能引入不确定输出,调试不了就慎用。
探针从哪里发出,由你指定
监控 worker 被 Cloudflare 的 cron 触发时,会在某个随机边缘数据中心执行;对绝大多数探活这无所谓,但当被监控的服务只对特定地区友好(比如只对内地图加速的站点),探针落在哪里就决定了结果是真实故障还是连通性误报。UptimeFlare 用一个 checkProxy 字段解决这件事,官方文档给出三种方案:
| 写法 | 探测执行者 | 适合场景 |
|---|---|---|
worker://weur | 部署在你账号内、通过 Durable Objects 固定在指定 Cloudflare 地区的远程检查器 | 选择官方列出的地区参数(如西欧 weur)即可,无需额外部署 |
globalping://<token>/?magic=CN | 第三方 Globalping 的全球探针网络 | 需要城市/ASN 级粒度或境内探针;标记为实验性,POST 监控和 checkProxyFallback 在该模式下不生效 |
https://proxy.example.com/ | 自建 Node.js 检查代理(仓库 proxy/ 目录),可跑在 VPS 或 Vercel 等平台 | 监控内网服务或 Cloudflare 覆盖不到的地区;代理端要用公网可达的域名地址(HTTP 也行),不能是裸 IP 或自签证书 |
早期的定区域方案 checkLocationWorkerRoute 因 Cloudflare 内部变更在 2025-04-13 被官方移除,读到旧教程里扫描地域 IP、配 Workers 路由的做法可以直接跳过。
状态变化之外还有响应延迟数据。源码显示 worker 用 p-limit 把并发检查数压到 5(注释写明 Cloudflare Workers 的上限是 6 个并发连接,取 5 保险)。每分钟的检查结果先并入一份压缩状态,再整体写回 D1 的那张两列 key/value 表:延迟时间戳定宽转十六进制串接、探测地点做游程编码(store.ts)。D1 的写入量直接对应免费额度消耗,deploy.tf 的 cron 注释因此指向了节流阀 kvWriteCooldownMinutes:默认没有状态变化时每 3 分钟才落一次盘,宕机与恢复则即时记录。
状态页:一份构建产物,两种消费方式
状态页是 Next.js 前端经 @cloudflare/next-on-pages 编译后的 Pages 部署,交互延迟图、事故历史页、维护横幅、深色模式跟随和中英德法繁中多语言界面都在这份静态产物里。页面上没有后端 API 进程:数据从 Pages 函数直接读同一块 D1 数据库。
对外的消费入口有三个。/api/data 返回实时 JSON(各 monitor 的当前状态、延迟、最后一次探测所在数据中心和错误信息),适合把状态接进自己的仪表盘;URL 追加 #monitor_id 可以把单个监控卡片以 iframe 嵌进别的网页;pages/api/badge.ts 则输出 Shields 风格的总体状态徽章。README 功能清单里的 CNAME 自定义域名,操作是在 Cloudflare 控制台对 Pages 项目(不是 Worker)Setup custom domain,官方 Wiki 有一页截图说明。
通知走统一的 webhook 配置:指定 url、payloadType(param / json / x-www-form-urlencoded)和 payload,正文里的 $MSG 占位符会被替换成人话的状态变更消息,Telegram Bot、企业微信机器人、Pushover 在通知文档里都有可直接照抄的示例。gracePeriod 控制抖动抑制——监控持续宕满 N 分钟的连续检查后才发通知,恢复消息只对已通知过的故障发送。早期的 Apprise 聚合方案仍可用,但官方已把通用 webhook 列为推荐路径。
十分钟部署到 Cloudflare
以下流程按 官方 Quickstart 整理,本文未实际执行部署;前置条件是两个账号——Cloudflare 免费账号(不要求信用卡)和 GitHub 账号。
- 在 Cloudflare 控制台 API Tokens 页面 用
Edit Cloudflare Workers模板创建 Token,并手动补上 D1 Edit 权限——存储层迁移到 D1 之后这一步不能省,缺权限时流水线会在建库脚本处以认证错误直接失败。 - 从没碰过 Workers 的新账号,先去控制台打开一次 Workers 落地页。这一步会静默开通部署所必需的 workers.dev 子域,跳过则初始化阶段会失败。
- 对
lyc8503/UptimeFlare点击Use this template建自己的仓库。配置里可能要填 Bearer Token 之类的凭据,介意可见性的建私有仓库。 - 在自己仓库的 Settings → Secrets and variables → Actions 里新建 Secret,名字为
CLOUDFLARE_API_TOKEN,值为第一步的 Token。账号 ID 可以不填,流水线会自动查询。 - 编辑仓库根目录的
uptime.config.ts,把示例 monitor 的target换成自己的站点,id保持不变历史数据才能延续。 - 推送后到 Actions 观察
Deploy to Cloudflare工作流。配置有语法错误时流水线会红在构建阶段,改对再推即可。
成功的信号很直观:Cloudflare 控制台的 Workers & Pages 里出现 uptimeflare(Pages 项目)和 uptimeflare_worker(Worker)两个资源,打开 Pages 项目的默认域名就能看到自己的状态页,访问 /api/data 能返回带 monitor 状态的 JSON。此后改配置只需要重复第五步,流水线会自动对齐所有资源。
部署下去的到底是哪些资源
状态页与探针共享一块 D1 数据库:deploy.tf 声明了全部四类云资源——D1 数据库 uptimeflare_d1(开启自动读复制)、绑定 UPTIMEFLARE_D1 的 Worker uptimeflare_worker、每分钟整点触发的 cron * * * * *、生产分支为 main 的 Pages 项目。Worker 还绑定了名为 REMOTE_CHECKER_DO 的 Durable Object,worker:// 区域探测正是由该对象在指定地区执行;流水线会先探测账号里是否已有这个命名空间,只在缺失时启用迁移。
部署工作流固定了版本口径:Terraform 1.6.4、Cloudflare provider v5(~> 5)、Node.js 22.x,运行时 compatibility_date 为 2025-04-02 并开启 nodejs_compat。数据库表由 deploy/init_d1.py 建(一张 key/value 表),老用户的历史数据由 deploy/migrate_kv.py 自动搬运。凭据面很小:整条流水线只需要 GitHub 里那一个 CLOUDFLARE_API_TOKEN Secret。
| 变更 | 日期 | 对使用方的影响 |
|---|---|---|
| 存储从 KV 迁到 D1 | 2026-01-03 | API Token 需补 D1 Edit 权限;历史数据自动同步,旧 KV 数据被清除,升级后延迟数据完整回填可能需要约 12 小时 |
| 通知改为通用 webhook | 2025-10-15 | 沿用 Apprise 的配置需要按新格式改写 |
| 维护窗口功能引入 | 2025-05-01 | 旧配置文件需按 master 模板微调 |
移除 checkLocationWorkerRoute | 2025-04-13 | 旧的定区域配置失效,改用 checkProxy |
升级走仓库自带的 Upstream Sync 工作流:在自己的仓库里手动触发,代码会自动从上游合并并重新部署;当工作流文件本身有更新时,需要临时提供一个带 Workflows 与 Contents 权限的 GitHub Token。UptimeFlare 上游仓库没有发布过任何 Git tag 或 Release,版本粒度就是 main 分支头,上游同步文档按日期记录破坏性变更。回滚没有官方流程,可行的做法是把自有仓库 checkout 到旧提交再触发部署,历史数据仍在 D1 中不至于丢失,但新格式写回旧版本读取的行为没有文档背书。
值得先知道的限制
- 一切绑在 Cloudflare 免费额度上。GitHub issue 里有用户报告使用区域代理时撞上 Durable Objects 免费层的时长上限(#109),也有讨论要求聚合探测请求以降低消耗(#46)。监控数量少时这层风险很低,把上百个目标搬到 UptimeFlare 上之前值得先读这两条。
- 凭据与配置同仓。监控 headers 里的 Bearer Token、通知 URL 中的机器人密钥都明文写在
uptime.config.ts,仓库必须按私有的姿态管理。2026-03-04 修复的安全公告(CVE-2026-29779)涉及41257c6(2025-09-21)至修复日之间的版本会把配置暴露给客户端,仍在使用该区间部署的用户应尽快升级。 - 部署链路是 GitOps 单向的:控制台里手改资源会被下一次
terraform apply对齐回去,改配置永远回到uptime.config.ts。 - 本地部署方向已有官方 Dockerfile 和 entrypoint(用 wrangler 本地跑 Worker 与 Pages、cron 打
__scheduled端点),README 也勾选了该项,但官方文档明确标注 docs WIP,issue #157 仍在讨论中。生产采用建议以 Cloudflare 路径为准。 - 功能上,ICMP ping 和 SSL 证书检查在 README 的待办清单里处于未完成状态;需要这两项的读者要考虑 Uptime Kuma(自备服务器、功能面更全)或商业监控服务。
工作原理:配置的两次生命
回到第一次部署成功后读者最好奇的问题:改一行配置,云端发生了什么。
正在准备渲染...
查看源码
flowchart LR
A["push uptime.config.ts"] --> B["GitHub Actions<br/>构建 worker 与 Pages 产物"]
B --> C["Terraform apply<br/>对齐 D1 / Worker / cron / Pages"]
B --> D["wrangler pages deploy<br/>上传状态页静态产物"]
E["Cloudflare cron 每分钟"] --> F["uptimeflare_worker<br/>scheduled: 并行探活"]
F -- "结果写入" --> G[("D1 uptimeflare_d1")]
F -. "checkProxy=worker://region" .-> H["Durable Object<br/>RemoteChecker 异地执行"]
D -- "页面函数读取" --> G
G --> I["状态页 / /api/data"]配置在这条链上被消费了两次。部署期,Actions 把 uptime.config.ts 连同源码构建成 worker bundle 和 Pages 静态产物,Terraform 只负责资源形状;运行期,worker 的 scheduled 入口直接 import 这份配置数组逐个发起检查——这就是为什么没有管理界面:改配置等价于重新发布一份编译了配置的代码。状态页一侧同理,pages/index.tsx 在服务端渲染时用 getFromStore 读 D1,pages/api/data.ts 则把同一份压缩状态整理成实时 JSON。
理解了这一点,设计选择就各归其位:id 不变历史才延续,因为监控记录按 monitor id 挂在那份压缩状态里;前面看到的十六进制压缩与写入节流,则同出于免费额度这一条预算逻辑。
下一步
- 给最想盯的那个接口配上通知:从 Setup notification 挑 Telegram 或企业微信示例,加上
gracePeriod: 2,亲手制造一次超时(指向一个不存在的端口)验证通知到达。 - 试用区域探测:给某个 monitor 加
checkProxy: 'worker://weur',观察状态页延迟图里探测节点标识的变化。 - 想读源码的话,
worker/src/monitor.ts里 HTTP/TCP/代理三条检查分支和worker/src/store.ts的压缩存储是全项目信息密度最高的两个文件;本地开发按 How to develop 的建议改码推送、交给 Actions 重新部署,嫌流水线慢可以在本机跑工作流里的构建与wrangler deploy;仓库根 package.json 还有一个preview脚本,用wrangler pages dev在本地预览状态页。
参考资料
- UptimeFlare 仓库(固定提交 a5670e5,2026-09-23 核对)
- Quickstart · Configuration · Check proxy setup · Setup notification · Synchronize updates from upstream
- deploy.tf · deploy.yml · uptime.config.ts · worker/src/index.ts · worker/src/store.ts
- 安全公告 GHSA-36q9-v7p3-vj6v
- 在线演示(作者部署的实例)