











UptimeFlare 是一个基于 Cloudflare Workers 的 Serverless 网站状态监控服务,完全免费且易于部署。本文将详细介绍其技术架构、核心功能实现以及开发部署流程。项目 fork 自 lyc8503/UptimeFlare,在原有基础上进行了界面美化和功能优化。在线演示:status.weizwz.com,项目地址:weizwz/UptimeFlare。预览图如下:



监控流程
Cron Trigger → Worker 检查 → 更新 D1 → 记录状态/故障页面渲染流程
用户访问 → Pages 请求 → 读取 D1 → SSR 渲染 → 返回 HTML实时更新流程
Worker 定时检查 → 状态变化 → 更新数据库 → 前端轮询/刷新UptimeFlare/
├── components/ # React 组件
│ ├── MonitorCard.tsx # 监控卡片
│ ├── MonitorDetail.tsx # 监控详情
│ ├── DetailBar.tsx # 数据可视化
│ ├── MaintenanceAlert.tsx # 维护通知
│ ├── IncidentsDrawer.tsx # 历史故障侧边栏
│ └── OverallStatus.tsx # 整体状态
│
├── pages/ # Next.js 页面
│ ├── index.tsx # 主页
│ ├── incidents.tsx # 历史故障页面
│ └── api/ # API 路由
│ └── data.ts # 数据接口
│
├── worker/ # Cloudflare Worker
│ └── src/
│ ├── index.ts # Worker 入口
│ ├── monitor.ts # 监控逻辑
│ ├── store.ts # 数据存储
│ └── util.ts # 工具函数
│
├── locales/ # 国际化
│ ├── en/ # 英文
│ ├── zh-CN/ # 简体中文
│ └── zh-TW/ # 繁体中文
│
├── types/ # TypeScript 类型
│ └── config.ts # 配置类型定义
│
├── uptime.config.ts # 监控配置
├── wrangler.toml # Worker 配置
├── next.config.js # Next.js 配置
└── package.json # 依赖管理重要
uptime.config.ts 里的监控服务 monitors 建议首次就配置好,尤其是里面的 id,多次修改会造成脏数据。所有配置项都可以参考 uptime.config.full.ts 文件
uptime.config.ts
typescript
const pageConfig: PageConfig = {
// 标题
title: '服务状态 - weizwz',
// 分组,根据 monitors 里的服务 id
group: {
基础服务: ['weiwz', 'blog', 'picture'],
实用工具: ['nav', 'cover'],
演示项目: ['fun_animation', 'charts']
}
}
export const workerConfig = {
monitors: [
{
id: 'blog', // 唯一标识,不要随意修改
name: '博客',
method: 'HEAD',
target: 'https://note.weizwz.com/', // 必需,监控 url
statusPageLink: 'https://note.weizwz.com/', // 项目点击链接,有了之后界面可以点击跳转
preview: 'https://p.weizwz.com/siteshot_note.webp' // 监控项目主页预览图,非必须
}
],
notification: {
webhook: {
// 通知必需,建议去 `https://resend.com/` 注册,免费。后面有具体教程
url: 'https://api.resend.com/emails',
payload: {
from: '系统状态更新 <uptimeflare@updates.weizwz.com>', // 你的线上监控服务域名
to: ['xxxxxx@gmial.com'], // 你的邮箱
subject: 'UptimeFlare 状态更新',
text: '$MSG'
}
}
}
}
// 公告,非必须
const maintenances: MaintenanceConfig[] = [
// {
// title: '图床服务维护',
// body: '正在进行图床服务器升级维护,预计2小时完成',
// monitors: ['picture'],
// start: '2026-02-01T18:00:00+08:00',
// end: '2026-02-21T23:00:00+08:00',
// },
]重要说明:
npm run dev 时,Wrangler 会自动在 .wrangler/state/v3/d1/ 目录创建 SQLite 数据库文件uptimeflare 表需要手动执行 SQL 创建步骤 3.1:启动开发服务器
bash
npm run dev
# 此时会自动创建数据库文件,但表结构未创建,页面无数据
# 访问 http://localhost:3000步骤 3.2:创建表结构
bash
# 使用 init.sql 初始化表结构
npx wrangler d1 execute UPTIMEFLARE_D1 --local --file=./init.sql步骤 3.3:初始化数据
选择以下任一方式:
bash
# 插入空的初始状态
npx wrangler d1 execute UPTIMEFLARE_D1 --local \
--command "INSERT INTO uptimeflare (key, value) VALUES ('state', '{\"overallUp\":0,\"overallDown\":0,\"lastUpdate\":0,\"incident\":{},\"latency\":{}}')"查询远程数据库名称,运行 npx wrangler d1 list。
在项目根目录运行以下命令导出数据(请将 <YOUR_DB_NAME> 替换为实际名称):
bash
npx wrangler d1 execute <YOUR_DB_NAME> \
-c /dev/null \
--remote \
--command "SELECT value FROM uptimeflare WHERE key = 'state'" \
--json > backup_data.json运行脚本(已自动绕过 Wrangler 长度限制写入 sqlite):
bash
python3 scripts/import_local_data.pypy
#!/usr/bin/env python3
"""
UptimeFlare - 数据导入脚本
详细文档查看: scripts/import_data_guide.md
运行此脚本: python3 scripts/import_local_data.py
"""
import json
import subprocess
import sys
import os
def main():
# 检查备份文件是否存在
backup_file = "backup_data.json"
if not os.path.exists(backup_file):
print(f"❌ 错误: 找不到备份文件 '{backup_file}'")
print("\n请先从生产环境导出数据:")
print(' npx wrangler d1 execute <YOUR_DB_NAME> \\')
print(' -c /dev/null \\')
print(' --remote \\')
print(' --command "SELECT value FROM uptimeflare WHERE key = \'state\'" \\')
print(' --json > backup_data.json')
sys.exit(1)
# 读取备份数据
print(f"📖 读取备份文件: {backup_file}")
try:
with open(backup_file, 'r', encoding='utf-8') as f:
data = json.load(f)
except json.JSONDecodeError as e:
print(f"❌ 错误: JSON 格式错误 - {e}")
sys.exit(1)
except Exception as e:
print(f"❌ 错误: 读取文件失败 - {e}")
sys.exit(1)
# 提取 state 数据
if not data or len(data) == 0:
print("❌ 错误: 备份文件为空")
sys.exit(1)
# Wrangler 导出的格式可能包含 results
state_value = None
if isinstance(data, list) and len(data) > 0:
if 'results' in data[0] and data[0]['results']:
state_value = data[0]['results'][0].get('value')
else:
state_value = data[0].get('value')
elif isinstance(data, dict):
if 'results' in data and data['results']:
state_value = data['results'][0].get('value')
else:
state_value = data.get('value')
else:
print("❌ 错误: 无法识别的数据格式")
sys.exit(1)
if not state_value:
print("❌ 错误: 找不到 'value' 字段")
sys.exit(1)
print(f"✅ 成功读取数据 ({len(state_value)} 字符)")
# 转义 JSON 字符串中的特殊字符
# 将单引号替换为两个单引号(SQLite 转义方式)
# 将单引号替换为两个单引号(SQLite 转义方式)
escaped_value = state_value.replace("'", "''")
print("\n🔄 准备导入数据...")
import glob
db_files = glob.glob('.wrangler/state/v3/d1/miniflare-D1DatabaseObject/*.sqlite')
if not db_files:
print("❌ 错误: 找不到本地数据库,请先运行一次 npm run dev 初始化")
sys.exit(1)
latest_db = max(db_files, key=os.path.getmtime)
print(f"🔄 绕过 Wrangler 限制,使用 sqlite3 直接写入数据库...")
try:
sql = f"INSERT OR REPLACE INTO uptimeflare (key, value) VALUES ('state', '{escaped_value}');"
subprocess.run(['sqlite3', latest_db], input=sql, text=True, check=True)
print("✅ 数据导入成功!")
print("\n✨ 完成! 现在可以重启开发服务器:")
print(" npm run dev")
except Exception as e:
print(f"❌ 错误: 导入失败 - {e}")
sys.exit(1)
if __name__ == "__main__":
main()步骤 3.4:重启开发服务器
bash
# 停止之前的服务器(Ctrl+C)
# 重新启动
npm run dev
# 现在应该可以正常访问了创建步骤如图示,注意第 5 步的时候,要添加对数据库 D1 的编辑权限,是这个默认模板里没有的,之后就是继续确定等操作了。

创建完成后记得复制 API,然后将该 API 绑定到你的 Github 仓库,key 名:CLOUDFLARE_API_TOKEN

去 https://resend.com/,注册并创建一个 API,API 复制备用。然后再创建一个 domain 来绑定你的 API。如果你的域名直接在 CloudFlare 上托管的话,直接会提示自动修改 CloudFlare 的 DNS 解析,如果是其他服务商的域名,需要你按他的要求去修改。

同 Cloudflare API 一样,这个 API 也去 GitHub 仓库添加并绑定,key 名:RESEND_API_KEY
在 GitHub 仓库的 Action 里,直接运行已有的工作流 .github/workflows/deploy.yml

运行正常的话,你的 Workers 和 Pages 里会多出两项服务,一个 uptimeflare page 和一个 uptimeflare_worker,数据库里会多出一个 uptimeflare_d1 数据库。

去 uptimeflare page里设置一下自定义域,即可访问你的状态监控服务

D1 数据库限制
Worker 限制
Next.js Edge Runtime
runtime = 'experimental-edge'本地数据库
.wrangler/state/v3/d1/ 目录.wrangler/state 目录后重新执行步骤3此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。