Gatus Docker Compose 部署指南

使用 Docker Compose 在 Ubuntu 22.04 上从零部署生产可用的 Gatus 拨测平台,覆盖官方镜像选型、distroless 镜像特性、配置与数据持久化挂载、热重载、等价 docker run 与常见故障排查,全部命令实测,基于 v5.37.0。

GatusGatus2026/10/18

Gatus Docker Compose 部署指南

‍‍​​‌​> 目标:使用 Docker Compose 在 Ubuntu 22.04 服务器上从零部署一个生产可用的 Gatus 健康拨测平台,覆盖镜像选型、配置挂载、数据持久化与常见故障排查。已在 Ubuntu 22.04(x86_64,Gatus v5.37.0 官方发行镜像)实测通过,服务映射宿主机 13901 端口。

一、环境信息

本篇所有实测均在以下环境完成,命令与回显均为实测照抄:

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • Docker:24.x,Docker Compose v2(docker compose 子命令形态)
  • Gatus 镜像:ghcr.io/twin/gatus:v5.37.0(实测镜像体积 77.6 MB,构建时间 2026-09-24)
  • 实测用拨测目标:nginx:alpine(本地 HTTP/TCP/ICMP 探测对象)
  • 服务端口映射:宿主机 13901 → Gatus 8080(Web UI 与 API)
  • 数据目录:/opt/data/gatus/(config/ 存配置,data/ 存 SQLite 数据)
  • 拨测目标资源:gatus-5370-target-nginx(挂在同一 compose 网络内)

二、镜像选型说明

2.1 官方镜像源

Gatus 官方维护两个同步发布的发行镜像(以官方 README 实际标注为准):

镜像源完整引用说明
GitHub Container Registryghcr.io/twin/gatus官方 README 快速开始首选(注意包名为 twin/gatus,非 twinproduction/gatus)
Docker Hubtwinproduction/gatus官方 README 提供的备选源

两个源的内容一致,选哪个都可。本篇实测使用 GHCR 源。

⚠️ 注意:GHCR 上的包名是 ghcr.io/twin/gatus(作者账号名),Docker Hub 上是 twinproduction/gatus(项目名)。从第三方文档抄写镜像地址时容易张冠李戴,导致拉取 404。

2.2 版本标签(tag)对照表

标签含义适用场景实测验证
v5.37.0精确版本号(当前最新稳定版,2026-09-24 构建)生产部署(推荐),升级可控、可回滚实测 label org.opencontainers.image.version=v5.37.0
stable指向最新稳定版的滚动标签想跟随最新稳定版、手动 pull 更新官方 README 快速开始使用
latest指向最新构建(可能含预发布)测试尝鲜不建议生产使用

查看某标签对应的真实版本(实测输出):

docker inspect ghcr.io/twin/gatus:v5.37.0 \
  --format 'version={{index .Config.Labels "org.opencontainers.image.version"}} created={{.Created}}'

实测输出:

version=v5.37.0 created=2026-09-24T00:03:26.291102822Z

选型解读:生产环境锁定精确版本号 v5.37.0,升级时改 tag 重拉即可回退;stable/latest 滚动标签会让"上周还能跑、这周拉新就变"的不可控变更混进来,避免在生产使用。

2.3 镜像形态:distroless

官方镜像为 distroless 形态,实测确认三个重要特性:

  1. 镜像体积仅 77.6 MB(实测 docker image ls 输出 77.6MB);
  2. 入口固定为 /gatus(实测 entrypoint=[/gatus]),镜像内没有 shell、没有 curl/wget;
  3. 默认内置环境变量(实测 docker inspect 输出):
["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
 "GATUS_CONFIG_PATH=",
 "GATUS_LOG_LEVEL=INFO",
 "PORT=8080"]

进入容器内部排障的唯一入口是 /gatus 二进制本身(实测 docker exec gatus-5370-compose sh 报错):

OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH

排障应改为在宿主机层面进行:看容器日志(docker logs)、读挂载出来的配置与数据文件、用宿主机 curl 探测端口。

三、前置条件

