Gatus 运维手册

覆盖 Gatus v5.37.0 日常巡检、备份恢复、监控告警、扩容缩容、升级回滚与故障排查的完整运维闭环,全部命令与回显实测照抄。

GatusGatus2026/10/18

Gatus 运维手册

‍‍​​‌​> 目标:覆盖 Gatus v5.37.0 日常巡检、备份恢复、监控告警、扩容缩容、升级回滚与故障排查的完整运维闭环,全部命令与回显均在真实环境实测照抄。已在 Ubuntu 22.04(x86_64,Gatus v5.37.0,systemd 托管)实测通过。

一、环境信息

本篇所有操作均在以下环境实测,回显逐条照抄:

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • Gatus 版本:v5.37.0(二进制 /usr/local/bin/gatus,50876715 字节,版本确认方法见 六、6.1)
  • 运行方式:systemd 服务 gatus.service(Restart=on-failure,RestartSec=5),环境变量 GATUS_CONFIG_PATH=/opt/data/gatus-server/config.yaml
  • 存储:SQLite(/opt/data/gatus-server/data/data.db,WAL 模式),sqlite3 3.37.2
  • 端点:3 个 HTTP 端点(core_nginx-health 15s、core_nginx-missing 1m、自监控 ops_gatus-self 30s)+ 1 个外部推送端点(core_ext-agent)
  • 告警渠道:custom(HTTP POST,配置见《Gatus 配置参数详解》)
  • 实测期间的配置热重载、告警触发/解除、升级与回滚均为真实发生并留有日志

二、日常巡检

2.1 服务与端口巡检

systemctl status gatus --no-pager -l | head -12

实测输出(节选,CGroup 行略):

