Gatus Service Monitoring: Deploy a Developer-Focused Status Page in Docker

Step-by-step tutorial to setting up Gatus using Docker Compose. Monitor your service health, response times, and configure alerts via Discord or Telegram.

Core Architecture and Prerequisites

Before deploying Gatus, ensure you have: * A VPS running a Linux distribution (e.g., Ubuntu 22.04 LTS/24.04 LTS). * Docker Engine (v20.10+) and Docker Compose (v2.0+) installed. * A domain name pointing to your VPS IP address (optional but recommended for SSL setup).

Gatus runs as a single binary inside a lightweight Alpine-based container. In a standard self-hosted environment, you will deploy: 1. Gatus: The core monitoring engine. 2. Reverse Proxy (Caddy/Nginx): To handle SSL termination (HTTPS). 3. Database (Optional): Gatus uses SQLite for persistent metrics.


The Docker Compose Configuration

Create a dedicated directory for your Gatus deployment and create a docker-compose.yml file:

version: '3.8'

services:
  gatus:
    image: twinproduction/gatus:latest
    container_name: gatus
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./config:/config
      - ./data:/data
    environment:
      - TZ=UTC
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 256M

Ensure the configuration directory exists and set correct permissions:

mkdir -p config data
touch config/config.yaml

Configuring Gatus (config.yaml)

Gatus configuration uses a single YAML file. The configuration is divided into three primary blocks: 1. Web Server: Port, path, security, and UI customisation. 2. Alerting: Integrations for notifications. 3. Endpoints: The health checks themselves.

Below is a production-ready config.yaml using SQLite for persistence:

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

web:
  port: 8080

ui:
  title: "System Status"
  header: "Service Health Dashboard"
  buttons:
    - name: "Homepage"
      link: "https://example.com"

# Global alerting defaults
alerting:
  telegram:
    token: "${TELEGRAM_BOT_TOKEN}"
    id: "${TELEGRAM_CHAT_ID}"
    default-alert:
      enabled: true
      failure-threshold: 3
      success-threshold: 2
      send-on-resolved: true

  discord:
    webhook-url: "${DISCORD_WEBHOOK_URL}"
    default-alert:
      enabled: true
      failure-threshold: 3
      success-threshold: 2
      send-on-resolved: true

# Monitoring target definitions
endpoints:
  - name: API Gateway
    group: Core Services
    url: https://api.example.com/health
    interval: 30s
    conditions:
      - "[STATUS] == 200"
      - "[RESPONSE_TIME] < 500"
      - "[BODY].status == up"
    alerts:
      - type: telegram
        send-on-resolved: true

  - name: Public Website
    group: Websites
    url: https://example.com
    interval: 60s
    conditions:
      - "[STATUS] == 200"
      - "[RESPONSE_TIME] < 1000"
    alerts:
      - type: discord

  - name: Database Port (TCP)
    group: Infrastructure
    url: tcp://db.example.com:5432
    interval: 30s
    conditions:
      - "[CONNECTED] == true"

  - name: DNS Resolution Check
    group: Infrastructure
    url: dns://8.8.8.8:53/google.com?type=A
    interval: 60s
    conditions:
      - "[DNS_RCODE] == NOERROR"

Detailed Endpoint Checking Syntax

Gatus supports a rich query language for validation checks. Here are standard patterns for different protocols.

1. HTTP/HTTPS Checks

Evaluate status codes, response latency, certificates, and JSON payload values:

endpoints:
  - name: Secure Endpoint Check
    url: https://api.example.com/v1/users
    method: POST
    body: '{"username": "gatus-monitor"}'
    headers:
      Content-Type: application/json
      Authorization: Bearer my-secure-token
    conditions:
      - "[STATUS] == 201"
      - "[RESPONSE_TIME] < 800"
      - "[CERTIFICATE_EXPIRATION] > 48h"
      - "[BODY].id != null"

2. TCP Port Checks

Verify that infrastructure daemons (e.g., SSH, PostgreSQL, Redis) are listening:

endpoints:
  - name: SSH Server
    url: tcp://10.0.0.5:22
    interval: 10s
    conditions:
      - "[CONNECTED] == true"

3. DNS Verification

Query a name server and validate response records:

endpoints:
  - name: Primary DNS Resolver
    url: dns://1.1.1.1:53/example.com?type=A
    interval: 30s
    conditions:
      - "[DNS_RCODE] == NOERROR"
      - "[DNS_IP] == 93.184.216.34"

4. ICMP Ping Checks

Simple network accessibility tests:

endpoints:
  - name: Router Gateway
    url: icmp://192.168.1.1
    interval: 15s
    conditions:
      - "[CONNECTED] == true"
      - "[RESPONSE_TIME] < 50"

Configuring Notification Alerting

Integrate Gatus with Telegram and Discord to receive real-time notifications on failures and resolutions.

Telegram Alert Setup

  1. Message @BotFather on Telegram to create a new bot and retrieve the Bot Token.
  2. Start a chat with your bot, then retrieve the Chat ID by querying updates: bash curl -s https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates | jq .
  3. Update config.yaml: yaml alerting: telegram: token: "123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ" id: "987654321"

Discord Alert Setup

  1. In your Discord server, open Server Settings > Integrations > Webhooks.
  2. Click New Webhook, select the target channel, and copy the webhook URL.
  3. Update config.yaml: yaml alerting: discord: webhook-url: "https://discord.com/api/webhooks/..."

Reverse Proxy configuration (Optional SSL Deployment)

To access your status page securely over HTTPS, configure Caddy as a reverse proxy in your docker-compose.yml:

version: '3.8'

services:
  gatus:
    image: twinproduction/gatus:latest
    container_name: gatus
    restart: unless-stopped
    volumes:
      - ./config:/config
      - ./data:/data
    environment:
      - TZ=UTC

  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - gatus

volumes:
  caddy_data:
  caddy_config:

Create a Caddyfile in the same directory:

status.yourdomain.com {
    reverse_proxy gatus:8080
}

Run docker compose up -d to launch the stack with automatic SSL configuration.


Operational Validation and Maintenance

Checking Deployment Status

Verify container runtime health and check standard logs for initialization errors:

docker compose ps
docker compose logs gatus

Hot-Reloading Configuration

Gatus supports hot-reloading configurations without stopping the container. Trigger a reload by sending a SIGHUP signal to the process:

docker kill --signal=HUP gatus

Alternatively, if using the HTTP management server, execute:

curl -X POST http://localhost:8080/api/v1/config/reload