How to Self-Host Gatus on a VPS
Build a lightweight status page from a YAML file, check HTTP and TCP services, and send alerts without running a full monitoring stack.
Gatus is a lightweight status-page and health-check service configured in YAML. It fits a VPS when you want repeatable HTTP, TCP, DNS, or ICMP checks without building a Prometheus and Grafana stack. This guide keeps the Gatus port private, publishes the dashboard through Caddy, and stores check history outside the container.
What you need
- An Ubuntu or Debian VPS with Docker Engine and the Compose plugin
- A DNS record such as
status.example.compointing to the VPS - TCP ports 80 and 443 allowed through the cloud and guest firewalls
A small Gatus deployment is light enough for gc.nano. Choose more memory when the same VPS also runs the applications being checked. Monitoring from the same machine proves that a process is reachable locally, but it cannot tell you the VPS itself is offline; use a second location for that failure mode.
1. Create the project
mkdir -p /opt/gatus/config /opt/gatus/data
cd /opt/gatus
Create compose.yaml. Binding to 127.0.0.1 prevents clients from bypassing the HTTPS proxy on port 8080:
services:
gatus:
image: ghcr.io/twin/gatus:stable
restart: unless-stopped
ports:
- "127.0.0.1:8080:8080"
volumes:
- ./config:/config:ro
- ./data:/data
2. Define the first health checks
Create /opt/gatus/config/config.yaml. Conditions decide whether each endpoint is healthy; keep response-time thresholds realistic for the route you are measuring:
storage:
type: sqlite
path: /data/gatus.db
endpoints:
- name: Website
group: Public services
url: "https://example.com/health"
interval: 60s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 1000"
- name: SSH
group: Infrastructure
url: "tcp://203.0.113.10:22"
interval: 2m
conditions:
- "[CONNECTED] == true"
Replace the example domain and documentation IP. Gatus supports HTTP, TCP, DNS, ICMP, TLS, WebSocket, and push-based checks, so add only checks that describe a real customer dependency. Do not publish internal hostnames, ports, or error bodies on a public status page.
3. Start Gatus and inspect it locally
docker compose up -d
docker compose logs --tail=100 gatus
curl -I http://127.0.0.1:8080
If Gatus rejects the YAML, fix the reported field or indentation and run docker compose restart gatus. Keep the configuration in private version control so changes are reviewable and recoverable.
4. Add HTTPS with Caddy
Install Caddy using its official package instructions, then add this site to /etc/caddy/Caddyfile:
status.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8080
}
Reload Caddy and verify the public URL:
caddy validate --config /etc/caddy/Caddyfile
systemctl reload caddy
curl -I https://status.example.com
5. Add alerts without alert storms
Gatus separates alert providers from endpoint alert rules. Configure a provider such as email, ntfy, Discord, Slack, or PagerDuty, then give the endpoint a failure threshold. Requiring several consecutive failures filters brief network noise. Test both the failure notification and the recovery notification before relying on it.
6. Back up and update
Back up /opt/gatus/config and /opt/gatus/data to another system. LayerOne does not take VPS snapshots or backups. To update, copy the data first, then pull and recreate the container:
cd /opt/gatus
docker compose pull
docker compose up -d
docker compose logs --tail=100 gatus
Use the official Gatus documentation for current endpoint types and alert-provider syntax. For a click-configured alternative, see how to host Uptime Kuma on a VPS. Compare small VPS sizes on the LayerOne pricing page.