Uptime Kuma — Uptime & Status Pages
Monitor HTTP, TCP, DNS, and certificate expiry from outside your infrastructure. Build public status pages your users can check themselves.
RamNode VPS ($4/mo+), Docker & Docker Compose
30–40 minutes
Deploy on a separate VPS from production for accurate external checks
Internal monitoring like Beszel answers the question "is my server healthy?" Uptime Kuma answers a different question: "can my users actually reach my services?"
These are not the same thing. A web server can have low CPU and available memory while being completely unreachable due to a misconfigured firewall rule, a failed DNS record, a hung process that is no longer accepting connections, or an expired SSL certificate. Beszel would not catch any of those. Uptime Kuma would.
What Uptime Kuma Monitors
| Monitor type | What it checks |
|---|---|
| HTTP / HTTPS | Status code, response time, optional keyword |
| TCP port | Whether a port is open and accepting connections |
| Ping | ICMP reachability |
| DNS | Resolution of a hostname, expected record value |
| Docker container | Container running/stopped state via Docker socket |
| Database | MySQL, PostgreSQL, Redis, MongoDB connectivity |
| Certificate expiry | Days until SSL cert expires |
| Push | Heartbeat monitor (your app pings Uptime Kuma) |
| Steam game server | Game server query protocol |
Architecture
Uptime Kuma VPS (monitoring server)
- Checks every N seconds/minutes
- Sends HTTP requests, TCP connections, pings
- Stores results in SQLite
- Publishes status page
Production VPS (app server)
- Receives checks from Uptime Kuma
- No agent required
- No configuration changes neededFor a typical RamNode setup, deploy Uptime Kuma on a separate low-cost VPS in a different region from your main servers. This way, a full regional outage affecting your production server will also show up as a downtime event.
Deployment
Step 1 — Create the project directory
mkdir -p /opt/uptime-kuma && cd /opt/uptime-kumaStep 2 — Write the Compose file
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
restart: unless-stopped
ports:
- "3001:3001"
volumes:
- ./uptime-kuma-data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:roThe docker.sock mount is only needed if you plan to monitor Docker containers on this same host.
Step 3 — Start and configure
docker compose up -dOpen http://YOUR_SERVER_IP:3001. Create your admin account immediately — the setup page is publicly accessible until you do.
Step 4 — Reverse proxy
Caddy:
status.yourdomain.com {
reverse_proxy localhost:3001
}nginx:
server {
listen 443 ssl;
server_name status.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/status.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/status.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3001;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600;
}
}The proxy_read_timeout 3600 is important — Uptime Kuma uses WebSockets for live dashboard updates.
Setting Up Monitors
HTTP / HTTPS monitor
Click Add New Monitor, select HTTP(s). Key settings:
- • Heartbeat Interval — 60 seconds default; 30 seconds for critical services
- • Retries — Set to 1 or 2 to prevent single slow responses from triggering downtime
- • Keyword monitoring — Verify actual page content, not just HTTP status code
TCP port monitor
Useful for non-HTTP services: game server ports, mail server ports (25, 587, 993), custom application ports.
DNS monitor
Monitor your primary domain's A record and set the expected value to your server IP. If someone accidentally changes your DNS, you get alerted immediately.
SSL certificate expiry
Enter your domain, set a warning threshold (30 days is sensible). Especially useful if you manage certs across multiple servers.
Push monitor (heartbeat)
Push monitors invert the checking model — your service sends a periodic HTTP request to Uptime Kuma. If the request stops coming, the monitor goes down. Use for cron jobs, background workers, and services behind firewalls.
# At the end of your cron job
curl -s "https://status.yourdomain.com/api/push/TOKEN?status=up&msg=OK" > /dev/nullNotification Channels
Discord (quickest setup)
- In Discord, go to your server's channel settings
- Integrations > Webhooks > New Webhook
- Copy the webhook URL
- In Uptime Kuma, add a Discord notification and paste the URL
Slack
Create a Slack app at api.slack.com/apps, enable Incoming Webhooks, add a webhook to your workspace and paste it into Uptime Kuma's Slack notification settings.
Email (SMTP)
SMTP Host: smtp.mailgun.org (or your provider's host)
SMTP Port: 587
Security: STARTTLS
Username: your SMTP username
Password: your SMTP password
From: alerts@yourdomain.com
To: your@email.comAfter creating a notification channel, edit each monitor and select the channel under Notifications. You can assign multiple channels per monitor.
Status Pages
Status pages let your users check service health themselves, reducing support load during incidents.
Go to Status Page > New Status Page. Add groups to organize your monitors — "Website", "Infrastructure", "Third-party Services".
Custom domain for status page
Point a CNAME from status.yourcompany.com to your Uptime Kuma domain:
status.yourcompany.com {
reverse_proxy localhost:3001
}Set the custom domain in the status page settings. Uptime Kuma will serve that status page on requests from that hostname.
Maintenance Windows
Go to Maintenance > Create Maintenance. Options include manual start/stop, single time, and recurring schedules.
For planned RamNode VPS reboots or kernel updates, create a 30-minute maintenance window starting 5 minutes before you begin. Your status page will show "Scheduled Maintenance" rather than downtime.
Backup and Restore
Uptime Kuma stores everything in SQLite. Stop-and-copy method:
docker compose stop
cp -r /opt/uptime-kuma/uptime-kuma-data /backups/uptime-kuma-$(date +%Y%m%d)
docker compose startOr use SQLite's online backup to avoid downtime:
docker exec uptime-kuma sqlite3 /app/data/kuma.db ".backup /app/data/kuma.db.bak"
cp /opt/uptime-kuma/uptime-kuma-data/kuma.db.bak /backups/uptime-kuma-$(date +%Y%m%d).dbCombining With Beszel
If you are running both Beszel (from Part 1) and Uptime Kuma, they complement each other without overlap:
| Question | Tool |
|---|---|
| Is my server's CPU spiking? | Beszel |
| Is my web service responding to HTTP? | Uptime Kuma |
| Is my disk almost full? | Beszel |
| Is my SSL cert about to expire? | Uptime Kuma |
| Is that container using too much memory? | Beszel |
| Are my users able to reach my app right now? | Uptime Kuma |
| What happened at 3 AM last Tuesday? | Both (different angles) |
Run both. The combined RAM footprint on even a $4/month VPS is well under 200 MB.
What's Next
Beszel and Uptime Kuma cover reactive monitoring — you know when something breaks. Part 3 introduces a different philosophy: Gatus, a YAML-driven health monitoring tool built for teams that want their monitoring configuration version-controlled alongside their infrastructure code.
Part 3 covers:
- Health checks defined as code in YAML
- Condition expression syntax with JSON body inspection
- CI/CD pipeline for auto-deploying config changes
- Environment variable substitution for secrets