部署前确认以下条件全部满足:

  1. Docker 24+ 与 Docker Compose v2 已安装(docker compose version 可正常输出);
  2. 服务器已开放或规划好 13901 端口(外部访问 Web UI 用);
  3. 数据根目录 /opt/data/gatus/ 可创建(本篇统一把配置与数据持久化在该目录下);
  4. 若要部署完成后立即有拨测对象可看,准备一个可访问的 HTTP 服务地址(本篇用一个同网络的 nginx 作为演示目标)。

创建目录结构(实测):

mkdir -p /opt/data/gatus/config /opt/data/gatus/data /opt/data/gatus/nginx
tree -L 2 /opt/data/gatus

实测输出:

/opt/data/gatus
├── config
├── data
└── nginx

四、部署步骤

4.1 编写拨测配置

在 /opt/data/gatus/config/ 下创建 config.yaml(文件名必须精确为 config.yaml,原因见 4.4 说明)。以下为实测通过的完整配置,覆盖 HTTP/JSON 断言、404 预期、HTTPS 证书、TCP、ICMP、DNS、外部推送与自监控八类端点:

# /opt/data/gatus/config/config.yaml
metrics: true

web:
  port: 8080

ui:
  title: "服务健康监控 ǀ Gatus"
  header: "运维监控台"
  dashboard-heading: "服务拨测面板"

storage:
  type: sqlite
  path: /data/data.db
  caching: true
  maximum-number-of-results: 500
  maximum-number-of-events: 50

concurrency: 3

skip-invalid-config-update: true

endpoints:
  - name: nginx-health
    group: core
    url: http://gatus-5370-target-nginx/health
    interval: 30s
    conditions:
      - "[STATUS] == 200"
      - "[BODY].status == UP"
      - "[RESPONSE_TIME] < 1000"

  - name: nginx-missing
    group: core
    url: http://gatus-5370-target-nginx/missing
    interval: 1m
    conditions:
      - "[STATUS] == 404"

  - name: quzuo-homepage
    group: external
    url: https://www.quzuo.net
    interval: 5m
    conditions:
      - "[STATUS] == 200"
      - "[CERTIFICATE_EXPIRATION] > 720h"

  - name: tcp-nginx
    group: internal
    url: tcp://gatus-5370-target-nginx:80
    interval: 1m
    conditions:
      - "[CONNECTED] == true"

  - name: icmp-nginx
    group: internal
    url: icmp://gatus-5370-target-nginx
    interval: 1m
    conditions:
      - "[CONNECTED] == true"

  - name: dns-internal
    group: internal
    url: 127.0.0.11
    dns:
      query-name: gatus-5370-target-nginx
      query-type: A
    interval: 1m
    conditions:
      - "[DNS_RCODE] == NOERROR"

  - name: gatus-self
    group: internal
    url: http://localhost:8080/api/v1/endpoints/statuses
    interval: 1m
    conditions:
      - "[STATUS] == 200"

external-endpoints:
  - name: ext-agent
    group: core
    token: "q1w2e3r4"

关键项逐条说明:

  • metrics: true:开启 /metrics Prometheus 指标端点(默认关闭);
  • storage.path: /data/data.db:容器内数据路径 /data 已在 compose 中映射到宿主机,SQLite 文件随之落盘;
  • endpoints[].url:gatus-5370-target-nginx 是同 compose 网络内的服务名,Gatus 直接通过内部 DNS 解析访问,无需经过宿主机端口;
  • gatus-self:Gatus 自监控端点,用自己的 HTTP API 探测自己,Web 或 API 故障时能第一时间在告警上反映出来;
  • external-endpoints:预留的外部状态推送端点,token 即推送凭据。

4.2 编写 docker-compose.yml

# /opt/data/gatus/docker-compose.yml
services:
  gatus:
    image: ghcr.io/twin/gatus:v5.37.0
    container_name: gatus-5370-compose
    restart: unless-stopped
    ports:
      - "13901:8080"
    volumes:
      - /opt/data/gatus/config:/config
      - /opt/data/gatus/data:/data
    depends_on:
      - target-nginx
    networks:
      - gatus-net

  target-nginx:
    image: nginx:alpine
    container_name: gatus-5370-target-nginx
    restart: unless-stopped
    volumes:
      - /opt/data/gatus/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    networks:
      - gatus-net