● gatus.service - Gatus Health Dashboard
     Loaded: loaded (/etc/systemd/system/gatus.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2026-10-17 20:45:56 UTC; 15min ago
   Main PID: 3433 (gatus)
      Tasks: 14 (limit: 5753)
     Memory: 13.4M
        CPU: 390ms

进程级内存与存活时间用 ps 观察(与 systemd 的 cgroup 统计口径不同,建议巡检时固定用同一种命令对比历史基线):

ps -o pid,rss,etime,args -p $(pidof gatus)

实测输出:

    PID   RSS     ELAPSED COMMAND
   3433  37732      15:28 /usr/local/bin/gatus

端口探活:最小化安装的系统常无 ss/netstat,直接用 HTTP 探测最可靠(进程在但不服务时也能发现,见 七、7.1):

curl -s -o /dev/null -m 3 -w '%{http_code}\n' http://127.0.0.1:8080/

实测输出:

200

2.2 拨测结果巡检

一条命令汇总所有端点的最近一次结果(API 细节见《Gatus API 使用详解》):

curl -s http://127.0.0.1:8080/api/v1/endpoints/statuses | python3 -c "
import json,sys
for ep in json.load(sys.stdin):
    r=ep['results'][-1] if ep['results'] else None
    print('%-24s %-6s %s' % (ep['key'], 'OK' if r and r.get('success') else 'FAIL', r['timestamp'] if r else 'n/a'))
"

实测输出:

core_ext-agent           OK     2026-10-17T20:50:54.013883228Z
core_nginx-health        OK     2026-10-17T21:17:44.093950836Z
core_nginx-missing       OK     2026-10-17T21:17:44.315556424Z
ops_gatus-self           OK     2026-10-17T21:17:14.541862094Z

巡检关注两点:FAIL 的端点,以及时间戳停滞的端点——core_ext-agent 是外部推送端点,其最后结果停在 20:50:54 说明外部推送方已停止推送(正常端点时间戳应随拨测间隔推进)。

2.3 日志巡检

journalctl -u gatus --no-pager -n 5

实测输出:

Oct 17 21:00:32 970d253b8646 gatus[3433]: 2026/10/17 21:00:32 [watchdog.executeEndpoint] Monitored group=core; endpoint=nginx-health; key=core_nginx-health; success=true; errors=0; duration=0s
Oct 17 21:00:47 970d253b8646 gatus[3433]: 2026/10/17 21:00:47 [watchdog.executeEndpoint] Monitored group=core; endpoint=nginx-health; key=core_nginx-health; success=true; errors=0; duration=0s
Oct 17 21:01:02 970d253b8646 gatus[3433]: 2026/10/17 21:01:02 [watchdog.executeEndpoint] Monitored group=core; endpoint=nginx-health; key=core_nginx-health; success=true; errors=0; duration=0s
Oct 17 21:01:02 970d253b8646 gatus[3433]: 2026/10/17 21:01:02 [watchdog.executeEndpoint] Monitored group=core; endpoint=nginx-missing; key=core_nginx-missing; success=true; errors=0; duration=0s
Oct 17 21:01:17 970d253b8646 gatus[3433]: 2026/10/17 21:01:17 [watchdog.executeEndpoint] Monitored group=core; endpoint=nginx-health; key=core_nginx-health; success=true; errors=0; duration=1ms

每行含 success=、errors=、duration=,巡检时抓失败行即可:

journalctl -u gatus --no-pager --since "2026-10-17 20:45" | grep -c "has been TRIGGERED"
journalctl -u gatus --no-pager --since "2026-10-17 20:45" | grep -c "has been RESOLVED"

实测输出(触发 4 行 = 2 次事故各打 2 行日志,解除 2 行):

4
2

2.4 存储巡检

ls -la /opt/data/gatus-server/data/
sqlite3 /opt/data/gatus-server/data/data.db "SELECT e.endpoint_key, COUNT(r.endpoint_result_id) FROM endpoint_results r JOIN endpoints e ON e.endpoint_id=r.endpoint_id GROUP BY 1;"

实测输出:

-rw-r--r-- 1 root root 114688 Oct 17 21:16 data.db
-rw-r--r-- 1 root root  32768 Oct 17 21:16 data.db-shm
-rw-r--r-- 1 root root 692192 Oct 17 21:16 data.db-wal
core_ext-agent|4
core_nginx-health|135
core_nginx-missing|43
ops_gatus-self|24

巡检要点:-wal 文件随写入波动(实测 667KB~992KB 均出现过)属正常现象,SQLite 以 WAL 模式运行(PRAGMA journal_mode 实测返回 wal);数据文件大小受 storage.maximum-number-of-results 保留上限控制(实测本例 500),行数不应无限增长。

2.5 巡检基线(实测参考值)

项目命令实测基线(3~13 个端点)
服务状态systemctl is-active gatusactive
Web 探活curl -w '%{http_code}'200
进程 RSSps -o rss= -p $(pidof gatus)36.8MB~42.5MB(随端点数浮动,见 五、5.1)
cgroup 内存systemctl status 的 Memory 行13.4M
数据文件ls -la data/data.db96KB~123KB(保留 500 条/端点内)
WAL 文件ls -la data/data.db-wal0~1MB 波动

三、备份与恢复

3.1 备份范围与 WAL 陷阱

需要备份的只有两样:配置文件与 SQLite 数据文件。直接 cp 数据文件有丢数据风险:Gatus 以 WAL 模式运行,最近的写入在 data.db-wal 中尚未合并(实测 WAL 一度达 992952 字节,而主文件仅 98304 字节),只拷主文件会丢掉 WAL 里的数据。两种安全做法:

  1. 在线备份:sqlite3 .backup(推荐,不停服务);
  2. 冷备:systemctl stop gatus 后拷贝整个 data/ 目录(含 WAL)。

3.2 在线备份(实测)

sqlite3 /opt/data/gatus-server/data/data.db ".backup '/tmp/gatus-data-backup.db'"
ls -la /tmp/gatus-data-backup.db
sqlite3 /tmp/gatus-data-backup.db "PRAGMA integrity_check; SELECT COUNT(*) FROM endpoint_results;"

实测输出:

-rw-r--r-- 1 root root 110592 Oct 17 21:02 /tmp/gatus-data-backup.db
ok
114

.backup 命令已将 WAL 内容合并进备份文件(110592 字节 > 主文件 98304 字节),integrity_check 返回 ok,服务全程未中断。

3.3 配置备份

cp -a /opt/data/gatus-server/config.yaml /tmp/gatus-config-$(date +%F).yaml

配置文件含告警渠道 token 等敏感信息,备份文件的权限与存放位置按敏感数据处理(本例实测 ls -la 显示 -rw-r--r--,生产建议收紧为 600)。

3.4 恢复演练(实测)

用 3.2 的备份文件完整演练一次恢复:

systemctl stop gatus
rm -f /opt/data/gatus-server/data/data.db-wal /opt/data/gatus-server/data/data.db-shm
cp /tmp/gatus-data-backup.db /opt/data/gatus-server/data/data.db
systemctl start gatus

验证(实测输出):

systemctl is-active gatus
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/api/v1/endpoints/statuses
sqlite3 /opt/data/gatus-server/data/data.db "SELECT COUNT(*) FROM endpoint_results;"
active
200
116

恢复成功:行数从备份时刻的 114 继续增长到 116(服务启动后立即补了两轮拨测)。注意恢复前必须删除旧 WAL/SHM 文件,否则旧 WAL 会与新恢复的主文件错配。

3.5 备份策略建议

  • 配置文件:每次修改前后各存一版(本篇排障多次依赖 /tmp/config-good.yaml 式的快速回退),并纳入定期备份;
  • 数据文件:sqlite3 .backup 每日一次即可(数据是拨测历史,丢失只影响在线率曲线,不影响功能);历史在线率也可改从 API 导出归档(见《Gatus API 使用详解》);
  • 升级前:二进制、配置、数据三样全部备份(见 六、6.6)。

四、监控告警

4.1 给 Gatus 配自监控端点

Gatus 自身的 Web 服务停摆不会体现在任何业务端点上(见 七、7.1 的实测事故),必须让 Gatus 拨测自己。在 config.yaml 的 endpoints: 列表中加入(本环境实测配置):

  - name: gatus-self
    group: ops
    url: http://127.0.0.1:8080/api/v1/endpoints/statuses
    interval: 30s
    conditions:
      - "[STATUS] == 200"
    alerts:
      - type: custom
        description: "Gatus 自监控异常(Web 停摆)"

保存后无需重启,配置监听到变更后自动生效(实测日志):

Oct 17 21:03:17 970d253b8646 gatus[3717]: 2026/10/17 21:03:17 [main.listenToConfigurationFileChanges] Configuration file has been modified
Oct 17 21:03:17 970d253b8646 gatus[3717]: 2026/10/17 21:03:17 [watchdog.monitorEndpoint] Canceling current execution of group=core; endpoint=nginx-health; key=core_nginx-health
Oct 17 21:03:17 970d253b8646 gatus[3717]: 2026/10/17 21:03:17 [controller.Handle] Server has shut down successfully
Oct 17 21:03:17 970d253b8646 gatus[3717]: 2026/10/17 21:03:17 [watchdog.monitorEndpoint] Canceling current execution of group=core; endpoint=nginx-missing; key=core_nginx-missing
Oct 17 21:03:18 970d253b8646 gatus[3717]: 2026/10/17 21:03:18 [config.LoadConfiguration] Reading configuration from configFile=/opt/data/gatus-server/config.yaml
Oct 17 21:03:18 970d253b8646 gatus[3717]: 2026/10/17 21:03:18 [config.ValidateEndpointsConfig] Validated 3 endpoints
Oct 17 21:03:18 970d253b8646 gatus[3717]: 2026/10/17 21:03:18 [config.ValidateEndpointsConfig] Validated 1 external endpoints
Oct 17 21:03:18 970d253b8646 gatus[3717]: 2026/10/17 21:03:18 [controller.Handle] Listening on 0.0.0.0:8080

新端点随即出现在 API 中(实测 ops_gatus-self 首条结果 success: true、hostname: "127.0.0.1"、duration: 2517031 纳秒)。

注意热重载序列中的 Server has shut down successfully:每次重载都会先关 Web 再重启,这是一切热重载事故的源头(见 七、7.1)。此外配置变更的监听延迟不固定(实测同环境从 1 秒到约 57 秒不等),改配置后以这条日志为准,见 七、7.4。

4.2 自监控告警实录(实测)

2026-10-17 21:06 排障实验中故意注入坏配置,Web 停摆,自监控端点立刻抓到并触发告警:

Oct 17 21:06:55 970d253b8646 gatus[3717]: 2026/10/17 21:06:55 [watchdog.handleAlertsToTrigger] Sending custom alert because alert for endpoint with key=ops_gatus-self with description='Gatus 自监控异常(Web 停摆)' has been TRIGGERED
Oct 17 21:06:55 970d253b8646 gatus[3717]: 2026/10/17 21:06:55 [watchdog.handleAlertsToTrigger] Sending initial custom alert because alert for endpoint=gatus-self with description='Gatus 自监控异常(Web 停摆)' has been TRIGGERED

配置修复后服务自愈,告警自动解除:

Oct 17 21:08:26 970d253b8646 gatus[3717]: 2026/10/17 21:08:26 [main.listenToConfigurationFileChanges] Configuration file has been modified
Oct 17 21:08:27 970d253b8646 gatus[3717]: 2026/10/17 21:08:27 [config.LoadConfiguration] Reading configuration from configFile=/opt/data/gatus-server/config.yaml
Oct 17 21:08:27 970d253b8646 gatus[3717]: 2026/10/17 21:08:27 [controller.Handle] Listening on 0.0.0.0:8080
Oct 17 21:08:57 970d253b8646 gatus[3717]: 2026/10/17 21:08:57 [watchdog.handleAlertsToResolve] Sending custom alert because alert for endpoint with key=ops_gatus-self with description='Gatus 自监控异常(Web 停摆)' has been RESOLVED

TRIGGERED 21:06:55 → RESOLVED 21:08:57,闭环完整。触发态持久化在 SQLite 中(endpoint_alerts_triggered 表),进程重启不会丢告警状态。

4.3 Prometheus 指标

配置 metrics: true 后 GET /metrics 暴露 Prometheus 指标。实测指标族共 5 个(重启后立刻抓取):

# HELP gatus_results_code_total Total number of results by code
# TYPE gatus_results_code_total counter
# HELP gatus_results_connected_total Total number of results in which a connection was successfully established
# TYPE gatus_results_connected_total counter
# HELP gatus_results_duration_seconds Duration of the request in seconds
# TYPE gatus_results_duration_seconds gauge
# HELP gatus_results_endpoint_success Displays whether or not the endpoint was a success
# TYPE gatus_results_endpoint_success gauge
# HELP gatus_results_total Number of results per endpoint
# TYPE gatus_results_total counter

实测系列样例:

gatus_results_code_total{code="200",group="core",key="core_nginx-health",name="nginx-health",type="HTTP"} 1
gatus_results_duration_seconds{group="core",key="core_nginx-health",name="nginx-health",type="HTTP"} 0.00094434
gatus_results_endpoint_success{group="core",key="core_nginx-health",name="nginx-health",type="HTTP"} 1
gatus_results_total{group="core",key="core_nginx-health",name="nginx-health",success="true",type="HTTP"} 1

实测要点:grep -cE '^gatus_' 重启后为 10(2 个被拨测端点 × 5 个指标族);counter 类指标随进程运行累计,进程重启后归零,长期趋势图须用 rate()/increase() 而非绝对值;外部推送端点(external-endpoints)不产生这些 HTTP 拨测指标(实测确认)。

4.4 告警渠道与维护窗口

  • 告警渠道配置与触发阈值实测见《Gatus 配置参数详解》(custom 渠道全链路 TRIGGERED/RESOLVED 实测);
  • 端点侧必须显式声明 alerts: - type: custom 才会告警,default-alert 只是模板(实测踩坑记录见同篇);
  • 维护窗口(maintenance 段)只抑制告警不暂停拨测(实测),升级期间不希望收告警时用它。

五、扩容缩容

5.1 扩容实测(3 端点 → 13 端点)

向配置追加 10 个端点(group: bench,interval: 10s,指向同一目标),热重载生效后实测:

ps -o rss= -p $(pidof gatus)          # 扩容前:36856
sleep 45
ps -o rss= -p $(pidof gatus)          # 扩容后:40092
curl -s http://127.0.0.1:8080/api/v1/endpoints/statuses | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d), sum(len(x['results']) for x in d if x['group']=='bench'))"
sqlite3 /opt/data/gatus-server/data/data.db "SELECT COUNT(*) FROM endpoint_results;"

实测输出:

36856
40092
14 30
176

结论:10 个 10s 间隔端点(每秒约 1 次拨测)增加 RSS 约 3.2MB,45 秒内产生 30 条结果,endpoint_results 增长到 176 行。每增加 10 个高频端点按个位数 MB 估算内存即可(官方 README 对资源消耗的描述为 "negligibly small",实测相符)。

5.2 缩容与内存释放

移除这 10 个端点后实测:端点数回落到 4,但 RSS 不回落(实测仍为 42484KB)——Go 运行时保留已分配内存,这是正常现象。判断依据应看增量后的稳态值;确需立即释放(如长期驻留了扩容期峰值)就重启服务:

systemctl restart gatus && sleep 5 && ps -o rss= -p $(pidof gatus)

5.3 存储保留与手工收缩

保留上限由 storage.maximum-number-of-results / maximum-number-of-events 控制(默认 100/50),改小不会立即收缩历史数据(实测行为见《Gatus 配置参数详解》)。需要立即收缩时停服手工处理(实测):

systemctl stop gatus
sqlite3 /opt/data/gatus-server/data/data.db "PRAGMA wal_checkpoint(TRUNCATE); DELETE FROM endpoint_results WHERE endpoint_id=(SELECT endpoint_id FROM endpoints WHERE endpoint_key='core_nginx-health') AND endpoint_result_id NOT IN (SELECT endpoint_result_id FROM endpoint_results WHERE endpoint_id=(SELECT endpoint_id FROM endpoints WHERE endpoint_key='core_nginx-health') ORDER BY timestamp DESC LIMIT 50); VACUUM; PRAGMA page_count; PRAGMA freelist_count;"
ls -la /opt/data/gatus-server/data/
systemctl start gatus

实测输出:

0|0|0
28
0
-rw-r--r-- 1 root root 114688 Oct 17 21:16 data.db

验证:服务恢复 active、API 返回 200,core_nginx-health 行数实测 51(保留 50 + 启动后新一轮)。实测结论:WAL 截断是主要回收手段(WAL 从 692192 字节归零);Gatus 自身的周期清理使 freelist 常年为 0,VACUUM 在小库上收益有限(page_count 30→28),大批量手工删除后才明显。

六、升级与回滚

6.1 版本确认

Gatus 没有 --version 参数(实测传参只会正常启动服务),也没有版本 API(实测 curl http://127.0.0.1:8080/api/v1/version 返回 404 与 Cannot GET /api/v1/version)。可靠的两条确认途径:

途径一,go version -m(需要 Go 环境,实测输出):

go version -m /usr/local/bin/gatus | head -3
/usr/local/bin/gatus: go1.26.9
        path    github.com/TwiN/gatus/v5
        mod     github.com/TwiN/gatus/v5        v5.37.0 h1:LlOlToOmKIqNaffPQzGq9FBiSi998jmcCobgoi/t0V8=

途径二,无需任何工具:启动失败时的 panic 堆栈自带版本(实测日志):

/root/go/pkg/mod/github.com/!twi!n/gatus/v5@v5.37.0/main.go:32

6.2 官方分发形态与编译环境

官方 GitHub Release 不提供预编译二进制(实测 v5.37.0 release 资产列表仅有 Source code (zip) 与 Source code (tar.gz) 两项),官方 README 的二进制安装方式即编译安装:

go install github.com/TwiN/gatus/v5@latest

因此升级 = 用 Go 编译新版本并替换二进制。编译环境实测(Ubuntu 22.04 上安装 Go 1.26.9):

curl -sL -o /tmp/go1.26.9.linux-amd64.tar.gz https://mirrors.aliyun.com/golang/go1.26.9.linux-amd64.tar.gz
tar -C /usr/local -xzf /tmp/go1.26.9.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version

实测输出:

go version go1.26.9 linux/amd64

编译走模块代理加速:export GOPROXY=https://goproxy.cn,direct。

6.3 升级演练环境(隔离实测)

以下升级与回滚均在独立演练目录完成(端口 8081、独立 SQLite,主服务不受影响,演练后主服务实测仍为 active/200)。演练配置:

web:
  port: 8081
storage:
  type: sqlite
  path: /opt/gatus-upgrade-lab/data.db
endpoints:
  - name: lab-target
    group: lab
    url: http://gatus-5370-target-nginx/health
    interval: 10s
    conditions:
      - "[STATUS] == 200"

6.4 升级实测(v5.36.0 → v5.37.0)

先编译安装上一版本 v5.36.0 并运行(实测版本信息与运行状态):

go install github.com/TwiN/gatus/v5@v5.36.0
go version -m /root/go/bin/gatus | grep "mod "

实测输出:

mod     github.com/TwiN/gatus/v5        v5.36.0 h1:htpXnA4ESSqarxy1hRhrQLsyfp6Q30vb3X/yDC3Cb80=
GATUS_CONFIG_PATH=/opt/gatus-upgrade-lab/config.yaml /opt/gatus-upgrade-lab/gatus-v5.36.0 &
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/api/v1/endpoints/statuses
sqlite3 /opt/gatus-upgrade-lab/data.db "SELECT COUNT(*) FROM endpoint_results;"

实测输出(运行约 12 秒后):

200
2

然后编译 v5.37.0(实测 go version -m 输出 mod github.com/TwiN/gatus/v5 v5.37.0 h1:LlOlToOmKIqNaffPQzGq9FBiSi998jmcCobgoi/t0V8=),停旧进程、换二进制、原库重启:

GATUS_CONFIG_PATH=/opt/gatus-upgrade-lab/config.yaml /opt/gatus-upgrade-lab/gatus-v5.37.0 &
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/api/v1/endpoints/statuses
sqlite3 /opt/gatus-upgrade-lab/data.db "SELECT COUNT(*) FROM endpoint_results;"

实测输出:

200
4

升级实测结论:同一数据文件直接跨版本启动,无迁移报错、无数据丢失(2 行历史保留,继续写入 2 行),启动日志仅 Listening on 0.0.0.0:8081,与《Gatus Docker Compose 部署指南》中升级版本的实测行为一致。

6.5 回滚实测(v5.37.0 → v5.36.0)

同一数据文件直接换回 v5.36.0 二进制启动:

GATUS_CONFIG_PATH=/opt/gatus-upgrade-lab/config.yaml /opt/gatus-upgrade-lab/gatus-v5.36.0 &
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/api/v1/endpoints/statuses
sqlite3 /opt/gatus-upgrade-lab/data.db "SELECT COUNT(*) FROM endpoint_results;"

实测输出:

200
6

实测结论:v5.36.0 可正常打开 v5.37.0 写过的数据文件并继续拨测(日志恢复 Monitored group=lab; ... success=true),同 5.x 小版本系列内二进制回滚可行。跨大版本回滚前仍应先做 3、的完整备份,不要依赖未实测的降级路径。

6.6 主服务标准升级步骤

结合以上实测,主服务升级清单(版本号替换为目标版本):

# 1. 备份(配置+数据+二进制,见 三、)
cp -a /opt/data/gatus-server/config.yaml /tmp/gatus-config-$(date +%F).yaml
sqlite3 /opt/data/gatus-server/data/data.db ".backup '/tmp/gatus-data-pre-upgrade.db'"
cp -a /usr/local/bin/gatus /usr/local/bin/gatus.bak

# 2. 编译新版本并核对版本号
go install github.com/TwiN/gatus/v5@v5.38.0
go version -m /root/go/bin/gatus | grep "mod "

# 3. 替换并重启
systemctl stop gatus
install -m 755 /root/go/bin/gatus /usr/local/bin/gatus
systemctl start gatus

# 4. 验证清单
systemctl is-active gatus                     # active
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/api/v1/endpoints/statuses   # 200
sqlite3 /opt/data/gatus-server/data/data.db "SELECT COUNT(*) FROM endpoint_results;"       # 行数延续
journalctl -u gatus --no-pager -n 20 | grep -iE "error|panic"                              # 无异常

回滚 = systemctl stop gatus && cp -a /usr/local/bin/gatus.bak /usr/local/bin/gatus && systemctl start gatus(6.5 实测可行)。

七、故障排查手册

7.1 进程 active 但 8080 拒绝连接(热重载失败停摆)

现象:systemctl is-active 返回 active,curl 却连接拒绝。实测复现(向配置追加一个与现有 external-endpoints 重名的条目):

Oct 17 21:06:56 970d253b8646 gatus[3717]: 2026/10/17 21:06:56 [config.LoadConfiguration] Reading configuration from configFile=/opt/data/gatus-server/config.yaml
Oct 17 21:06:56 970d253b8646 gatus[3717]: 2026/10/17 21:06:56 [main.listenToConfigurationFileChanges] Failed to load new configuration: error parsing config: invalid external endpoint core_ext-agent: name and group combination must be unique
Oct 17 21:06:56 970d253b8646 gatus[3717]: 2026/10/17 21:06:56 [main.listenToConfigurationFileChanges] The configuration file was updated, but it is not valid. The old configuration will continue being used.
systemctl is-active gatus
curl -s -m 3 -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8080/

实测输出:

active
000

根因:热重载流程是「先关 Web → 加载新配置」,校验失败后旧配置继续拨测,但 Web 服务不再重启,UI 与 API 全部停摆。行为链完整实测见《Gatus 配置参数详解》(skip-invalid-config-update: true 已配置时同样发生)。此时唯一可靠的捕获手段是 4.1 的自监控端点——本次事故中它实时触发了告警(4.2 实录)。

处置:把配置改对(或恢复备份),监听到正确文件后服务自愈,无需重启进程(实测 21:08:27 自动重新 Listening on 0.0.0.0:8080,curl 恢复 200)。应急快速恢复用配置备份:

cp /tmp/config-good.yaml /opt/data/gatus-server/config.yaml

预防:改配置前先在临时目录跑 GATUS_CONFIG_PATH=<新文件> gatus 验证能正常启动;热重载生效前盯一眼日志里有无 Failed to load new configuration。

7.2 启动 panic: configuration file not found

配置文件路径不存在时启动直接 panic(实测:停服后把配置文件移走再启动):

Oct 17 21:09:42 970d253b8646 gatus[3874]: panic: configuration file not found
Oct 17 21:09:42 970d253b8646 gatus[3874]: goroutine 1 [running]:
Oct 17 21:09:42 970d253b8646 gatus[3874]: main.main()
Oct 17 21:09:42 970d253b8646 gatus[3874]:         /root/go/pkg/mod/github.com/!twi!n/gatus/v5@v5.37.0/main.go:32 +0x209
Oct 17 21:09:42 970d253b8646 systemd[1]: gatus.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Oct 17 21:09:42 970d253b8646 systemd[1]: gatus.service: Failed with result 'exit-code'.

两个实测细节值得注意:

  1. GATUS_CONFIG_PATH 指向的文件名必须精确——把 config.yaml 误命名为 gatus.yml 等都会触发本 panic(实测《Gatus Docker Compose 部署指南》同款案例);
  2. 在 Restart=on-failure 下这不是一次性失败:每 5 秒重启再 panic,unit 状态停留在 activating(实测 systemctl is-active 与 is-failed 均返回 activating),基于 is-failed 的监控不会报警,必须靠端口探活。

处置:恢复配置文件后 systemctl restart gatus,实测立即恢复 active 与 200。

7.3 TLS 证书校验失败(x509)

拨测自签/过期证书的目标时,端点失败且 UI 显示 errors(实测 ops_tls-badssl 端点拨测 self-signed.badssl.com,API 返回照抄):

{
  "hostname": "self-signed.badssl.com",
  "duration": 905156670,
  "errors": [
    "Get \"https://self-signed.badssl.com/\": tls: failed to verify certificate: x509: certificate signed by unknown authority"
  ],
  "conditionResults": [
    {
      "condition": "[STATUS] (0) == 200",
      "success": false
    }
  ],
  "success": false,
  "timestamp": "2026-10-17T21:12:19.875776064Z"
}

x509: certificate signed by unknown authority 即系统 CA 库不信任该证书链,且 status 渲染为 (0)(未收到 HTTP 响应)。处置分两种:

  • 内部自签服务:给该端点加 client: {insecure: true} 跳过校验(仅限内网可信目标,参数见《Gatus 配置参数详解》);
  • 公共站点报错:说明本机系统 CA 过旧,apt install --only-upgrade ca-certificates 升级。注意 Go 程序在启动时加载 CA 池,升级 CA 后必须重启 Gatus 进程才生效(实测:升级 CA 并更新证书后不重启仍失败,重启后恢复)。

7.4 改了配置迟迟不生效(配置监听延迟)

配置变更监听的延迟不固定,实测同环境三次变更的「写入 → 日志出现 Configuration file has been modified」间隔分别为约 57 秒、11 秒、1 秒。改配置后:

journalctl -u gatus --no-pager -n 10 | grep -E "modified|Failed to load|Listening"

看到 modified 且无 Failed to load 才算生效;对生效时间敏感的变更(如调整 interval)宁可 systemctl restart gatus。

7.5 存储文件一直不变小

maximum-number-of-results 改小后旧数据由后台周期清理,不立即收缩;手工清理与 WAL 截断见 五、5.3 实测。日常巡检以 2.4 的行数统计为准,只要行数在保留上限内即正常。

八、常见问题

Q1:Web 服务监听在哪,公网能直接访问吗

实测启动日志为 Listening on 0.0.0.0:8080(全地址监听)。生产环境务必配合防火墙限制来源,并启用 Basic 认证(实测 401/200 行为见《Gatus 配置参数详解》)或置于反向代理之后。

Q2:巡检时 systemctl status 显示的 Memory 与 ps 的 RSS 差很多

两个口径不同(cgroup 统计 vs 进程常驻内存),实测分别为 13.4M 与约 37MB。趋势判断选定一种命令固定对比即可,勿混用。

Q3:重启进程后 Prometheus 图表断了

counter 类指标随进程重启归零(4.3 实测),图表层用 rate()/increase() 处理,重启造成的断点属预期行为。

Q4:ss、netstat 都不存在怎么探活

最小化系统常不带这些工具,直接 curl -s -o /dev/null -m 3 -w '%{http_code}\n' http://127.0.0.1:8080/(2.1 实测),比端口工具更能发现「进程在但不服务」的假活状态。

九、参考链接