Uptime Kuma 之外的选择:Checkmate 本地自托管状态页,用 cpolar 给客户临时演示
项目交付到最后,客户最常问的一句话不是“你的 Prometheus 指标怎么配”,而是:“现在几个服务到底是不是正常?”
这时候我不想把内网 Grafana、服务器面板、Docker 后台都丢给对方看。客户需要的是一个干净的状态页:服务在线、接口响应、历史可用率、最近有没有故障。Checkmate 正好适合这个场景,再用 cpolar 临时开一个 HTTPS 入口,验收会结束就关掉。
这篇不写 Uptime Kuma 复刻教程。Uptime Kuma 更像经典的轻量 uptime 工具,生态成熟、上手快;Checkmate 的定位更偏“自托管状态页 + uptime / infrastructure monitoring”,界面展示、团队协作和可用率报表更适合拿给客户看。本文主角就是 Checkmate 的状态页演示链路。
先说清楚:这篇只开放状态页,不开放运维后台
我这次的目标很具体:
- 在本地 Docker 部署 Checkmate;
- 添加几个测试服务或脱敏接口监控;
- 整理状态标签、公开状态页、基础通知和历史可用率展示;
- 用 cpolar 暂时生成 HTTPS 地址,发给客户或远程团队看状态页;
- 演示结束关闭 cpolar,不留下长期公开入口。
安全边界也先写在前面:
- 监控对象只用测试服务、演示接口、脱敏后的服务名;
- 不把数据库端口、SSH、Docker socket、服务器目录、管理密码暴露到公网;
- 不把 Checkmate 管理后台当成客户入口;
- cpolar 只短时开放公开状态页或低权限只读入口;
- 长期状态页要换正式域名、鉴权、只读权限、备份和告警策略。
这点很重要。状态页是给人看的,不是给人进内网翻后台的。
本地准备一个 Checkmate
Checkmate 官方提供 Docker Compose 方式,默认会跑一个 Checkmate 应用和 MongoDB。下面我放到一个单独目录里,便于后面清理。
mkdir -p ~/checkmate-demo cd ~/checkmate-demo curl -O https://raw.githubusercontent.com/bluewave-labs/checkmate/master/docker/docker-compose.yaml第一次启动前生成一个 JWT_SECRET:
JWT_SECRET="$(openssl rand -hex 32)" docker compose up -d启动后看容器:
docker compose ps本地访问:
http://localhost:52345如果你在局域网其他机器访问,比如http://192.168.31.20:52345,建议在 compose 里把CLIENT_HOST调成实际访问地址。后面用 cpolar 开临时公网地址时,也要把它调成 cpolar 给出的 HTTPS 域名,避免邀请链接、状态页链接、接口跨域信息不一致。
一个简化后的服务配置长这样,实际以你下载到的官方 compose 为准:
services: checkmate: image: ghcr.io/bluewave-labs/checkmate:latest ports: - "127.0.0.1:52345:52345" environment: DB_CONNECTION_STRING: mongodb://mongodb:27017/uptime_db JWT_SECRET: ${JWT_SECRET} CLIENT_HOST: http://localhost:52345 depends_on: - mongodb mongodb: image: mongo:7 volumes: - checkmate-mongo:/data/db volumes: checkmate-mongo:这里52345只绑定到本机回环地址,MongoDB 不映射到宿主机,更不通过 cpolar 暴露出去。客户不需要看数据库,状态页也不需要公网直连数据库。
初始化账号,先别急着加真实业务名
打开http://localhost:52345后,按页面提示创建管理员账号。这里建议用演示邮箱和强密码,例如:
admin-demo@example.com密码不要写进文档、截图和聊天记录里。做库存文章、客户演示、内部培训时尤其要注意:截图里出现真实域名、客户名、账号名,会给后续传播留下麻烦。
我会先创建三个脱敏监控对象:
| 展示名称 | 真实含义 | 对外展示建议 |
|---|---|---|
| 官网首页 | 客户能访问的 Web 首页 | Customer Portal |
| API 健康检查 | /healthz或/api/ping | Public API |
| 文档站 | 只读帮助中心 | Help Center |
客户看状态页时,只要知道“哪些服务正常、什么时候不正常、可用率是多少”。不需要知道服务器 IP、内网端口、容器名、数据库地址。
添加第一个 HTTP 监控:官网或测试首页
进入 Checkmate 后,找到创建 Monitor 的入口,类型选择 HTTP / Website 这类监控。第一个监控我建议用可公开访问的测试页或本地演示服务。
如果你手头没有测试服务,可以先用 Python 起一个临时页面:
mkdir -p ~/checkmate-demo/mock-site cd ~/checkmate-demo/mock-site cat > index.html <<'HTML' <!doctype html> <html> <head><meta charset="utf-8"><title>Customer Portal Demo</title></head> <body><h1>Customer Portal Demo OK</h1></body> </html> HTML python3 -m http.server 8081 --bind 127.0.0.1在 Checkmate 里添加监控:
Name: Customer Portal URL: http://host.docker.internal:8081 Method: GET Expected Status: 200 Interval: 60s Timeout: 10s如果你在 Linux Docker 环境里访问宿主机服务,host.docker.internal不一定默认可用。可以在 compose 的 Checkmate 服务里加:
extra_hosts: - "host.docker.internal:host-gateway"然后重启:
docker compose up -d这个监控用来模拟客户门户。它不是资源监控,也不是日志检索,就是回答一个问题:客户访问入口现在通不通。
再加一个接口健康检查
第二个监控建议加 API 健康检查。很多项目交付时,前端页面正常不代表接口正常,所以要单独检查/healthz。
本地起一个简单健康接口:
mkdir -p ~/checkmate-demo/mock-api cd ~/checkmate-demo/mock-api cat > server.py <<'PY' from http.server import BaseHTTPRequestHandler, HTTPServer class Handler(BaseHTTPRequestHandler): def do_GET(self): if self.path == "/healthz": body = b'{"status":"ok"}' self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) else: self.send_response(404) self.end_headers() HTTPServer(("0.0.0.0", 8082), Handler).serve_forever() PY python3 server.pyCheckmate 里添加:
Name: Public API URL: http://host.docker.internal:8082/healthz Method: GET Expected Status: 200 Interval: 60s Timeout: 10s如果 Checkmate 支持响应内容校验,就把status":"ok作为关键字;如果当前版本只做状态码和响应时间,也足够完成演示。客户真正要看的不是每个字段,而是这个接口在验收期间有没有掉线,响应时间有没有明显波动。
用状态标签把页面整理成客户看得懂的样子
状态页最容易犯的错误,是把内部名字原样丢出去。
比如这些名字不适合给客户看:
prod-nginx-01 mysql-master-3306 redis-cache-a ssh-bastion admin-panel它们暴露了架构细节,还会引导客户问一些不该在验收会上展开的问题。更好的状态页命名是:
Customer Portal Public API Help Center File Preview Service Notification Service在 Checkmate 里可以按业务视角整理状态标签或分组:
Core Services - Customer Portal - Public API Support Services - Help Center - Notification Service状态标签也用客户语言:
Operational Degraded Maintenance Incident如果页面支持中文显示,可以写成:
正常运行 性能下降 维护中 故障处理中我更倾向验收页用中英文都能读懂的短词,减少会议里来回解释。重点是:客户一眼知道“服务能不能用”,团队成员一眼知道“要不要处理”。
打开公开状态页:客户看状态,不登录后台
接下来配置公开状态页。不同版本的 Checkmate 页面入口命名略有变化,思路一致:选择要展示的 monitors,生成一个 public status page,设置标题、说明、服务分组和展示项。
我会这样配置:
Page Title: Project Delivery Status Description: Demo status page for acceptance testing. No internal admin access is exposed. Visible Monitors: - Customer Portal - Public API - Help Center Show: - Current status - Response time - Recent incidents - Historical uptime这里别把所有监控都勾上。比如服务器 CPU、内存、磁盘、容器状态这类信息,就算 Checkmate 可以结合 agent 做展示,也不适合给客户临时演示。客户验收看的是服务可用性,不是你的机器资源曲线。
公开状态页保存后,先在本地浏览器打开确认:
http://localhost:52345/status/你的状态页路径确认页面只展示脱敏服务名、当前状态、历史可用率和事件记录。没有管理入口,没有服务器路径,没有环境变量,没有真实内网地址。
基础通知:给团队看,不一定给客户看
状态页是“展示”,通知是“处理”。演示环境里我一般只做一个基础通知,比如邮件、Webhook、Slack/Discord/飞书机器人中的一种。目的不是搭一个复杂告警平台,而是证明服务异常时团队会收到提醒。
以 Webhook 思路为例,配置项通常包括:
Notification Name: Delivery Demo Alert Trigger: Down / Recovery Target: 团队内部机器人 Webhook Message: Monitor name, status, time, response code这里要注意两点:
第一,Webhook 地址不要放到文章、截图和客户群。它等同于一个可调用入口。
第二,客户状态页里不需要展示通知配置。客户看到“历史事件”和“恢复时间”就够了;团队在内部群里收到告警,再按流程处理。
如果只是写库存教程,不接真实机器人,也可以在 Checkmate 里把通知配置走到保存前一步,用本地测试 Webhook 服务验证请求格式:
python3 -m http.server 9090正式项目中再换成团队内部的通知地址。
用 cpolar 开一个临时 HTTPS 状态页入口
本地状态页确认没问题后,再用 cpolar 暂时开放给客户。
先确认 Checkmate 本地端口:
curl -I http://localhost:52345启动 cpolar:
cpolar http 52345cpolar 会生成一个 HTTPS 地址,例如:
https://xxxx.cpolar.top这时候不要急着把根地址发出去。根地址通常能访问 Checkmate 登录页。更好的做法是把公开状态页路径拼完整,只发状态页地址:
https://xxxx.cpolar.top/status/project-delivery如果 Checkmate 页面里的链接、资源或 API 因为 origin 不一致报错,把 compose 里的CLIENT_HOST改成 cpolar 的 HTTPS 地址:
environment: CLIENT_HOST: https://xxxx.cpolar.top然后重启:
docker compose up -d再打开完整状态页地址检查一次。确认无误后,发给客户的话术可以很短:
这是本次验收用的临时服务状态页: https://xxxx.cpolar.top/status/project-delivery 页面只展示演示服务的运行状态和历史可用率,不包含后台管理入口。验收结束后我们会关闭临时访问地址。这个链接适合验收会、远程排障、短时间联调。它不适合当长期生产状态页使用。
演示一个短暂故障,再看历史可用率
为了让客户理解状态页不是静态页面,可以演示一次受控故障。
比如临时停掉 mock API:
# 找到 python server.py 的进程 ps aux | grep "server.py" # 结束对应进程 kill <PID>等 Checkmate 下一轮检查完成,Public API 会从正常变成异常。再重新启动接口:
cd ~/checkmate-demo/mock-api python3 server.py恢复后,状态页里就能看到这段异常和恢复记录。客户能看到“系统确实在监控,异常有记录,恢复也有记录”。这比口头说“我们有监控”可信得多。
如果不想在客户会上制造红色状态,也可以提前在内部演示一次,然后在正式会上展示历史记录。验收环境要稳,演示动作不要影响真实业务。
和 Uptime Kuma 的区别:不要把它们写成同一篇
Uptime Kuma 很适合个人服务器、NAS、小团队做 uptime 检查,操作路径短,社区资料也多。Checkmate 这篇我更看重三个点:
- 状态页表达更偏团队和交付场景;
- uptime、响应时间、事件、历史可用率放在同一个客户可读页面里;
- 后续还能扩展到服务器、Docker、基础设施监控,但本文只拿服务状态页做临时演示。
所以本文不去讲“Uptime Kuma 怎么迁移到 Checkmate”,也不比较谁更强。选型很简单:你要一个熟悉、极简、社区资料多的 uptime 工具,Uptime Kuma 够用;你想做一个更像交付看板的自托管状态页,Checkmate 值得试。
演示结束后的收尾动作
验收结束后,不要让临时公网入口一直挂着。
先停止 cpolar:
# 如果是在前台运行,按 Ctrl+C # 如果是后台进程,先查进程再结束 ps aux | grep cpolar kill <PID>再确认公网地址已经无法访问。然后按项目情况决定是否保留本地 Checkmate:
cd ~/checkmate-demo docker compose ps如果只是一次性演示,清理容器:
docker compose down如果还要保留历史数据,不要删除 volume。只有确认不再需要数据时,才执行:
docker compose down -v长期使用则换成正式方案:固定域名、HTTPS 证书、反向代理、账号权限、只读状态页、备份 MongoDB、告警分级、操作审计。cpolar 仍然适合临时远程验收,但不应该替代正式生产入口。
写在最后
我喜欢把 Checkmate 放在“客户能看懂的监控页”这个位置上,而不是把它写成又一个监控平台大而全教程。
本地部署负责数据和控制权,Checkmate 负责把服务状态、响应时间、历史可用率整理成页面,cpolar 负责在验收那一小时给出一个临时 HTTPS 入口。整个链路不复杂,但刚好解决了交付里最尴尬的问题:客户想看状态,团队又不想暴露后台。
记住边界就行:只展示状态页,只用脱敏服务名,只短时开放入口,验收结束关闭 cpolar。这样既能让客户安心,也不会把内网运维面板变成新的风险点。