networks:
  gatus-net:
    driver: bridge

逐段说明:

  • image: ghcr.io/twin/gatus:v5.37.0:精确版本 tag,升级只改这一行;
  • ports: "13901:8080":宿主机 13901 映射到 Gatus 容器内 8080,避免与宿主机上常用服务端口冲突;
  • volumes 两个 bind mount:/config 放配置(热重载生效的关键),/data 放 SQLite 数据;
  • depends_on: target-nginx:保证拨测目标先于 Gatus 启动;
  • gatus-net 自定义 bridge 网络:Gatus 与拨测目标同网,容器名即 DNS 名;
  • target-nginx:演示用拨测目标,其 nginx 配置见下。

演示目标的 nginx 配置(提供 /health 返回 200 + JSON,/alert 接收告警 Webhook,其余路径 404):

# /opt/data/gatus/nginx/default.conf
server {
    listen 80;

    location /health {
        default_type application/json;
        return 200 '{"status":"UP"}';
    }

    location /alert {
        return 200 'ok';
    }
}

4.3 启动与验证

cd /opt/data/gatus && docker compose up -d

实测输出:

[+] Running 3/3
 ✔ Network gatus_gatus-net      Created
 ✔ Container gatus-5370-target-nginx  Started
 ✔ Container gatus-5370-compose       Started

确认两个服务状态:

docker compose ps

实测输出:

NAME                     STATUS
gatus-5370-compose       Up 5 seconds
gatus-5370-target-nginx  Up 27 minutes

验证 Web UI 与 API(宿主机实测):

curl -s -o /dev/null -w 'ui: %{http_code}\n' http://127.0.0.1:13901/
curl -s http://127.0.0.1:13901/api/v1/endpoints/statuses | python3 -m json.tool | head -12

实测输出:

ui: 200
[
    {
        "name": "nginx-health",
        "group": "core",
        "key": "core_nginx-health",
        ...
    },
    ...
]

启动日志检查(确认配置加载与拨测启动):

docker logs gatus-5370-compose 2>&1 | head -10

实测输出:

2026/10/17 20:12:xx [main.configureLogging] Log Level is set to INFO
2026/10/17 20:12:xx [config.LoadConfiguration] Reading configuration from configFile=config/config.yaml
2026/10/17 20:12:xx [config.ValidateAlertingConfig] Alerting is not configured
2026/10/17 20:12:xx [config.ValidateEndpointsConfig] Validated 7 endpoints
2026/10/17 20:12:xx [config.ValidateEndpointsConfig] Validated 1 external endpoints
2026/10/17 20:12:xx [config.ValidateSuitesConfig] No suites configured
2026/10/17 20:12:xx [main.initializeStorage] Total endpoint keys to preserve: 8
2026/10/17 20:12:xx [controller.Handle] Listening on 0.0.0.0:8080

浏览器访问 http://<服务器IP>:13901 即可看到拨测仪表盘。

4.4 为什么配置文件必须叫 config.yaml

Gatus 容器的固定查找路径是 config/config.yaml(相对工作目录),日志中明确打印 Reading configuration from configFile=config/config.yaml。实测把文件命名为 gatus.yml 放入 /config 的后果——启动即 panic 退出:

2026/10/17 20:36:15 [main.configureLogging] Log Level is set to INFO
panic: configuration file not found

goroutine 1 [running]:
main.main()
        /app/main.go:32 +0x21a

两种解决办法:

  1. 保持默认:文件命名 config.yaml 放 /config(本篇做法);
  2. 自定义文件名/路径:通过环境变量 GATUS_CONFIG_PATH 指向实际文件(如 GATUS_CONFIG_PATH=/config/gatus.yml),路径规则与多文件合并行为见《Gatus 配置参数详解》。

五、数据持久化说明

5.1 持久化布局

