Healthchecks v4.4 快速入门与集成示例
Healthchecks v4.4 快速入门:建 Check、ping URL 上报、curl/cron/脚本集成、超时与宽限期、通知渠道与告警邮件实测,全部命令带真实回显。
Healthchecks v4.4 快速入门与集成示例
目标:在已部署的 Healthchecks v4.4 上完成一次完整闭环——创建 Check、用 curl 上报 ping(成功/失败/开始/日志)、cron 与 Shell 脚本集成、配置超时与宽限期、绑定通知渠道并实测收到 UP/DOWN 告警邮件。已在 Ubuntu 22.04(源码部署 v4.4)实测通过,回显均为真实输出。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- Healthchecks:v4.4(源码部署,监听
http://localhost:8000;Docker 部署同样适用,把地址换成你的即可) - 管理账号:
admin@example.org/q1w2e3r4 - 项目:登录后自动创建的默认项目(Project UUID
bfe79acf-9a76-472b-8029-9828d9a4ffe2) - API Key:
hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi(读写权限) - 演示 Check:
backup-db(UUID83459720-9231-40d0-b7c6-5d237327951d) - 客户端:curl 7.81.0(Ubuntu 22.04 自带)
二、核心概念与准备工作
Healthchecks 的使用闭环只有四步:建 Check → 拿 ping URL → 任务里上报 → 配通知渠道。登录 Web 界面(http://<服务器>:8000,邮箱 + 密码)后默认进入项目 Check 列表页;本篇所有操作同时给出 Web 界面路径与 API/curl 等价命令,命令部分全部实测。
2.1 获取 API Key
界面路径:项目页右上角「⚙ Settings → Show API Keys / Create API Key」。API Key 分两种:hcw_ 开头可读写、hcr_ 开头只读。等价的命令行生成方式(与界面按钮调用同一函数,明文只显示一次):
cd /opt/healthchecks
/opt/venv/bin/python manage.py shell -c "from hc.api.models import Project; p = Project.objects.first(); key = p.set_api_key(); p.save(); print(key)"
实测输出:
hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi
⚠️ 注意:必须紧跟
p.save(),否则 Key 未落库;另注意 API Key 的校验与SECRET_KEY绑定(HMAC 存储),更换SECRET_KEY后旧 Key 全部失效。
用错 Key 的真实报错长这样(后面所有 API 调用都带 X-Api-Key 头):
curl -s -H "X-Api-Key: wrong-key" http://127.0.0.1:8000/api/v3/checks/
{"error": "wrong api key"}
三、创建第一个 Check
3.1 Web 界面方式
登录后 Check 列表页点「Add Check」,弹窗里填名称、预期周期(Schedule)与宽限期(Grace),保存后列表出现一行新 Check,点它就能看到 ping URL。界面保存的每个字段与下文 API 参数一一对应。
3.2 API 方式(curl 实测)
创建一个每天 03:00(Asia/Shanghai)执行、宽限 30 分钟的数据库备份监控项:
curl -s -H "X-Api-Key: hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi" \
-H "Content-Type: application/json" \
-d '{"name": "backup-db", "slug": "backup-db", "tags": "prod db", "schedule": "0 3 * * *", "tz": "Asia/Shanghai", "grace": 1800}' \
http://127.0.0.1:8000/api/v3/checks/
实测输出:
{"name": "backup-db", "slug": "backup-db", "tags": "prod db", "desc": "", "grace": 1800, "n_pings": 0, "status": "new", "started": false, "last_ping": null, "next_ping": null, "manual_resume": false, "methods": "", "subject": "", "subject_fail": "", "start_kw": "", "success_kw": "", "failure_kw": "", "filter_subject": false, "filter_body": false, "filter_http_body": false, "filter_default_fail": false, "badge_url": "http://localhost:8000/b/2/368d0429-ed60-4f14-a25d-37612958edaa.svg", "uuid": "83459720-9231-40d0-b7c6-5d237327951d", "ping_url": "http://localhost:8000/ping/83459720-9231-40d0-b7c6-5d237327951d", "update_url": "http://localhost:8000/api/v3/checks/83459720-9231-40d0-b7c6-5d237327951d", "pause_url": "http://localhost:8000/api/v3/checks/83459720-9231-40d0-b7c6-5d237327951d/pause", "resume_url": "http://localhost:8000/api/v3/checks/83459720-9231-40d0-b7c6-5d237327951d/resume", "channels": "", "schedule": "0 3 * * *", "tz": "Asia/Shanghai"}
要点:uuid 是 Check 身份,ping_url 就是待会儿要集成的上报地址;schedule 用 cron 表达式时必须同时给 tz,否则按 UTC 解释;列表查询用 GET /api/v3/checks/,单条查询把 UUID 拼到 URL 后面:
curl -s -H "X-Api-Key: hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi" http://127.0.0.1:8000/api/v3/checks/83459720-9231-40d0-b7c6-5d237327951d | python3 -m json.tool | grep -E '"(name|status|n_pings|last_ping|next_ping)"'
"name": "backup-db",
"n_pings": 7,
"status": "up",
"last_ping": "2026-10-16T15:34:17+00:00",
"next_ping": "2026-10-16T19:00:00+00:00",
💡 说明:
next_ping的 19:00 UTC 正是0 3 * * *的 Asia/Shanghai 时间,时区换算已按tz参数生效。
3.3 修改 Check 用 POST(不是 PATCH)
改周期/宽限期直接 POST 到 update_url。注意 Healthchecks API 不支持 PATCH(返回 405),一律用 POST:
curl -s -X PATCH -H "X-Api-Key: hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi" -H "Content-Type: application/json" -d '{"timeout": 60}' http://127.0.0.1:8000/api/v3/checks/83459720-9231-40d0-b7c6-5d237327951d -w "\nPATCH -> %{http_code}\n"
PATCH -> 405
curl -s -X POST -H "X-Api-Key: hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi" -H "Content-Type: application/json" -d '{"timeout": 60, "grace": 60}' http://127.0.0.1:8000/api/v3/checks/83459720-9231-40d0-b7c6-5d237327951d | python3 -c "import json,sys; d=json.load(sys.stdin); print('timeout:', d['timeout'], 'grace:', d['grace'], 'status:', d['status'])"
timeout: 60 grace: 60 status: down
💡 说明:把周期临时改成 60 秒后状态立刻变
down——上一次 ping 已超过「60 秒周期 + 60 秒宽限」,这正是下一章超时判定的直接体现。
四、ping 上报详解(curl 实测)
ping URL 的完整语义族(<uuid> 换成你的 Check UUID):
| 端点 | 语义 | 实测状态码 |
|---|---|---|
GET/POST /ping/<uuid> | 上报成功 | 200 |
/ping/<uuid>/fail | 上报失败(立即告警) | 200 |
/ping/<uuid>/start | 任务开始(计时起点) | 200 |
/ping/<uuid>/log | 仅记录,不影响状态 | 200 |
/ping/<uuid>/<exit code> | 按退出码判定,非 0 视为失败 | 200 |
| 错误的 UUID | — | 404 not found |
逐个实测:
PING=http://127.0.0.1:8000/ping/83459720-9231-40d0-b7c6-5d237327951d
curl -s $PING -w " <- 成功 ping: %{http_code}\n"
curl -s --data "backup finished, 0 errors" $PING -w " <- 带 body 的成功 ping: %{http_code}\n"
curl -s $PING/start -w " <- /start: %{http_code}\n"
curl -s $PING/fail -w " <- /fail: %{http_code}\n"
curl -s "$PING/0" -w " <- /0 (exit code 0, 成功): %{http_code}\n"
curl -s "$PING/1" -w " <- /1 (exit code 1, 失败): %{http_code}\n"
curl -s "$PING/log" -w " <- /log (仅记录): %{http_code}\n"
curl -s http://127.0.0.1:8000/ping/ffffffff-ffff-ffff-ffff-ffffffffffff -w " <- 不存在的 UUID: %{http_code}\n"
实测输出:
OK <- 成功 ping: 200
OK <- 带 body 的成功 ping: 200
OK <- /start: 200
OK <- /fail: 200
OK <- /0 (exit code 0, 成功): 200
OK <- /1 (exit code 1, 失败): 200
OK <- /log (仅记录): 200
not found <- 不存在的 UUID: 404
💡 说明:所有合法 ping 的响应体都是
OK(2 字节),非法 UUID 返回not found。/fail/<退出码>的写法不存在——退出码直接跟在 UUID 后(/<uuid>/1),拼成/<uuid>/fail/1会 404(实测)。POST 的 body 会作为执行输出留档(默认最多 10 KB,PING_BODY_LIMIT可调),在界面的 ping 详情里可回看。
上报记录可通过 API 查询(GET /api/v3/checks/<uuid>/pings/):
curl -s -H "X-Api-Key: hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi" http://127.0.0.1:8000/api/v3/checks/83459720-9231-40d0-b7c6-5d237327951d/pings/ | python3 -m json.tool | head -18
实测输出(节选):
{
"pings": [
{
"type": "success",
"date": "2026-10-16T15:40:22.398366+00:00",
"n": 8,
"scheme": "http",
"remote_addr": "127.0.0.1",
"method": "GET",
"ua": "curl/7.81.0",
"rid": null,
"body_url": null
},
{
"type": "log",
"date": "2026-10-16T15:34:17.787909+00:00",
4.1 按 slug 上报(免查 UUID)
项目设置里开启「Show ping URLs as slugs」后可生成项目级 ping key,URL 形如 /ping/<ping_key>/<slug>,人读性更好。生成:
/opt/venv/bin/python manage.py shell -c "from hc.api.models import Project; p=Project.objects.first(); key=p.set_ping_key(); p.save(); print(key)"
实测输出:
hqrgaag0lzaqaxffaozw2g
实测按 slug 上报与未知 slug 的行为:
PKEY=hqrgaag0lzaqaxffaozw2g
curl -s "http://127.0.0.1:8000/ping/$PKEY/backup-db" -w " <- 按 slug 成功: %{http_code}\n"
curl -s "http://127.0.0.1:8000/ping/$PKEY/backup-db/fail" -w " <- 按 slug 失败: %{http_code}\n"
curl -s "http://127.0.0.1:8000/ping/$PKEY/nonexistent" -w " <- 不存在的 slug: %{http_code}\n"
OK <- 按 slug 成功: 200
OK <- 按 slug 失败: 200
not found <- 不存在的 slug: 404
4.2 状态徽章(Badge)
每个 Check 都有一个 SVG 徽章 URL(API 返回里的 badge_url),可嵌进 README 或状态页。实测拉取:
curl -s "http://localhost:8000/b/2/368d0429-ed60-4f14-a25d-37612958edaa.svg" | head -2
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="93" height="20">
<linearGradient id="smooth" x2="0" y2="100%">
五、集成示例(curl / cron / Shell 脚本)
5.1 cron 集成(最常用)
cron 作业末尾追加一条 curl 即可。真实写入 crontab:
echo "*/5 * * * * curl -fsS --retry 3 http://127.0.0.1:8000/ping/83459720-9231-40d0-b7c6-5d237327951d > /dev/null" | crontab -
crontab -l
实测输出:
*/5 * * * * curl -fsS --retry 3 http://127.0.0.1:8000/ping/83459720-9231-40d0-b7c6-5d237327951d > /dev/null
参数含义:-f 让 HTTP 非 2xx 时 curl 以非 0 退出;-s 静默;--retry 3 上报失败自动重试 3 次;输出丢弃。Check 的 Schedule 要与 crontab 表达式一致,宽限期按任务最长容忍延迟设置。
5.2 Shell 脚本模板(区分成功/失败)
#!/bin/bash
# backup.sh —— 数据库备份 + 心跳上报示例
PING_URL="http://127.0.0.1:8000/ping/83459720-9231-40d0-b7c6-5d237327951d"
# 1) 上报"开始",失败时长告警将以 start 为计时起点
curl -fsS --retry 3 "$PING_URL/start" > /dev/null
# 2) 真正的业务任务
if pg_dump -h 127.0.0.1 -U hc hc > /tmp/hc-$(date +%F).sql; then
# 成功:带上输出摘要上报
curl -fsS --retry 3 --data "dump ok: $(du -h /tmp/hc-$(date +%F).sql | cut -f1)" "$PING_URL" > /dev/null
else
# 失败:立即触发 down 告警,并携带错误输出
curl -fsS --retry 3 --data "pg_dump failed" "$PING_URL/fail" > /dev/null
fi
要点:/start 之后若任务迟迟不结束,超过「预估时长 + 宽限」就按运行超时告警(适合备份卡死场景);/fail 上报会立即把 Check 置为 down 并告警,不等宽限期。
5.3 按退出码一键上报
简单任务可把脚本退出码直接拼进 URL:
your-job; curl -fsS --retry 3 "http://127.0.0.1:8000/ping/83459720-9231-40d0-b7c6-5d237327951d/$?" > /dev/null
$? 为 0 走成功判定,非 0 即失败,URL 里的实测行为见第四章表格。
六、超时与宽限期
两类时间参数决定"什么时候算掉线":
- Period(周期)/Schedule(计划):任务预期的执行节奏。简单模式用固定间隔(如每 5 分钟),精确模式用 cron 表达式 + 时区;
- Grace Time(宽限期):周期到点后额外的容忍时间,吸收任务偶发的延迟与网络抖动。
判定规则(实测验证):上次 ping + 周期 + 宽限 时刻一到,Check 由 up 转 down 并触发告警;期间任何一次成功 ping 都会复位计时。第六章 3.3 节的实测(timeout=60、grace=60 后状态立即 down)就是这条规则的直接结果。
设置建议:宽限期取「任务最长正常耗时」与「告警可容忍延迟」的折中,一般 5–60 分钟;cron 类 Check 宽限太短会造成夜间抖动误报,太长则故障发现变慢。对「任务开始后跑了很久没结束」的场景,配合 /start 使用运行时长判定。
💡 技术拓展:Schedule 表达式除标准 cron 外,Healthchecks 还支持
oncalendar语法的*-*-* 03:00:00形式(create 接口传schedule_type: "oncalendar"),对「工作日 9 点」「每月最后一天」这类人话排期更直观。本文采用最通用的标准 cron 表达式。
七、通知渠道与告警实测
7.1 添加邮件渠道
界面路径:页面顶部「Integrations → Add Integration → Email」,填收件邮箱;EMAIL_USE_VERIFICATION=False(内网快速上手)时直接生效,生产默认要收确认邮件。渠道添加后,在 Check 详情页勾选该渠道(或保持默认「全部渠道」绑定)。
7.2 实测一次完整告警
前置:/etc/healthchecks 已配置出站 SMTP(EMAIL_HOST 等五个变量),healthchecks-sendalerts 服务运行中(systemctl is-active 为 active)。让 backup-db 保持 timeout=60/grace=60 且不再 ping,约 2 分钟后观察:
Check 状态查询(已转 down):
status: down
告警邮件实测内容(用 aiosmtpd 调试服务器 python -m aiosmtpd -n -l 127.0.0.1:2525 在 2525 端口抓包,真实回显节选):
Subject: DOWN | backup-db
From: healthchecks@localhost
To: admin@example.org
The check "backup-db" has gone down.
Reason: success signal did not arrive on time, grace time passed.
View on Mychecks:
http://localhost:8000/cloaked/3f38fe19bb75f6d5ddb13657062bf8cc04616683/
Details:
--------
Tags: prod db
Period: 1 minute
Total pings: 8 (since Oct 16, 2026)
Last ping: 2 minutes ago, from 127.0.0.1
Last ping type: Success
Status changed to down at: Fri, 16 Oct 2026 15:42:22 +0000
Projects Overview:
------------------
* admin@example.org: 1 check down
随后再 ping 一次成功,恢复邮件同样发出:
Subject: UP | backup-db
...
The check "backup-db" has gone up.
The downtime lasted 4 minutes, 4 seconds.
💡 说明:
DOWN邮件带掉线原因(success signal did not arrive on time, grace time passed即超时+宽限都过了)与最近 ping 摘要;正文链接走/cloaked/跳转避免泄露 Check UUID。除邮件外,Healthchecks 还内置 Webhook、Slack、Telegram、Discord、PagerDuty、飞书类 Webhook 等几十种渠道,均在 Integrations 页配置,告警派发机制相同(sendalerts常驻进程消费状态翻转事件)。
八、API 速查(v3,实测可用)
Base URL:http://<SITE_ROOT>/api/v3,鉴权头:X-Api-Key: <hcw_ 开头的读写 Key>。错误时返回 JSON {"error": "wrong api key"}。
| 操作 | 方法与路径 | 本文实测要点 |
|---|---|---|
| 列出全部 Check | GET /checks/ | 返回 checks 数组,含 ping_url/状态/周期 |
| 创建 Check | POST /checks/(JSON body) | 支持 name/slug/tags/schedule/tz/grace/timeout |
| 查询单条 | GET /checks/<uuid> | 字段同上 |
| 更新 | POST /checks/<uuid> | 不支持 PATCH(405),用 POST |
| 暂停/恢复 | POST /checks/<uuid>/pause、/resume | 实测均 200,暂停后 status=paused |
| ping 记录 | GET /checks/<uuid>/pings/ | type/date/n/method/ua/body_url |
| 通道列表 | GET /channels/ | 返回 id/kind/name |
| 徽章 | GET /badges/ | 各项目徽章 URL 汇总 |
| 状态文档 | GET /api/v3/status/ | 镜像健康检查所用端点 |
暂停/恢复实测回显:
KEY=hcw_WEvuuwb0tRz3jxAhM3BfYkT2bGAi
UUID=83459720-9231-40d0-b7c6-5d237327951d
curl -s -X POST -H "X-Api-Key: $KEY" http://127.0.0.1:8000/api/v3/checks/$UUID/pause -o /dev/null -w "POST pause -> %{http_code}\n"
curl -s -H "X-Api-Key: $KEY" http://127.0.0.1:8000/api/v3/checks/$UUID | python3 -c "import json,sys; print('status:', json.load(sys.stdin)['status'])"
curl -s -X POST -H "X-Api-Key: $KEY" http://127.0.0.1:8000/api/v3/checks/$UUID/resume -o /dev/null -w "POST resume -> %{http_code}\n"
POST pause -> 200
status: paused
POST resume -> 200
💡 说明:
pause用于计划内停机窗口(如维护期间不想收告警);暂停期间 ping 仍被记录但状态保持 paused,resume后按最后 ping 重新计时。维护窗口结束后记得恢复,长期 paused 的 Check 不产生任何告警。
九、注意事项与常见问题
Q1:ping 返回 404 not found?
UUID 拼错(复制时截断)或用 /fail/<exit code> 形式拼了 URL——退出码应直接跟在 UUID 后(/<uuid>/1)。按 slug 上报时确认 slug 与 ping key 是否匹配项目。
Q2:Check 一直显示 new / 不变 up?
new 表示从未收到 ping。先用浏览器/curl 手打一遍 ping URL 确认链路;再核对 Schedule 是否配置成了很久一次(下次 ping 时间在 Check 详情页可见);服务端侧确认 healthchecks-sendalerts 常驻且 web 服务正常(systemctl is-active healthchecks-web healthchecks-sendalerts)。
Q3:任务明明失败但没告警?
三步排查:① 任务是否真的上报了 /fail(在 ping 记录里看 type=fail 是否出现);② Check 是否绑定了通知渠道(详情页渠道勾选);③ 出站 SMTP 是否配置且 sendalerts 服务 active(判定进程与发信进程是同一个,掉线判定不发即全链路不通)。告警派发过程在 journalctl -u healthchecks-sendalerts 中可逐条核对(含每个渠道的发送结果与耗时)。
Q4:HTTPS 反代后 ping URL 是 http?
ping URL 由 SITE_ROOT 派生。反代启用 TLS 后把 SITE_ROOT 更新为 https:// 形式并重启服务,新创建 Check 的 ping URL 即为 https;存量 Check 在界面上可直接复制正确的 URL(ping 端点本身 http/https 都接受)。
Q5:一台服务器上有很多同类任务,怎么管理?
用 tags 批量组织(如 prod db),列表页按 tag 过滤;跨项目聚合监控用「Badges」生成总览徽章;大量同类 Check 可用 API 批量创建(脚本循环调 POST /checks/,属用户程序逻辑)。