Gatus Health Dashboard Installation

Gatus is a lightweight, developer-oriented health monitoring dashboard written in Go that continuously checks endpoints and generates a public status page with configurable alerting via Slack, PagerDuty, email, and more. This guide covers installing Gatus on Linux and Docker, configuring endpoint checks, defining conditions, setting up alerts, and generating a status page.

Prerequisites

  • Ubuntu 20.04+ or CentOS 8+ / Rocky Linux 8+
  • Docker (recommended) or Go 1.21+
  • 256 MB RAM (Gatus is very lightweight)
  • Outbound internet access for alert notifications

Installing Gatus with Docker

Docker is the simplest deployment method:

# Create configuration directory
mkdir -p /opt/gatus

# Create a basic configuration file
cat > /opt/gatus/config.yaml << 'EOF'
web:
  port: 8080

endpoints:
  - name: Website
    url: https://example.com
    interval: 30s
    conditions:
      - "[STATUS] == 200"
      - "[RESPONSE_TIME] < 300"
EOF

# Run Gatus
docker run -d \
    --name gatus \
    --restart unless-stopped \
    -p 8080:8080 \
    -v /opt/gatus/config.yaml:/config/config.yaml \
    twinproduction/gatus:latest

# Check it's running
curl http://localhost:8080/health
# Access the dashboard at http://your-server:8080

With Docker Compose:

# /opt/gatus/docker-compose.yml
version: "3.9"
services:
  gatus:
    image: twinproduction/gatus:latest
    container_name: gatus
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./config.yaml:/config/config.yaml:ro
    environment:
      - SLACK_WEBHOOK_URL=${SLACK_WEBHOOK_URL}  # Pass secrets via env
cd /opt/gatus && docker compose up -d

Installing Gatus as a Binary

# Download the latest release
GATUS_VERSION="5.11.0"
wget https://github.com/TwiN/gatus/releases/download/v${GATUS_VERSION}/gatus_${GATUS_VERSION}_linux_amd64.tar.gz
tar xzf gatus_${GATUS_VERSION}_linux_amd64.tar.gz
sudo mv gatus /usr/local/bin/
gatus --version

# Create directories and user
sudo useradd -r -s /sbin/nologin gatus
sudo mkdir -p /etc/gatus /var/lib/gatus
sudo chown -R gatus:gatus /etc/gatus /var/lib/gatus

# Create systemd service
sudo cat > /etc/systemd/system/gatus.service << 'EOF'
[Unit]
Description=Gatus Health Dashboard
After=network.target

[Service]
User=gatus
Group=gatus
Environment=GATUS_CONFIG_PATH=/etc/gatus/config.yaml
ExecStart=/usr/local/bin/gatus
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now gatus

Configuring Endpoint Checks

The configuration file supports HTTP, TCP, DNS, ICMP, and WebSocket checks:

# /etc/gatus/config.yaml

web:
  port: 8080
  # Uncomment for basic auth on the status page
  # security:
  #   basic:
  #     username: admin
  #     password: password

storage:
  type: sqlite      # Store check history in SQLite
  path: /var/lib/gatus/data.db

# Default settings applied to all endpoints (can be overridden per endpoint)
default-endpoint-group: *default-group
endpoints:

  # HTTP check
  - name: API Gateway
    group: production
    url: https://api.example.com/health
    method: GET
    interval: 30s
    conditions:
      - "[STATUS] == 200"
      - "[BODY] == {\"status\":\"ok\"}"
      - "[RESPONSE_TIME] < 500"
    headers:
      Authorization: Bearer ${API_TOKEN}
    alerts:
      - type: slack
        failure-threshold: 2    # Alert after 2 consecutive failures
        success-threshold: 1    # Resolve after 1 success
        send-on-resolved: true

  # HTTPS certificate check
  - name: API TLS Certificate
    group: production
    url: https://api.example.com
    interval: 6h
    conditions:
      - "[STATUS] == 200"
      - "[CERTIFICATE_EXPIRATION] > 720h"   # Alert if cert expires within 30 days

  # TCP port check
  - name: PostgreSQL
    group: databases
    url: tcp://db.example.com:5432
    interval: 30s
    conditions:
      - "[CONNECTED] == true"
      - "[RESPONSE_TIME] < 100"

  # DNS resolution check
  - name: DNS Resolution
    group: infrastructure
    url: dns://1.1.1.1
    interval: 5m
    dns:
      query-name: example.com
      query-type: A
    conditions:
      - "[DNS_RCODE] == NOERROR"
      - "len([BODY]) > 0"

  # ICMP ping
  - name: Database Server Ping
    group: infrastructure
    url: icmp://db.example.com
    interval: 30s
    conditions:
      - "[CONNECTED] == true"
      - "[RESPONSE_TIME] < 50"

Condition Definitions

Gatus evaluates conditions as simple expressions. Available placeholders:

PlaceholderDescriptionExample
[STATUS]HTTP status code[STATUS] == 200
[BODY]Response body[BODY].user.active == true
[RESPONSE_TIME]Response time (ms)[RESPONSE_TIME] < 500
[CERTIFICATE_EXPIRATION]TLS cert expiry[CERTIFICATE_EXPIRATION] > 720h
[CONNECTED]TCP/ICMP connected[CONNECTED] == true
[DNS_RCODE]DNS response code[DNS_RCODE] == NOERROR

JSON body expressions use dot notation:

