The Problem with Traditional Monitoring
Prometheus + Grafana are powerful for server metrics, but when all you need to know is “is the website up?” or “is the API returning 200?” — spinning up an entire stack like that is overkill. Before using Gatus, I was SSH-ing into each server to check things manually. Now I just open the dashboard and see everything at a glance — the status of every endpoint, uptime history, and response times.
Gatus solves exactly one problem: simple endpoint health checks, a clean Status Page, and Telegram alerts when something goes wrong. No database, no agents to install on servers — the entire configuration is a single YAML file.
What Is Gatus and Why Use It?
Technically, Gatus is a single Go binary — deploy it and it runs immediately, with no runtime or additional dependencies. The footprint is tiny: RAM usage typically stays under 20MB, and startup takes under a second. The tool supports four types of checks:
- HTTP/HTTPS — check status codes, body content, and response time
- TCP — check whether a port is open (databases, Redis, etc.)
- DNS — check whether a domain resolves correctly
- ICMP (ping) — check whether a host is reachable
Compared to Zabbix or Netdata, Gatus does not monitor CPU/RAM/disk — that’s what other tools are for. Gatus focuses entirely on “is this service working correctly?” — a complementary perspective, not a replacement, for your existing monitoring stack.
What I like most about Gatus: the built-in Status Page, with no extra plugins or services needed. When a client asks “what’s wrong with the website?” — just share the status page link, no lengthy chat explanations required.
Installing Gatus with Docker Compose
Docker is the fastest way to get started. Create a working directory:
mkdir -p ~/gatus && cd ~/gatus
touch config.yaml docker-compose.yml
Contents of docker-compose.yml:
version: "3.8"
services:
gatus:
image: twinproduction/gatus:stable
container_name: gatus
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./config.yaml:/config/config.yaml
environment:
- GATUS_CONFIG_PATH=/config/config.yaml
Start the container:
docker compose up -d
docker compose logs -f gatus
If you prefer not to use Docker, you can also build from source:
git clone https://github.com/TwiN/gatus.git
cd gatus
go build -o gatus .
./gatus --config config.yaml
Detailed Configuration
Basic config.yaml Structure
web:
port: 8080
# Optional: set base-path if using a reverse proxy subdirectory
# base-path: /status
storage:
type: sqlite # Store uptime history in SQLite (under /data directory)
path: /data/gatus.db
alerting:
telegram:
token: "1234567890:ABCdef..." # Bot token from @BotFather
id: "-100123456789" # Chat ID (groups use a negative number)
default-alert:
enabled: true
failure-threshold: 3 # Alert after 3 consecutive failed checks
success-threshold: 2 # Notify recovered after 2 consecutive successful checks
send-on-resolved: true # Send a message when the service recovers
endpoints:
- name: "Website itfromzero.com"
url: "https://itfromzero.com"
interval: 5m
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 3000" # Response time under 3 seconds
alerts:
- type: telegram
Monitoring Multiple Endpoint Types
endpoints:
# HTTP endpoint with body check
- name: "API Health Check"
url: "https://api.example.com/health"
interval: 2m
conditions:
- "[STATUS] == 200"
- "[BODY] == {\"status\":\"ok\"}" # Body must contain this JSON
- "[RESPONSE_TIME] < 1000"
alerts:
- type: telegram
failure-threshold: 2 # Override: alert after 2 failures
# TCP — check database port
- name: "PostgreSQL Port"
url: "tcp://db.internal:5432"
interval: 1m
conditions:
- "[CONNECTED] == true"
alerts:
- type: telegram
# TCP — Redis
- name: "Redis Cache"
url: "tcp://redis.internal:6379"
interval: 1m
conditions:
- "[CONNECTED] == true"
alerts:
- type: telegram
# DNS check — verify domain resolves to the correct IP
- name: "DNS itfromzero.com"
url: "dns://1.1.1.1"
dns:
query-name: "itfromzero.com"
query-type: "A"
interval: 10m
conditions:
- "[DNS_RCODE] == NOERROR"
# ICMP ping — check if server is reachable
- name: "VPS Singapore"
url: "icmp://103.x.x.x"
interval: 5m
conditions:
- "[CONNECTED] == true"
Getting the Bot Token and Chat ID for Telegram
Open Telegram and message @BotFather — type /newbot, give your bot a name, then save the token in the format 1234567890:ABCdef... that BotFather returns.
To get the Chat ID of a group or channel:
# Add the bot to the group, then call the API:
curl "https://api.telegram.org/bot<YOUR_TOKEN>/getUpdates"
# Find "chat":{"id":-100xxxxxxxxx} in the response
Using Environment Variables for Sensitive Values
Avoid hardcoding tokens in your config. Gatus supports environment variables using the ${VAR_NAME} syntax:
alerting:
telegram:
token: "${TELEGRAM_BOT_TOKEN}"
id: "${TELEGRAM_CHAT_ID}"
Update docker-compose.yml to pass in the variables:
services:
gatus:
image: twinproduction/gatus:stable
container_name: gatus
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ./config.yaml:/config/config.yaml
- gatus_data:/data
env_file:
- .env
volumes:
gatus_data:
The .env file:
TELEGRAM_BOT_TOKEN=1234567890:ABCdef...
TELEGRAM_CHAT_ID=-100123456789
Testing and Using the Monitoring Dashboard
Accessing the Status Page
Once Gatus is running, open http://your-server-ip:8080 and the dashboard appears immediately. Each endpoint displays its current status (green/red), average response time, and a 7-day plus last-24-hour uptime history as a block timeline — it’s immediately obvious whether anything is wrong.
To expose it to the internet via Nginx:
server {
listen 80;
server_name status.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Verifying Telegram Alerts Work
Add a test endpoint with a condition guaranteed to fail, then remove it afterwards:
endpoints:
- name: "Test Alert"
url: "https://httpstat.us/503" # Always returns 503
interval: 30s
conditions:
- "[STATUS] == 200" # Will fail
alerts:
- type: telegram
failure-threshold: 1 # Alert on the very first failure
Restart Gatus and wait 30 seconds — if everything is configured correctly, Telegram will receive an alert message with the endpoint details and the reason for the failure.
Viewing Logs and Debugging
# View logs in real time
docker compose logs -f gatus
# Verify the config is parsed correctly
docker compose exec gatus cat /config/config.yaml
# Restart after editing the config
docker compose restart gatus
Practical Tips for Day-to-Day Operation
- Set failure-threshold to >= 2 to avoid false alerts caused by temporary network hiccups
- Use
interval: 1mfor critical production endpoints and5mfor less critical ones — avoid generating unnecessary requests - Mount the
/datavolume to a host path so uptime history persists across container restarts - If Gatus runs on the same server as the services it monitors, add an external check from a separate server to avoid false positives when the entire server goes down
With this setup, I no longer have to worry about my website going down without me knowing. The entire endpoint monitoring stack costs just one YAML file and one container — far simpler than setting up a Prometheus exporter for every individual service.

