Install via Docker / Podman
# Plain docker run
docker run -d \
--name uptime-kuma \
--restart unless-stopped \
-p 127.0.0.1:3001:3001 \
-v uptime-kuma:/app/data \
louislam/uptime-kuma:1
Or compose / Quadlet for proper lifecycle management:
# docker-compose.yml
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
ports:
- "127.0.0.1:3001:3001"
volumes:
- ./data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro # only if monitoring docker containers
First run, browse to http://<host>:3001/ — the wizard creates an admin account. The SQLite database lives in /app/data/kuma.db.
Reverse proxy
# Caddy
status.example.com {
reverse_proxy 127.0.0.1:3001
}
Uptime Kuma uses WebSockets; Caddy supports them by default, nginx needs the usual Upgrade/Connection headers and a long proxy_read_timeout.
The first monitor
Add New Monitor → pick a type:
- HTTP(s) — URL + expected status code(s) + optional keyword-in-body check + optional certificate-expiry alert.
- HTTP(s) with JSON Query — for "the API returned
{"status": "ok"}"; uses JSONPath to extract and compare. - TCP port — for non-HTTP services (Postgres, Redis).
- Ping — ICMP, but note Docker needs
--cap-add=NET_RAWfor ping monitors. - DNS — resolve a name against a specific server, expect a record.
- Docker container — check that a container is running (via the mounted Docker socket).
- Push — Uptime Kuma generates a URL, your service hits it on a heartbeat. Perfect for cron jobs — "if I haven't heard a heartbeat in 24 hours, the backup didn't run." Same idea as healthchecks.io, self-hosted.
- Database (Postgres / MySQL / MongoDB / Redis / SQL Server) — check a connection succeeds and a query returns expected data.
- Real-Browser — run a headless Chrome against the page, useful for SPA endpoints where HTTP 200 doesn't mean the page actually rendered.
Useful settings per monitor
- Heartbeat interval — how often to check. 60s is the default; below 20s for critical, 5-10 min for non-critical so you don't pay rate-limit cost.
- Retries before "Down" — 2–3 is sane; 0 means a single transient blip pages you.
- Heartbeat retry interval — once a check fails, retry sooner (e.g. 20s) until either it recovers or "Down" is confirmed.
- Resend Notification — repeat the notification every N minutes while down; useful for catching alerts you missed.
- Tags — group monitors by service / project / customer. The dashboard filter and the status pages both use these.
Notifications
Set up notifications once under Settings → Notifications, then attach them to monitors. The channel list is exhaustive; the most-used in practice:
- Slack / Discord / Teams — webhook URL, channel name. Default templates are good.
- Telegram — create a bot via @BotFather, paste the token, chat ID.
- ntfy — self-hosted push notifications (ntfy.sh or a local instance); maps to a topic the mobile app subscribes to.
- SMTP email — works fine with Stalwart, Mailgun, etc.
- Generic webhook — POST the alert JSON anywhere. Useful for tying into n8n (see that tutorial) for "alert → create ticket in Linear" flows.
Status pages
Status Pages → Add New Status Page. Pick a slug (becomes https://status.example.com/status/<slug>), pick which monitors / monitor groups to show, customize the title and colour. Public viewers see uptime history, current status, and ongoing incidents; no auth required.
For incident transparency, the "Incident" banner at the top of a status page is a manual message that operators post during an outage (with status: investigating / identified / monitoring / resolved). Status-page status auto-updates from the monitor results below the banner.
Per-monitor SSL cert expiry
HTTP(s) monitors automatically track certificate expiry of the target. Default alert is 21/14/7 days before expiration. For sites behind Let's Encrypt + ACME, this is a useful canary against "auto-renewal silently broke a month ago."
Multi-instance / multi-region
Uptime Kuma 2.x (currently in beta) introduces remote browser instances and remote regions — checks running from a different IP than the central one. For 1.x: deploy multiple Kumas in different geographic locations and have them monitor each other plus your services. The "Uptime Kuma is the one watching the watchers" problem is real; run two instances in two clouds for the cheapest workable HA.
Backups
The entire state lives in the data volume: kuma.db (monitors, alerts, history), uploaded images, status-page config. A nightly file-level backup of that directory (restic, rsnapshot, ZFS send) is enough to rebuild a fresh Kuma instance.
API and Prometheus metrics
- Uptime Kuma exposes a Prometheus-compatible
/metricsendpoint (with the right API key header), so the same data flows into Grafana dashboards via Prometheus (see that tutorial). - The REST API is undocumented but stable enough; Status Page JSON is at
/api/status-page/<slug>for embedding.