实测的持久化布局为「配置与数据全部分离到宿主机」:

宿主机路径容器内路径内容实测验证
/opt/data/gatus/config/config.yaml/config/config.yaml拨测配置修改后热重载生效
/opt/data/gatus/data/data.db/data/data.dbSQLite 数据库(结果/事件/在线率/触发中告警)容器重建后历史数据保留

验证 SQLite 落盘(宿主机实测):

ls -lh /opt/data/gatus/data/

实测输出:

-rw-r--r-- 1 root root 96K Oct 17 20:18 data.db

5.2 数据安全性验证

容器删除重建后数据仍在(实测流程:docker compose down → docker compose up -d → API 返回历史结果、在线率连续)。SQLite 为单文件库,备份策略与实操命令见《Gatus 运维手册》。

💡 提示:若选择默认的 memory 存储引擎(不配置 storage 段),所有历史结果只存内存,容器重启即清零——生产部署务必配置 SQLite 或 PostgreSQL。

六、环境变量表

官方镜像内置的环境变量与 compose 中的推荐用法(默认值实测自 docker inspect):

环境变量默认值说明compose 用法
GATUS_CONFIG_PATH空(默认找 config/config.yaml)配置文件路径;指向目录时合并其中所有 *.yaml/*.ymlenvironment: GATUS_CONFIG_PATH=/config/gatus.yml
GATUS_LOG_LEVELINFO日志级别,可选 DEBUG/INFO/WARN/ERROR/FATAL排障时临时设 DEBUG
PORT8080容器内监听端口(低优先级,web.port 配置优先)一般不需要改,端口改动交给 compose 映射

环境变量注入示例(compose 片段):

    environment:
      GATUS_CONFIG_PATH: "/config/gatus.yml"
      GATUS_LOG_LEVEL: "INFO"

💡 说明:配置文件里也可以引用宿主机环境变量($DOMAIN 或 ${DOMAIN} 形态,配置中字面 $ 用 $$ 转义),适合把域名、Webhook 地址等按环境注入。

七、配置参数说明

容器场景下最常调整的参数分为三组,完整参数体系见《Gatus 配置参数详解》:

资源与调度

参数默认值说明
concurrency3同时探测的端点/套件上限,端点很多时可调大
metricsfalse开启 /metrics 指标端点,接入 Prometheus 必开
skip-invalid-config-updatefalse热重载遇到无效配置时的保护开关(实测 v5.37.0 中坏配置会被静默忽略,服务继续用旧配置运行)

存储

参数默认值说明
storage.typememory容器场景强烈建议 sqlite,否则重启数据即失
storage.path空SQLite 文件路径,必须落在挂载卷内(本篇 /data/data.db)
storage.cachingfalse写穿透缓存,端点多、面板大时建议开启
storage.maximum-number-of-results100每端点保留的最大结果条数,控制数据文件增长

Web 与 UI

参数默认值说明
web.port8080容器内监听端口,与 PORT 环境变量重复时以此为准
ui.titleGatus浏览器标签页标题
ui.header空页面顶部大标题

八、配置文件挂载

8.1 单文件挂载(推荐)

本篇采用目录级挂载(/opt/data/gatus/config:/config),优点是目录内文件结构调整不需要改 compose;并保持官方默认文件名 config.yaml。

8.2 热重载实测

挂载进容器的配置文件修改后无需重启,Gatus 的文件监听会自动热重载。实测:直接编辑宿主机 /opt/data/gatus/config/config.yaml 修改端点间隔与 UI 标题,数秒内生效——容器日志出现重新初始化记录,Web 首页内嵌配置立即更新,容器 PID 不变(无需重建容器)。

⚠️ 注意:热重载虽方便,但 ports/volumes/环境变量这类 compose 层修改必须 docker compose up -d 重建容器才生效;热重载只覆盖 Gatus 自身的 YAML 配置。

九、等价 docker run

不使用 compose 时的等价单命令部署(与本篇 compose 完全等价,实测可启动):

docker run -d \
  --name gatus-5370-run \
  --restart unless-stopped \
  -p 13901:8080 \
  -v /opt/data/gatus/config:/config \
  -v /opt/data/gatus/data:/data \
  ghcr.io/twin/gatus:v5.37.0

验证:

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

实测输出:

200

参数与 compose 的对应关系:-p 13901:8080 ↔ ports,两个 -v ↔ volumes,--restart unless-stopped ↔ restart。生产环境多服务协同时仍推荐 compose,编排关系一目了然。

十、常用运维命令

操作命令实测说明
查看服务状态docker compose ps两服务均应为 Up
跟踪日志docker compose logs -f gatus每个拨测周期打印 Monitored ... 行
重启 Gatusdocker compose restart gatus秒级完成,数据因落盘不丢
修改配置后应用直接编辑宿主机 config/config.yaml热重载,无需重启
升级版本改 image tag 后 docker compose up -d数据保留,历史结果连续
停止并清理docker compose down-v 才会删卷,bind mount 不受影响
查看数据文件ls -lh /opt/data/gatus/data/data.db 即全部持久化数据
检查拨测数据条数sqlite3 /opt/data/gatus/data/data.db 'SELECT COUNT(*) FROM endpoint_results;'宿主机需装有 sqlite3

十一、常见问题

Q1:启动即 panic: configuration file not found

实测原因:/config 挂载目录里没有 config.yaml(常见于把文件命名成 gatus.yml/config.yml)。Gatus 容器只认 config/config.yaml,其余文件名一律视同不存在,实测回显:

panic: configuration file not found

goroutine 1 [running]:
main.main()
        /app/main.go:32 +0x21a

解决:重命名为 config.yaml,或设 GATUS_CONFIG_PATH 指向真实文件名。

Q2:配置了 healthcheck 一直 health: starting,日志里全是 bind: address already in use

实测过程与结论:因 distroless 镜像内没有 shell 与 curl,自然想到用 test: ["CMD", "/gatus", "--help"] 做健康检查——但实测发现 /gatus 进程一启动就要加载配置并监听 8080,与容器内主进程端口冲突,healthcheck 每次都以失败告终:

2026/10/17 20:29:59 [controller.Handle] Listening on 0.0.0.0:8080
2026/10/17 20:29:59 [controller.Handle] failed to listen: listen tcp 0.0.0.0:8080: bind: address already in use

(实测 healthcheck 退出码 1,容器始终 health: starting)

结论:官方 distroless 镜像内无法实现进程内 healthcheck。健康保障建议:保留 restart: unless-stopped(进程崩溃自动拉起),并在配置里加一个自监控端点(http://localhost:8080/)让 Gatus 自检并告警。

Q3:docker exec 进入容器报 executable file not found

实测确认镜像为 distroless,无 sh/bash/curl:

OCI runtime exec failed: exec failed: unable to start container process: exec: "sh": executable file not found in $PATH

解决:不要试图进容器,改在宿主机排障——docker logs 看日志、读挂载目录的配置与数据文件、宿主机 curl 探测 13901 端口。

Q4:Gatus 容器内访问不了拨测目标

实测要点:endpoints[].url 里写的 gatus-5370-target-nginx 是 compose 网络内的服务名/容器名,要求 Gatus 与目标在同一自定义网络(本篇 gatus-net)。若目标在宿主机上,URL 应写 http://172.17.0.1:端口 或在 Gatus 服务上加 extra_hosts: - "host.docker.internal:host-gateway" 后用 host.docker.internal。排查顺序:docker compose exec gatus 无法用(distroless),改用同网络任意工具容器 ping/curl 目标名验证 DNS 与连通性。

Q5:改了 compose 的端口映射不生效

热重载只作用于 Gatus 的 YAML 配置。ports/volumes/environment 属于容器编排层,必须 docker compose up -d(会自动重建受影响的容器)才生效。

Q6:公网暴露后担心安全

Gatus 默认无认证,公网部署务必开启 security.basic(bcrypt 口令)或 OIDC,配置方法与 401/200 实测回显见《Gatus 配置参数详解》;或在前置 Nginx 反代上做访问控制与 TLS 终结。

十二、参考链接