How to Self-Host Uptime Kuma: Website Monitoring 2026
TL;DR
Uptime Kuma (MIT, ~56K GitHub stars, Node.js) is a beautiful self-hosted uptime monitoring tool with a polished real-time dashboard. Monitor websites, APIs, TCP ports, DNS records, Docker containers, and databases. UptimeRobot's free plan limits you to 50 monitors with 5-minute intervals. Uptime Kuma is unlimited monitors at 20-second intervals, with a customizable public status page, for free.
Key Takeaways
- Uptime Kuma: MIT, ~56K stars, Node.js — uptime monitoring with a gorgeous UI
- Monitor types: HTTP/HTTPS, TCP port, Ping, DNS, Docker container, Push (for cron jobs)
- Status pages: Public status pages — share uptime with customers or team
- Alerts: 90+ notification services (Slack, Discord, Telegram, PagerDuty, ntfy, email)
- Intervals: Down to 20 seconds (UptimeRobot free: 5 minutes)
- Certificates: TLS certificate expiry monitoring with alerts
Part 1: Docker Setup
# docker-compose.yml
services:
uptime-kuma:
image: louislam/uptime-kuma:latest
container_name: uptime-kuma
restart: unless-stopped
ports:
- "3001:3001"
volumes:
- uptime_kuma_data:/app/data
# For Docker container monitoring:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
TZ: America/Los_Angeles
volumes:
uptime_kuma_data:
docker compose up -d
Visit http://your-server:3001 → create admin account.
Part 2: HTTPS with Caddy
status.yourdomain.com {
reverse_proxy localhost:3001
}
Part 3: Monitor Types
HTTP/HTTPS (websites and APIs)
- + Add New Monitor
- Monitor Type: HTTP(S)
- URL:
https://yourdomain.com - Heartbeat interval:
60seconds - Retries:
3 - Save
Advanced options:
- Expected HTTP status:
200(alert if not 200) - Expected keyword:
"Welcome"(alert if keyword missing — useful for detecting fake 200s) - Certificate expiry notification: Alert 30 days before cert expires
- Authentication: Basic auth or bearer token
TCP port monitoring
Monitor SSH, databases, mail servers:
Monitor Type: TCP Port
Hostname: your-server.com
Port: 22 ← SSH
Port: 5432 ← PostgreSQL
Port: 3306 ← MySQL
Port: 25 ← SMTP
Docker container monitoring
Checks if a Docker container is running:
Monitor Type: Docker Container
Container Name: nginx
Docker Host: /var/run/docker.sock (local)
DNS monitoring
Check that DNS resolves correctly:
Monitor Type: DNS
Hostname: yourdomain.com
Record Type: A
Resolver: 1.1.1.1
Expected value: YOUR.SERVER.IP
Push monitoring (heartbeats for cron jobs)
For scheduled tasks — Uptime Kuma alerts if the job doesn't check in:
Monitor Type: Push
Generate a Push URL → copy the URL
# In your cron job, ping the URL on success:
0 2 * * * /opt/scripts/backup.sh && \
curl -s "https://status.yourdomain.com/api/push/UNIQUE_TOKEN?status=up&msg=OK"
Part 4: Notifications
Slack
- Settings → Notification → Add notification
- Type: Slack
- Webhook URL:
https://hooks.slack.com/services/... - Channel:
#alerts - Test → save
Telegram
Type: Telegram
Bot Token: 1234567890:AAHdqTcvCH1vGWJxfSeofSs0K7MDk (from @BotFather)
Chat ID: -1001234567890 (your channel/group ID)
ntfy (self-hosted push)
Type: ntfy
Server URL: https://ntfy.yourdomain.com
Topic: uptime-alerts
Priority: High
PagerDuty (for production)
Type: PagerDuty
Integration Key: your-pagerduty-routing-key
Email (SMTP)
Type: Email (SMTP)
Host: mail.yourdomain.com
Port: 587
Security: TLS
Username: alerts@yourdomain.com
Password: your-email-password
From: alerts@yourdomain.com
To: you@yourdomain.com
Part 5: Status Pages
Create a public status page for customers or team:
- Status Pages → + New Status Page
- Slug:
status(page at/status) - Title:
YourProduct Status - Description:
Real-time uptime and incident status
Add monitors to page
- Status Page → Edit → + Add group
- Group name:
Core Services - Add monitors: website, API, database
Custom domain
status.yourproduct.com {
reverse_proxy localhost:3001
}
In Uptime Kuma → Status Pages → [page] → Custom Domain: status.yourproduct.com
Incident reporting
- Status Page → + Create incident
- Title:
API degraded performance - Content:
We are investigating elevated error rates in the API. - Status: Investigating → Identified → Monitoring → Resolved
Part 6: Monitor Groups and Tags
Organize many monitors:
Groups:
├── Production
│ ├── Website (https://yourdomain.com)
│ ├── API (https://api.yourdomain.com/health)
│ └── Database port (TCP 5432)
├── Development
│ ├── Staging (https://staging.yourdomain.com)
│ └── Dev API
└── Infrastructure
├── VPS SSH (TCP 22)
└── Mail server (TCP 25)
Tags for filtering: production, critical, customer-facing
Part 7: REST API
# Authenticate and get API key:
# Settings → API Keys → + Add API Key
API_KEY="your-api-key"
BASE="https://status.yourdomain.com"
# Get all monitors:
curl "$BASE/api/v1/monitor" \
-H "Authorization: Bearer $API_KEY" | jq '.[].name'
# Get monitor status:
curl "$BASE/api/v1/monitor/1" \
-H "Authorization: Bearer $API_KEY" | jq '.heartBeatList'
# Add a monitor programmatically:
curl -X POST "$BASE/api/v1/monitor" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "http",
"name": "New API",
"url": "https://api.yourdomain.com/health",
"interval": 60,
"retryInterval": 60,
"maxretries": 3
}'
Maintenance
# Update:
docker compose pull
docker compose up -d
# Backup:
tar -czf uptime-kuma-backup-$(date +%Y%m%d).tar.gz \
$(docker volume inspect uptime-kuma_uptime_kuma_data --format '{{.Mountpoint}}')
# Logs:
docker compose logs -f uptime-kuma
# Export monitor list (JSON):
# Settings → Export Configuration → Download
See also: Healthchecks — for monitoring cron jobs specifically
See all open source monitoring tools at OSSAlt.com/categories/devops.