用 Gatus 监控网站和 API:Docker 部署、YAML 配置与 Gotify 告警

用Docker Compose部署Gatus5.37.0,以YAML检查网站状态、页面内容和JSON接口,保存SQLite历史记录,接入Gotify故障与恢复通知,并说明SSH访问和常见配置问题。

土耳其 VDS,完整 root 权限|BRNCHOST · 自管服务器
建站开服,云上轻松起步|雨云 RCS · 宝塔 / 1Panel 预装
低价年付,搭起你的应用|RackNerd · KVM VPS · SSD 存储
香港轻量,按配置选型|晚安云 · 云服务器
NVMe 机型,关注磁盘 I/O|野草云 · 香港 VPS
大陆优化,连接海外应用|搬瓦工 · CN2 GIA / CTGNet 套餐
读文件、写文档、跑任务|WorkBuddy · AI 工作台
CVM 云主机,配置按需选|腾讯云 · 云服务器
中国方向优化,认准系列|DMIT · Premium / CN2 GIA
双 ISP 住宅 VPS|丽萨主机 · 原生 IP · 多地区产品
每周自动异地备份|Evoxt · 高频 CPU · 云服务器
京东云轻量云主机:2核2G,129元/年,新人限购1台

网站首页还能打开,API 却已经连不上数据库;反向代理返回了一个漂亮的错误页,监控只看 HTTP 200,结果仍然显示正常。配置监控时,需要写清检查地址、正常响应的内容,以及连续失败多少次才通知人。

Gatus 把这些规则写进 YAML。管理几个网站、一个订阅服务和两三个 API 时,可以把配置和其他运维文件一起保存,修改规则也能查看差异。下面以 Docker Compose 部署 Gatus 5.37.0,先监控网页与 JSON 接口,再接入 Gotify 通知。示例域名和接口都需要换成自己的地址。

先决定从哪里检查网站

监控程序放在哪里,会影响结果的含义。在网站所在的 VPS 上检查本机端口,看到的是应用内部是否响应;在另一台服务器上检查公开域名,看到的是从该服务器出发,经过 DNS、TLS 和反向代理后的访问结果。这两种检查可以同时保留,名称要区分清楚。

例如,把任务命名为“博客公开首页”和“博客内部健康接口”。公开首页异常、内部接口正常时,可以继续检查解析、证书与反向代理;两项都异常时,再去看应用、数据库和主机。这能缩小排查范围,具体原因仍需要结合日志判断。

只有一台 VPS 时,也可以先在本机运行 Gatus,补上对服务的检查。不过整台服务器断网或停止运行时,Gatus 也会一起停掉,它无法从已经离线的机器发出通知。重要站点至少安排一个外部检查点,并让通知渠道尽量避开同一个故障范围。

如果准备另租一台小机器做检查点,可以在雨云查看可用云服务器与区域,注册优惠码填写 KuZhuJi。选区域时看它能否代表需要观察的访问方向,不必为了监控程序专门购买高频 CPU 套餐;实际配置、流量费用与优惠适用范围看订单页。部署在境外的检查点,也不能代表所有中国大陆用户的访问情况。

Gatus 官方项目展示的深色状态页,可按分组查看不同端点的检查记录

建好目录,先把状态页留在本机

准备一台可以使用 SSH 的 Linux VPS,安装好 Docker Engine 和 Docker Compose 插件。本文使用 docker compose 命令;如果机器仍只有旧版 docker-compose,先按 Docker 的安装文档完成插件配置。还需要允许容器访问待监控的网站,以及后续使用的通知服务。

Gatus 的配置文件和检查数据分开保存:配置放在 config,SQLite 文件放在 data。先在自己的工作目录创建它们:

mkdir -p ~/gatus/config ~/gatus/data
cd ~/gatus

创建 compose.yaml:

services:
  gatus:
    image: ghcr.io/twin/gatus:v5.37.0
    restart: unless-stopped
    ports:
      - "127.0.0.1:8088:8080"
    environment:
      GATUS_CONFIG_PATH: /config/config.yaml
    volumes:
      - ./config:/config:ro
      - ./data:/data

这里固定版本,避免下一次拉取 stable 时顺带跨到新版本。官方 5.37.0 发布于 2026年9月24日;配置项可以对照对应版本的配置说明。将来升级时,先阅读新版本的变更,再调整镜像标签。

端口前面的 127.0.0.1 让宿主机只在本机地址监听8088。你不需要为了初次查看状态页,把8088端口开放给整个互联网。容器内仍使用8080,配置文件路径则由 GATUS_CONFIG_PATH 明确指定。config 挂载为只读,data 保持可写,用来保存检查记录。

如果8088已经被其他服务占用,修改宿主机端口,例如 127.0.0.1:8098:8080,后面的 SSH 转发也相应修改。不要把容器端口和宿主机端口当成同一个数字来处理。

第一条检查:HTTP 200 加上页面内容

创建 config/config.yaml:

storage:
  type: sqlite
  path: /data/gatus.db

