基于 UptimeRobot 的中文状态页。项目已合并 /Users/Me/GitHub/status 的 Vue UI,前端展示以新版 UI 为主,后端继续使用当前项目的 Koa 服务负责动态拉取、整理和缓存监控数据。
- Vue + Vite 前端,展示状态分组、响应时间图、90 天可用率和宕机日志。
- 新版 UI 已移除侧栏和个人资料卡,并新增页脚。
- UptimeRobot API key 只保存在后端或平台环境变量中,不暴露给浏览器。
- Koa 常驻部署会通过 cron 预取刷新缓存。
- Vercel 和 Cloudflare Pages 通过函数动态提供
/api/status,不是纯静态页面。 - 兼容旧 Pug 页面,新版前端通过
/api/status获取状态数据,通过/api/info获取运行时站点配置。
.
├── api/index.js # Vercel Serverless 入口
├── config/ # Koa 配置和环境变量映射
├── functions/[[path]].js # Cloudflare Pages Function
├── frontend/ # Vue/Vite 前端
├── src/ # Koa 后端、UptimeRobot 服务、旧 Pug 页面
└── vercel.json # Vercel 部署配置
- Node.js >= 20.13.1 推荐。旧后端可运行在 Node.js >= 16,但前端依赖要求较新的 Node。
- Yarn Classic 1.22.x 用于根项目依赖。
- pnpm 8.15.8 用于前端依赖,构建脚本会通过
npx pnpm@8.15.8自动调用。 - UptimeRobot Read-Only API key。
yarn install
npm run build
node build/bootstrap默认监听端口来自 config/default.yml 的 app.port,默认是 3000。构建后 Koa 会优先托管 frontend/dist,如果前端产物不存在,则回退到旧 Pug 页面。
只开发前端时可单独运行:
cd frontend
npx pnpm@8.15.8 install --frozen-lockfile
npx pnpm@8.15.8 run dev前端开发环境的 API 地址来自 frontend/.env.development,默认请求 http://localhost:3000,因此需要同时启动后端。
| 变量 | 必填 | 说明 |
|---|---|---|
UPTIME_ROBOT_API |
是 | UptimeRobot API key |
UPTIME_ROBOT_NAME_PATTERN |
否 | 旧命名格式兼容解析规则;不设置时默认使用新版 UI 的 ${类别} / ${分组} |
WEBSITE_TITLE |
否 | 页面标题,默认 服务状态 |
WEBSITE_HOME_LABEL |
否 | 页头主页链接文字,默认 主页 |
WEBSITE_HOME_URL |
否 | 页头主页链接地址,默认 / |
WEBSITE_GITHUB_URL |
否 | 页头 GitHub 图标链接,默认 https://github.com/xOS |
WEBSITE_FOOTER_TITLE |
否 | 页脚标题;不设置时使用 WEBSITE_TITLE |
WEBSITE_FOOTER_DESCRIPTION |
否 | 页脚描述,默认 由 UptimeRobot 数据驱动,自动缓存并动态更新。 |
WEBSITE_FOOTER_OWNER |
否 | 页脚版权归属者;不设置时回退到 WEBSITE_COPYRIGHT |
WEBSITE_FOOTER_OWNER_URL |
否 | 页脚版权归属者链接,默认 https://www.nange.cn |
WEBSITE_COPYRIGHT |
否 | 兼容旧接口的版权字段,也会作为页脚版权归属者兜底 |
TIME_ZONE |
否 | 状态页日期范围和日志展示时区,使用 IANA 时区名,默认 Asia/Shanghai;也兼容 TZ |
CACHE_TTL_MS |
否 | 快照新鲜时间,超过后后台刷新,默认 60000 |
CACHE_STALE_TTL_MS |
否 | 快照可继续返回的时间,默认 0 表示不主动过期 |
CACHE_DISK |
否 | 是否启用磁盘缓存,设为 false 可关闭 |
CACHE_DISK_TTL_MS |
否 | 磁盘缓存有效期,默认跟随 CACHE_STALE_TTL_MS |
CACHE_DIR |
否 | 磁盘缓存目录,默认 .cache |
CACHE_REFRESH_TOKEN |
否 | 手动预热 /api/refresh 的访问令牌;也兼容 CRON_SECRET / REFRESH_TOKEN |
STATUS_PAGE_MAX_DAYS |
否 | /api/status?days= 最大允许天数,默认 90,用于避免异常大查询拖慢接口 |
UPTIME_ROBOT_TIMEOUT_MS |
否 | 后端单次请求 UptimeRobot 的超时时间,默认 30000 |
UPTIME_ROBOT_PAGE_SIZE |
否 | 后端分页拉取 UptimeRobot 监控的每页数量,默认 25,最大 50 |
UPTIME_ROBOT_REFRESH_BUDGET_MS |
否 | Cloudflare Pages 单次后台刷新最多执行时间,默认 18000,未完成会保存进度等待下次继续 |
UPTIME_ROBOT_REFRESH_RUNNING_TIMEOUT_MS |
否 | Cloudflare Pages 刷新状态最长可保持 running 的时间,默认 600000 |
UPTIME_ROBOT_REFRESH_CONTINUE_INTERVAL_MS |
否 | /api/status 触发后台续跑的最小间隔,默认 15000 |
UPTIME_ROBOT_RESPONSE_TIMES_HOURS |
否 | 响应时间曲线窗口,默认最近 24 小时,最大 168 小时 |
UPTIME_ROBOT_RESPONSE_TIMES_AVERAGE |
否 | 响应时间曲线聚合粒度,单位分钟,默认 30;设为 0 表示不聚合 |
UPTIME_ROBOT_RESPONSE_TIMES_LIMIT |
否 | 每个节点响应时间采样点数量;默认按窗口和聚合粒度自动计算 |
VITE_API_TIMEOUT_MS |
否 | 浏览器端 API 请求超时时间,默认 15000 |
PORT |
否 | Koa 监听端口 |
LOG_LEVEL |
否 | 日志级别 |
CRON_TIME |
否 | Koa cron 刷新周期 |
配置加载顺序为:
config/default.yml < config/${NODE_ENV}.yml < 环境变量
新版前端使用的数据接口。它只读取后端已经生成好的完整状态快照,不会在用户请求链路中实时请求 UptimeRobot。默认返回最近 90 天数据,可通过查询参数覆盖:
GET /api/status?days=90返回内容包含:
monitors:按分组整理后的节点状态。logs:宕机日志,按时间倒序。- 每个节点的
daily、response_times、total、average和status。
如果后端还没有任何完整快照,接口返回 202,并带上 meta.warming: true。此时需要等待定时任务或手动调用 /api/refresh 生成完整快照。
预热状态快照接口,用于外部 cron 或平台定时任务提前刷新后端缓存。手动或外部定时调用需要配置 CACHE_REFRESH_TOKEN,并通过 Authorization: Bearer <token> 或 ?token=<token> 调用;Vercel Cron 会通过平台 cron 请求头自动放行。
GET /api/refresh?days=90&token=your-token该接口默认立即返回 202 Accepted,刷新任务在后台执行,适合 UptimeRobot、Vercel Cron、Cloudflare Pages、GitHub Actions 等定时器调用。刷新过程中后端会按页拉取 UptimeRobot 监控,避免一次性大响应导致超时。Cloudflare Pages 会把进度写入 KV,单次执行未完成时,下次 /api/refresh 或页面轮询 /api/status 会继续处理剩余分页。
如果需要在本地或常驻 Koa 服务里同步等待刷新结果,可加 wait=1。Cloudflare Pages 不建议使用同步等待,监控数量多时应直接调用默认异步接口,稍后再访问 /api/status 确认快照是否生成。同步模式只返回刷新摘要,不返回完整状态数据:
GET /api/refresh?wait=1&token=your-token如果 Cloudflare Pages 的刷新状态长时间卡住,可用 force=1 丢弃旧进度并重新开始:
GET /api/refresh?force=1&token=your-token查看最近一次快照刷新状态,用于排查 Cloudflare Pages 后台刷新失败、KV 未绑定或 UptimeRobot API 配置错误。调用需要同一个刷新令牌:
GET /api/refresh-status?days=90&token=your-token返回中的 diagnostics.kvBound 应为 true,diagnostics.hasUptimeRobotApiKey 应为 true。Cloudflare KV 中会先写入 refresh:90 记录刷新状态;批处理未完成时还会暂存 refresh-data:90;只有完整快照成功生成后,才会写入 status:90。如果调用 /api/refresh 后 KV 仍完全为空,优先检查 Pages 项目的 KV 绑定是否在生产环境生效,并确认已经重新部署。
新版 UI 使用的运行时站点配置接口,同时保留旧字段 name、avatar、desc 和 rtl 以兼容旧前端。
{
"name": "服务状态",
"avatar": "",
"desc": "楠格",
"rtl": false,
"site": {
"title": "服务状态",
"home": {
"label": "主页",
"href": "/"
},
"github": {
"href": "https://github.com/xOS"
},
"footer": {
"title": "服务状态",
"description": "由 UptimeRobot 数据驱动,自动缓存并动态更新。",
"owner": "楠格",
"ownerUrl": "https://www.nange.cn",
"projectUrl": "https://github.com/xOS/StatusPage"
}
}
}页脚年份不是写死值,也不是构建时生成;前端会在浏览器运行时通过当前日期自动显示当年年份。
默认推荐直接在 UptimeRobot 监控名称中使用新版 UI 选项:
监控站${国家:us}${标签:info|Cloudflare}${类别:应用}
常用选项:
${类别:应用}或${分组:应用}:指定前端展示分组。${国家:us}:显示国家旗帜,值使用 flag-icons 的国家代码。${标签:info|Cloudflare,success|正常}:显示标签,格式是类型|文本,多个标签用英文逗号分隔。
如果不设置 ${类别} 或 ${分组},节点会进入 未分类 分组。
需要兼容旧项目命名时,再设置 UPTIME_ROBOT_NAME_PATTERN,例如:
%group/%index/%name
对应节点名称:
境内节点/000/北京
境内节点/001/上海
境外节点/100/洛杉矶
境外节点/101/香港
当同时存在 ${类别} / ${分组} 和旧命名解析结果时,新版 UI 优先使用 ${类别} / ${分组}。
项目已内置 Vercel 配置:
- 配置文件:
vercel.json - 构建命令:
npm run build - 输出目录:
frontend/dist - 函数入口:
api/index.js
至少配置:
UPTIME_ROBOT_API=你的 UptimeRobot API Key
WEBSITE_TITLE=服务状态
WEBSITE_HOME_URL=https://example.com
WEBSITE_GITHUB_URL=https://github.com/xOS
WEBSITE_FOOTER_OWNER=楠格Vercel 会托管 frontend/dist,并通过 Serverless Function 动态提供 /api/status。函数环境没有常驻 cron,数据会在函数实例内按请求缓存,默认 60 秒。
项目已在 vercel.json 配置 Vercel Cron,每天请求一次 /api/refresh 来预热状态快照。Vercel Hobby 计划只允许 daily cron;如果需要 5 分钟级别刷新,可用 UptimeRobot、GitHub Actions 或其他外部定时器请求 /api/refresh。
Cloudflare Pages 建议在控制台配置项目,不提交 wrangler.toml。这样 KV 绑定、环境变量和 Secret 都由 Cloudflare 控制台管理,不会把 KV namespace ID 写进仓库。
- 构建命令:
npm run build:cloudflare - 输出目录:
frontend/dist - 动态入口:
functions/[[path]].js
至少配置:
YARN_VERSION=1.22.22
UPTIME_ROBOT_API=你的 UptimeRobot API Key
TIME_ZONE=Asia/Shanghai
WEBSITE_TITLE=服务状态
WEBSITE_HOME_URL=https://example.com
WEBSITE_GITHUB_URL=https://github.com/xOS
WEBSITE_FOOTER_OWNER=楠格YARN_VERSION=1.22.22 用于让 Cloudflare Pages 使用 Yarn Classic 安装根项目依赖。Cloudflare Pages v3 构建镜像默认使用 Yarn 4,直接安装本项目的 Yarn 1 锁文件会尝试迁移锁文件并导致构建失败。
Cloudflare Pages 会托管 frontend/dist,并通过 Pages Function 动态提供 /api/status。项目不再使用从旧前端带来的 Worker/KV/backup 接口。
为了让 Cloudflare Pages 在换浏览器、换边缘实例时也能秒回,建议创建 Workers KV namespace,并在 Pages Functions 中绑定变量名 STATUS_CACHE。functions/[[path]].js 会优先读取 KV 中最后一次成功生成的快照;如果没有 KV,会退回到当前边缘实例内存和 Cache API。
KV namespace 的名称可以自定义,例如 status-page-cache。真正必须固定的是 Pages Functions 的绑定变量名:
Variable name: STATUS_CACHE
KV namespace: status-page-cache
KV 里的键值不需要手动创建。首次成功调用 /api/refresh 后,后端会自动写入类似 status:90 的键;如果你请求了其他天数,例如 /api/status?days=30,对应快照键就是 status:30。
配置步骤:
- 打开
Workers & Pages->KV,创建 namespace,例如status-page-cache。 - 进入 Pages 项目:
Settings->Bindings->Add->KV namespace。 Variable name填STATUS_CACHE,KV namespace选择刚创建的 namespace。- 保存后重新部署 Cloudflare Pages。
- 部署完成后调用一次
/api/refresh?token=your-token,接口返回202后等待几十秒,再访问/api/refresh-status?token=your-token和/api/status;刷新成功后 KV 会自动写入status:90。
Cloudflare Pages 没有本项目 Koa 进程那样的常驻 cron。需要提前刷新时,可用 Cloudflare Worker Cron、UptimeRobot、GitHub Actions 或其他外部定时器请求:
GET https://你的域名/api/refresh?token=your-token为了避免 UptimeRobot 慢请求阻塞页面,/api/status 完全不再拉取 UptimeRobot,只返回最后一次成功生成的完整快照。完整快照由 Koa cron、Vercel Cron、Cloudflare 外部定时器或手动 /api/refresh 生成。只要后端曾成功拿到过一次数据,之后刷新页面、换浏览器或缓存超过 CACHE_TTL_MS 都会先返回这份完整快照。Koa 常驻部署还会把新版状态数据写入磁盘缓存,进程重启后可先返回上次缓存。新版前端也会保存最近一次成功加载的完整状态快照,网络超时或后端冷启动时可以先显示旧数据。监控数量很多时可降低 UPTIME_ROBOT_RESPONSE_TIMES_LIMIT、设置 STATUS_PAGE_MAX_DAYS 或缩短前端请求的 days 参数。
wget https://raw.githubusercontent.com/XOS/StatusPage/master/docker-compose.yml
docker-compose up -d需要自定义配置时,将 config/ 挂载到容器中,并修改 config/default.yml 或通过环境变量覆盖。
npm test # 后端测试
npm run build:frontend # 仅构建 Vue 前端
npm run build # 构建前端、后端和旧静态资源
npm run clean # 清理 build/