如何使用 Upptime 免费搭建自己的状态站点
把监控这件事整个儿搬进 GitHub 仓库------Actions 当探针、仓库当数据库、Pages 当 CDN、Issues 当事件簿。零服务器,零月费,愣是凑出一个能看能查能留痕的状态站。说是黑魔法也好,说是穷人的智慧也罢,反正它跑起来了。
背景
运维一个由十几个对外服务凑起来的小型产品矩阵时,"到底通不通"这事常常变成了口头禅。客户反馈说访问不了,你 ssh 上去 curl 一遍发现是好的;过几分钟它又挂了,可你这次没盯到。商业监控(Pingdom、UptimeRobot 的高级档、Datadog)当然能解决,只是要么按站点收费,要么按请求次数收费,对一个独立开发者来说,成本和心智负担都不太划算而已。
更关键的是,状态页本身也得让用户能查。理想的样子是:一个域名(比如 status.hagicode.com),实时展示每个服务的可用率、响应时间曲线、历史事件,故障时还能自动留痕、自动通知。传统做法要凑齐四件套------跑 cron 的服务器、存历史数据的数据库、前端站点、CDN。这四样一摆开,运维成本立刻就盖过了被监控的服务本身,毕竟杀鸡用了牛刀,鸡还嫌挤。
为了解决这些痛点,我们做了一个决定:整个监控方案直接搬到 GitHub 上。这个决定带来的变化,可能比你想的还要大------稍后我再慢慢说。
关于 HagiCode
本文分享的方案,来自我们在 HagiCode 项目里摸爬滚打的经验。HagiCode 是个 AI 代码助手项目,对外吐出了网页、文档站、下载端点等十几个公共服务,背后由 HagiCode-org/site 这个主仓库驱动着。这些站点必须稳定可用,所以状态监控对我们不是可选项,而是刚需。下面这套 Upptime 方案,正是 HagiCode 实际生产环境在用的------不是我编的。
分析:Upptime 到底是怎么跑起来的
Upptime 的本质,其实是一份 GitHub 仓库模板,加上六个由模板生成的 workflow。理解它的关键,就是看清楚"谁在什么时候、调用谁、产出什么落到哪里"。把它拆开了看,也就不那么神秘了。
数据流:一个配置文件驱动一切
整个系统,就绕着 .upptimerc.yml 这一个声明式配置文件转。HagiCode 的实际配置结构,大概是这样:
yaml
owner: HagiCode-org
repo: upptime
sites:
- name: HagiCode Website
url: https://hagicode.com
- name: HagiCode Docs
url: https://docs.hagicode.com
- name: Server Package Index
url: https://index.hagicode.com/server/index.json
# ... 共 14 个站点
status-website:
cname: status.hagicode.com
logoUrl: https://raw.githubusercontent.com/HagiCode-org/upptime/master/assets/upptime-icon.svg
name: HagiCode Status
introTitle: "**HagiCode Status**"
introMessage: Real-time availability tracking for public HagiCode websites and download endpoints.
navbar:
- title: Status
href: /
- title: GitHub
href: https://github.com/$OWNER/$REPO
这里有两点值得拎出来说。第一,sites 既能监控网页(返回 HTML),也能监控纯 JSON 端点(比如 index.json),Upptime 只看 HTTP 状态码和响应时间,不做内容校验。第二,cname 指向 status.hagicode.com,这要求你得拥有该域名,并把 DNS 指向 GitHub Pages------毕竟白嫖归白嫖,域名还是要自己出的。
六个 workflow 的分工
.github/workflows/ 下所有文件顶部都有一行警告 Do not edit this file directly!------它们由模板每周自动更新,你只改 .upptimerc.yml 就好。每个 workflow 用 cron 触发,调用同一个 action upptime/uptime-monitor@v1.42.6 的不同子命令,分工明确,倒也省心:
| Workflow | cron | 命令 | 作用 |
|---|---|---|---|
uptime.yml |
*/5 * * * * |
update |
每 5 分钟探活,写 history/*.yml |
response-time.yml |
--- | response-time |
计算响应时间统计 |
graphs.yml |
--- | graphs |
生成日/周/月/年 PNG 曲线 |
summary.yml |
--- | summary |
更新 README 里的状态表 |
site.yml |
0 1 * * * |
site |
每日构建静态站,部署到 Pages |
update-template.yml |
0 0 * * * |
--- | 每周同步上游模板 |
uptime.yml 的核心片段,展示了"探针"是怎么跑的:
yaml
on:
schedule:
- cron: "*/5 * * * *"
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GH_PAT || github.token }}
- name: Check endpoint status
uses: upptime/uptime-monitor@v1.42.6
with:
command: "update"
env:
GH_PAT: ${{ secrets.GH_PAT || github.token }}
SECRETS_CONTEXT: ${{ toJson(secrets) }}
site.yml 则多了一步,用 peaceiris/actions-gh-pages@v4 把构建产物推到 gh-pages 分支:
yaml
- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GH_PAT || github.token }}
publish_dir: "site/status-page/__sapper__/export/"
user_name: "Upptime Bot"
user_email: "73812536+upptime-bot@users.noreply.github.com"
数据落盘:文件即数据库
监控结果不存数据库,而是直接以文件形式 commit 回仓库。这听起来有点野,但用起来倒也踏实。每个站点有三类产物。
状态快照 history/{slug}.yml,例如 history/hagi-code-website.yml:
yaml
url: https://hagicode.com
status: up
code: 200
responseTime: 96
lastUpdated: 2026-06-17T00:22:34.485Z
startTime: 2026-03-24T10:07:32.531Z
shields.io 的 endpoint 徽章数据源 api/{slug}/response-time.json、uptime.json:
json
{"schemaVersion":1,"label":"response time","message":"739 ms","color":"yellow"}
以及响应时间曲线图 graphs/{slug}/response-time-{day,week,month,year}.png。
这套"文件即数据库"的取舍,其实想得挺清楚:写多读少、规模可控(每个站点一天约 288 条采样,存增量而非全量)、天然带版本历史、零基础设施。代价嘛,就是仓库会持续长大,偶尔得回头关心一下它而已。
事件与通知:Issues 当事件簿
故障留痕靠 GitHub Issues,配合仓库自带的两个模板:.github/ISSUE_TEMPLATE/bug_report.md(用户报障)和 maintainance-event.md(计划性维护)。维护模板用 frontmatter 表达时间窗:
markdown
<!--
start: 2021-08-24T13:00:00.220Z
end: 2021-08-24T14:00:00.220Z
expectedDown: google, hacker-news
-->
Upptime 会解析这些 Issue,把"正在维护"和"已发生事件"渲染到状态页和 README 上。通知则靠 Issue 自身的 watch 机制,外加可配置的 webhook、Slack、Telegram(在 .upptimerc.yml 顶部声明 notifications,HagiCode 的示例仓库目前没启用,毕竟能少一样是一样)。
解决:五步复刻一套状态站
复刻一套 HagiCode 同款状态站,从零到上线,一共五步。说是五步,其实每步都不长,慢慢来就是。
第 1 步:从模板创建仓库
别 git clone 后改,直接用 GitHub 的 "Use this template" 创建仓库(例如 your-org/upptime)。模板已经内置了全部 workflow、Issue 模板和静态站点骨架。clone 到本地后,唯一需要手改的就是 .upptimerc.yml------其它的,留着别动就好。
第 2 步:编辑 .upptimerc.yml
把 owner/repo 改成你的,sites 列出要监控的地址,status-website 配置站点。最小可用版本大概是这样:
yaml
owner: your-org
repo: upptime
sites:
- name: Main Site
url: https://example.com
- name: API Health
url: https://api.example.com/health
expectedStatusCodes:
- 200
status-website:
cname: status.example.com # 没有域名可删掉,用默认的 your-org.github.io/upptime
name: Example Status
introTitle: "**Example Status**"
introMessage: 服务可用性实时监控
navbar:
- title: Status
href: /
- title: GitHub
href: https://github.com/$OWNER/$REPO
进阶项:expectedStatusCodes 限定可接受的状态码(默认 200-399);headers 自定义请求头(用于需要鉴权的端点);maxResponseTime 标记慢响应。这些都看你需要,按需取用罢了。
第 3 步:配置 Secret 与权限
workflow 默认用 ${{ secrets.GH_PAT || github.token }}。github.token 能跑通基本流程,但有两个限制会咬人:
- 默认 token 触发的 workflow 不会再触发下游 workflow(防止循环),导致"探活 → 建 Issue → 通知"这条链断在中间。
- 跨仓库操作(比如多组织)权限不足。
推荐新建一个 PAT(需要 repo + workflow 权限),存为仓库 Secret GH_PAT。update-template.yml 里专门有一段检查:没有 GH_PAT 就跳过模板自动更新并打印 warning,所以这个 secret 不只是可选项,更是省心的关键。
第 4 步:开启 GitHub Pages
仓库 Settings → Pages → Source 选 Deploy from a branch,分支选 gh-pages、目录 /root。site.yml 每天凌晨 1 点会自动把构建产物推到这个分支。如果配了 cname,再到你的 DNS 服务商加一条 CNAME 记录指向 your-org.github.io。
第一次手动触发一下也好:Actions 页面找到 "Static Site CI" → Run workflow,不用傻等定时任务,毕竟能早一秒看到结果,心里就早一秒踏实。
第 5 步:验证与维护
push 配置后,去 Actions 看 "Uptime CI" 是否每 5 分钟跑一次、history/ 是否开始出现 *.yml 文件。状态页地址就是 https://<your-org>.github.io/upptime/ 或你的自定义域名。后续加站点、改域名,只动 .upptimerc.yml 一个文件就行,workflow 全自动。HagiCode 这一年多就靠这套机制维护 14 个端点的可用性,基本没怎么操心过。
实践:踩过的坑都替你趟过了
下面这几条,是 HagiCode 实际运行中积累下来的经验,写出来也好让你少走点弯路。
实践 1:监控粒度选择
HagiCode 把网页(https://hagicode.com)和纯数据端点(https://index.hagicode.com/server/index.json)放在同一个 sites 列表里。对 JSON 端点,Upptime 会请求并解析 HTTP 状态码,但不校验内容结构。如果你需要"返回 200 但内容错误"这种深度检查,得用 expectedStatusCodes 加上外部探针来补,Upptime 本身只做黑盒 HTTP 检查------它只看脸色,不读心事。
实践 2:响应时间徽章的妙用
api/{slug}/response-time.json 是 shields.io 的 endpoint 徽章 数据源。HagiCode 的 README 里大量引用这种 URL:
perl
https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2FHagiCode-org%2Fupptime%2FHEAD%2Fapi%2Fhagi-code-website%2Fresponse-time.json
这样一来,你就能在任何 Markdown(项目 README、博客、第三方页面)里嵌入实时响应时间徽章,颜色由 message 里的数值和 color 字段驱动。注意用 HEAD 而不是 master/main 引用 raw 文件,能避免分支改名后大面积失效------细节之处,藏着安稳。
实践 3:仓库体积控制
每 5 分钟一次采样,一年下来 history/ 会累积出可观的体积。Upptime 用增量 YAML 而非全量日志,相对克制,但仍建议定期看一眼仓库大小。如果某个站点监控价值下降了,从 sites 移除即可,对应的历史文件也可以手动清理掉,毕竟舍不得删,仓库迟早会臃肿给你看。
实践 4:维护事件的真实用法
maintainance-event.md 不是摆设。计划发版前,按模板开一个 Issue,填好 start/end/expectedDown,Upptime 会把这段时间内的对应站点标记为"计划内维护",不计入可用率统计,避免一次正常发版把全年 SLA 拉低。HagiCode 的 expectedDown 支持逗号分隔的站点名列表,与 sites[].name 一一对应。
实践 5:模板更新与自定义的边界
所有 .github/workflows/*.yml 顶部的 Do not edit this file directly!,不是吓唬人的。update-template.yml 每周会用上游模板覆盖这些文件。需要自定义行为时,正确做法是在 .upptimerc.yml 里用官方支持的配置项(如 skipTopics、customStatusWebsite、runnerSettings),而不是去改 workflow。实在要改 workflow,要么关掉 update-template.yml,要么 fork 出来自己维护模板------后者会失去无痛升级,得失之间,自己掂量罢了。
实践 6:免费额度的现实约束
GitHub Actions 对公开仓库免费、不限时长,Upptime 设计上正是利用了这一点。私有仓库每月有 2000 分钟免费额度,而 uptime.yml 每 5 分钟跑一次、每次约 1 分钟,单这一项一个月就大概 8640 分钟,会超额。所以 Upptime 仓库必须是 public,这是"免费"两个字的前提------别图保密开成 private,然后收到账单,那就尴尬了。
总结
回到开头那个问题:监控一堆对外服务,到底有没有便宜的解法?HagiCode 的答案是------有,而且便宜得让你怀疑这是不是真的。Upptime 把监控拆成了四个 GitHub 原生组件:
- 探针 = GitHub Actions 的 cron
- 数据库 = 仓库里的 YAML/JSON 文件
- CDN = GitHub Pages
- 事件簿 = GitHub Issues
你得到的是:实时可用率、响应时间曲线、历史事件、可用率徽章、自定义域名、自动通知,全部零服务器、零月费。代价是要保持仓库公开,以及偶尔关心一下仓库体积。其实这点代价,比起手搓一套监控,已经轻得太多。
这套方案之所以能跑通,背后是 GitHub 生态对开源项目的诚意补贴。如果你也在维护一个多站点的小型产品矩阵,强烈建议花一个下午把它搭起来,比手搓监控省心太多。
参考资料
总结
围绕"如何使用 Upptime 免费搭建自己的状态站点",更稳妥的推进方式是先把关键配置、依赖边界和落地路径逐步跑通,再补齐优化细节。
当目标、步骤和验收点都明确之后,这类方案通常就能更顺畅地进入实际交付。
原文与版权说明
感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。
- 本文作者: newbe36524
- 原文链接: docs.hagicode.com/go?platform...
- 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!