endpoints:
  - name: 博客公开首页
    group: 网站
    url: https://blog.example.com/
    interval: 60s
    client:
      timeout: 10s
    conditions:
      - "[STATUS] == 200"
      - "[BODY] == pat(*我的技术笔记*)"

把 blog.example.com 换成自己的网站,把“我的技术笔记”换成响应 HTML 里实际存在的一段稳定文字。可以用站名,也可以用一个固定的页面标识;不要选每次请求都变化的数字、日期或随机推荐内容。

Gatus 的多个条件需要全部满足,任意一项失败都会让端点处于不健康状态。这个示例要求 HTTP 状态是200,并且响应正文包含指定文字。这样可以减少“返回的是错误页,但状态码仍然是200”的漏报。

pat 使用模式匹配,示例里的星号表示前后允许出现其他内容。它检查 HTTP 响应正文,不会启动浏览器执行 JavaScript。如果站名只在前端运行脚本之后才出现,原始 HTML 中没有这段文字,条件就会一直失败。这时应改用服务端响应中稳定存在的内容,或者检查专门提供的健康接口。

保存后执行:

docker compose config
docker compose up -d
docker compose logs --tail=80 gatus

docker compose config 检查的是 Compose 文件,不能代替 Gatus 对 config.yaml 的解析。启动日志如果报告 YAML 或条件表达式错误,先修正对应文件。日志里的请求失败也要分清原因:域名解析失败、TLS 校验失败和正文条件不成立,并不是同一种问题。

在自己的电脑上打开一个终端,建立 SSH 转发:

ssh -N -L 8088:127.0.0.1:8088 用户名@服务器IP

随后在本机浏览器访问 http://127.0.0.1:8088。这个终端需要保持运行;按 Ctrl+C 会关闭转发。若本机8088也被占用,可以使用 -L 8098:127.0.0.1:8088,浏览器访问本机8098。它不会改变服务器上的 Compose 配置。

API 检查要看接口实际返回了什么

公开首页正常,并不能证明登录、搜索或数据库查询也正常。应用已经有健康接口时,可以在同一份 endpoints 列表里加一项,例如:

  - name: API 健康检查
    group: 接口
    url: https://api.example.com/health
    interval: 60s
    client:
      timeout: 10s
    conditions:
      - "[STATUS] == 200"
      - "[BODY].status == UP"
      - "[RESPONSE_TIME] < 2000"

这个示例假设接口响应是 JSON,并且含有 "status":"UP"。Gatus 用 [BODY].status 读取相应字段。你的接口如果返回 "ok":true,条件就应写成 "[BODY].ok == true",不能把另一种接口的字段照搬过来。

响应时间条件的单位是毫秒,2000代表两秒。这是示例阈值,不能当成所有网站都适合的标准。跨区域检查可能受到线路影响;接口如果本来就执行较长的查询,过低的阈值会让它频繁报警。先明确这个接口应该完成什么,再决定多慢算异常。

健康接口本身也需要设计。如果它只是固定返回 UP,即使数据库已经不可用,也可能仍然显示正常。需要观察数据库访问的服务,可以让应用健康接口执行一项有限、可控的检查,再返回明确状态。不要让每分钟一次的探测触发全表扫描、发送邮件或创建订单。

需要鉴权的接口,可以使用端点的 headers 参数传入专用令牌。不要拿个人管理员令牌交给监控,也不要把令牌放进 URL 查询参数,使其更容易出现在日志里。接口权限只够读取健康状态即可;配置和环境文件应按秘密文件保管。

修改配置后,为了明确加载当前文件,可以执行:

docker compose restart gatus
docker compose logs --tail=80 gatus

官方也支持运行中重新加载配置。规则数量不多时,先用一次明确的重启和日志检查,确认改的是正在挂载的文件,而不是另一份留在旧目录的副本。

保存历史记录,别把检查结果数当成保留天数

Gatus 默认使用内存存储,重启后历史记录不会保留。前面已经改为 SQLite,数据库位于宿主机的 data 目录,因此正常重建容器不会顺带删掉它。还可以显式设置记录上限:

storage:
  type: sqlite
  path: /data/gatus.db
  maximum-number-of-results: 1440
  maximum-number-of-events: 100

这是替换原来的 storage 段,不是在同一文件末尾再增加第二个同名段。maximum-number-of-results 限制每个端点保存的结果数量,maximum-number-of-events 限制事件数量;它们不是统一的“保存多少天”。

按每分钟一条结果计算,1440条约对应一天,实际跨度还受检查调度、停机和配置调整影响。如果把间隔改成五分钟,同样的结果数会覆盖更长时间。保留记录用于近期排查即可,长期统计应另外考虑合适的存储和指标方案。项目支持 PostgreSQL,但几个端点的状态页没有必要仅为了更换数据库再维护一套额外服务。

定期保存配置,并给数据目录留一份备份。使用文件级复制保存 SQLite 数据时,停掉 Gatus 再归档,避免复制到正在变化的数据库文件;完成后及时启动:

cd ~/gatus
docker compose stop gatus
umask 077
tar -czf "$HOME/gatus-backup-$(date +%Y%m%d-%H%M%S).tar.gz" \
  compose.yaml config data
docker compose start gatus