conditions:
  # Check a specific JSON field value
  - "[BODY].status == healthy"
  # Check array length
  - "len([BODY].servers) > 0"
  # Numeric comparison on a JSON field
  - "[BODY].metrics.error_rate < 0.01"
  # Pattern matching
  - "[BODY] pat ^.*version.*$"

Operators: ==, !=, >, >=, <, <=, pat (regex), !pat.

Alerting Configuration

Configure alert channels in the top-level alerting section:

# /etc/gatus/config.yaml

alerting:
  slack:
    webhook-url: "${SLACK_WEBHOOK_URL}"
    default-alert:
      failure-threshold: 3
      success-threshold: 1
      send-on-resolved: true

  pagerduty:
    integration-key: "${PAGERDUTY_INTEGRATION_KEY}"
    default-alert:
      failure-threshold: 2
      success-threshold: 1
      send-on-resolved: true

  email:
    from: [email protected]
    username: [email protected]
    password: "${EMAIL_PASSWORD}"
    host: smtp.gmail.com
    port: 587
    to: [email protected]
    default-alert:
      failure-threshold: 3
      success-threshold: 1
      send-on-resolved: true

  telegram:
    token: "${TELEGRAM_BOT_TOKEN}"
    id: "-1001234567890"  # Chat ID (negative for groups)
    default-alert:
      failure-threshold: 2
      send-on-resolved: true

  custom:  # Generic webhook
    url: https://your-webhook.example.com/alert
    method: POST
    body: |
      {
        "status": "[ALERT_TRIGGERED_OR_RESOLVED]",
        "endpoint": "[ENDPOINT_NAME]",
        "url": "[ENDPOINT_URL]",
        "description": "[ALERT_DESCRIPTION]",
        "conditions": "[ENDPOINT_CONDITIONS]"
      }
    headers:
      Authorization: Bearer ${WEBHOOK_TOKEN}
      Content-Type: application/json
    default-alert:
      failure-threshold: 2
      send-on-resolved: true

Set environment variables for secrets:

# In systemd service (or docker-compose env file):
sudo systemctl edit gatus
# Add under [Service]:
# Environment=SLACK_WEBHOOK_URL=https://hooks.slack.com/...
# Environment=PAGERDUTY_INTEGRATION_KEY=your-key

External Endpoints and Connectivity Checks

Monitor third-party services your application depends on:

endpoints:
  # Check that your payment provider is up
  - name: Stripe API
    group: external
    url: https://api.stripe.com/v1/
    interval: 1m
    conditions:
      - "[STATUS] != 0"   # Any response = up (Stripe returns 401 for unauthenticated)

  # Check your CDN
  - name: CDN - Static Assets
    group: external
    url: https://cdn.example.com/images/health-check.png
    interval: 5m
    conditions:
      - "[STATUS] == 200"
      - "[RESPONSE_TIME] < 1000"

  # WebSocket check
  - name: Real-time Service
    group: production
    url: wss://realtime.example.com/ws
    interval: 30s
    conditions:
      - "[CONNECTED] == true"

  # Check your backup database
  - name: Read Replica
    group: databases
    url: tcp://read-replica.example.com:5432
    interval: 1m
    conditions:
      - "[CONNECTED] == true"
      - "[RESPONSE_TIME] < 100"

Status Page and UI

Gatus generates a public status page at http://your-server:8080:

  • Shows all endpoints grouped by their group field
  • Displays uptime badges (last 7 days)
  • Shows response time graphs
  • Lists recent incidents

Configure a custom header message and logo:

web:
  port: 8080

ui:
  title: "Acme Inc. Status Page"
  description: "Current operational status of all Acme services"
  logo: "https://example.com/logo.png"
  link: "https://example.com"
  buttons:
    - name: "Subscribe to updates"
      link: "https://status.example.com/subscribe"

Place Gatus behind Nginx with TLS for a public-facing status page:

server {
    listen 443 ssl;
    server_name status.example.com;

    ssl_certificate /etc/letsencrypt/live/status.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/status.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Troubleshooting

Gatus fails to start:

sudo journalctl -u gatus -f
# Common: invalid YAML syntax, missing required fields

Validate configuration syntax:

# Gatus will print errors on startup if config is invalid
gatus --config /etc/gatus/config.yaml
# Look for "error" messages in output

Alerts not firing:

# Check Gatus logs for alert delivery errors
docker logs gatus | grep -i "alert\|error"
# Verify webhook URL is reachable from the Gatus container
# Test Slack webhook directly:
curl -X POST -H 'Content-type: application/json' \
  --data '{"text":"Test from Gatus"}' \
  "${SLACK_WEBHOOK_URL}"

Endpoint always showing as failed:

# Test the endpoint manually
curl -v https://api.example.com/health
# Check if the condition is correct - use exact JSON body format

High failure count despite endpoint working:

  • Increase failure-threshold to avoid noise from transient failures
  • Check if the response time condition [RESPONSE_TIME] < X is too tight
  • Verify network connectivity from the Gatus host to the endpoint

Conclusion

Gatus provides a clean, self-hosted status page and uptime monitoring solution with minimal infrastructure requirements. Its declarative YAML configuration covers HTTP, TCP, DNS, ICMP, and WebSocket checks, while the flexible condition system handles everything from simple status code checks to JSON body assertions and TLS certificate expiration monitoring. With Slack, PagerDuty, and email alerting built in, Gatus delivers production-ready monitoring that's appropriate for teams of any size.