备份放在工作目录之外,避免下次归档把旧备份也包进去。这个短暂停机期间不会产生新检查记录。归档内可能包含接口令牌或通知配置,不要放进公开网盘;如果还有 .env 等秘密文件,按实际使用方式单独妥善备份。复制回原目录之前,应保留现有文件,避免把最近的配置覆盖成旧版本。

用 Gotify 接收故障和恢复通知

Gatus 的通知配置分两层:全局定义通知发送到哪里,端点决定什么时候触发。只配置全局渠道,没有给端点添加 alerts,不会自动为每条检查创建同一套通知规则。

如果已经部署了 Gotify,在 Gotify 里为 Gatus 创建一个应用,使用该应用的令牌。Gotify 3 的令牌只在创建或轮换时显示一次,生成时妥善保存。用户令牌与应用令牌用途不同,发送消息应使用对应的应用令牌。在 Compose 服务中添加环境文件:

    env_file:
      - .env

它与 environment、volumes 同属 gatus 服务,不要添加到顶层。创建 .env,填写自己的值:

GOTIFY_SERVER_URL=https://notify.example.com
GOTIFY_APP_TOKEN=替换为Gotify应用令牌

限制文件读取权限:

chmod 600 .env

接着在 config/config.yaml 顶层添加:

alerting:
  gotify:
    server-url: "${GOTIFY_SERVER_URL}"
    token: "${GOTIFY_APP_TOKEN}"
    priority: 5

Gatus 支持在配置中展开环境变量。这里的变量位于挂载的 Gatus 配置文件,Compose 不负责读取这个文件的内容;不要把它与 Compose 自己对 compose.yaml 的变量替换混为一谈。

在需要通知的每个端点里,与 conditions 同级添加:

    alerts:
      - type: gotify
        failure-threshold: 3
        success-threshold: 2
        send-on-resolved: true
        minimum-reminder-interval: 1h
        description: "请检查网站、反向代理和应用日志"

连续三次失败才触发,连续两次成功才将已触发的故障标记为恢复,恢复时也发送消息。一小时的提醒间隔用于持续故障期间的重复提醒。官方允许设置提醒间隔,但不能低于五分钟;默认不启用重复提醒。具体字段见告警配置。

每分钟检查一次,并不意味着故障发生后恰好三分钟就能收到通知。首次失败是在下一次探测才发现,单次超时、调度与通知网络也会影响时间。提高失败阈值会减少偶发波动带来的告警,也会推迟通知。

添加或修改 .env 后,需要重新创建服务,让新的环境变量进入容器:

docker compose up -d --force-recreate gatus
docker compose logs --tail=80 gatus

只执行 restart 不会把修改后的容器环境变量重新注入。页面变红也不等于通知已经送达,应另看 Gotify 是否收到消息,以及 Gatus 日志是否记录了通知渠道错误。

Gatus 官方文档里的 Gotify 故障通知示例,响应时间超出条件后触发消息

状态页公开之前,先删掉不能公开的服务信息

私人运维页可能出现内网域名、后台地址、环境名称和服务分组。这些信息没有必要对所有访客开放。继续通过 SSH 转发访问即可;需要从浏览器直接通过域名访问时,再接入已有的 HTTPS 反向代理,并配置访问控制。

Gatus 5.37.0 提供 HTTP Basic 和 OIDC 配置。Basic 密码字段 password-bcrypt-base64 需要的是 bcrypt 哈希再做 Base64 编码的结果,不能填明文密码,也不能只将明文做 Base64 编码。若已经有统一的身份认证入口,可按安全配置接入,而不是临时把一个没有保护的状态页发布出去。

面向访客的公开状态页,则只放适合公开的服务名称和地址。即使网站状态正常,用户仍可能遇到某个功能、账号或地区的故障。状态页展示的是已设置规则的检查结果,不能代替所有功能的真实访问情况。

页面一直红时,按失败条件排查

状态码失败,先检查实际返回的是重定向、认证页、限流还是服务器错误。不要为了让格子变绿,就把条件放宽成所有状态都接受。正文失败时,检查原始响应是否真的包含匹配字段;动态页面、JSON 字段大小写变化和登录跳转,都可能让旧规则失效。

TLS 失败时,检查域名和证书配置。跳过证书校验可以掩盖真正的问题,不应作为公开网站 HTTPS 检查的默认处理。只有 Gatus 报超时、本机访问正常时,还要检查容器的 DNS、出站网络与检查点所在地区的线路。

容器内部的 127.0.0.1 指向容器自身,不是 VPS 宿主机。把应用的宿主机端口写成 http://127.0.0.1:3000 放进 Gatus 配置,并不能自动访问宿主机上的那个应用。公开站点检查直接使用公开域名;检查同一个 Docker 网络内的服务时,使用该网络中能够解析的服务名和容器端口。不要为了解决一次连不上,就把所有容器改成宿主机网络或开放数据库端口。

先放进一条首页检查和一条 API 检查,确认结果与接口内容一致,再接通知。后续添加服务时,把正常条件、通知对象和日志位置一起记录下来,收到通知就能找到对应的配置和排查入口。