Uptime Kuma: The Self-Hosted Status Page and Monitor That Kills Your SaaS Subscription
"The cheapest status page is the one whose data never leaves your network. Uptime Kuma is that page — and it costs exactly zero dollars in software."
If you have ever paid UptimeRobot or Pingdom a recurring fee just to be told "your server is down," you have already felt the itch Uptime Kuma scratches.
Uptime Kuma (GitHub:
louislam/uptime-kuma) is a self-hosted uptime monitor and status page that does the one thing most SaaS monitoring bills you monthly for — watches your endpoints and tells you when they fall over — and then refuses to charge you for it. As of August 2026 it has roughly
89,000 stars, ships under the
MIT license, runs as a
single Docker container, and supports
90+ notification channels from Telegram to PagerDuty. For a blog about software you run on your own hardware, it is the obvious monitoring companion to every other self-hosted service you already keep alive.
This is the honest breakdown: how it works, what it really costs, where your telemetry lands, and the architectural limits that decide whether it belongs in your stack.
1. What Uptime Kuma Is (and Isn't)
Uptime Kuma is
not a metrics platform. It is not Prometheus, it is not Grafana, and it will not chart your CPU over time or trace a slow query. What it
is is a focused, beautiful uptime monitor: you point it at an endpoint, it pings that endpoint on an interval, and when the endpoint stops responding it yells at you through whatever channel you configured.
The supported probe types cover the practical majority of what a self-hoster or small team actually needs:
- HTTP/HTTPS — with keyword matching, status-code checks, and JSON-query assertions.
- TCP / port — "is my database port open."
- Ping / ICMP — "is the host alive."
- DNS — resolve a record and check the answer.
- SSL certificate — watch expiry and warn before it bites you.
- WebSocket, Docker, and push monitors — for the less ordinary cases.
That scope discipline is the reason people love it. It does one job, the dashboard is genuinely pretty, and there is no feature gate separating "free" from "useful." Every monitor, every status page, every notification channel is included, because there is no paid tier at all.
2. The Architecture: One Container, No REST API, Socket.IO Everywhere
The most interesting engineering decision in Uptime Kuma is also its most misunderstood:
there is no REST API. Every interaction between the Vue 3 frontend and the Node.js backend flows over
Socket.IO WebSockets. The author documented this as a deliberate choice — "try to use WebSocket with SPA instead of a REST API" — and it is why the dashboard feels alive: a status change propagates to every open browser tab the instant it is detected, with no polling.

Under the hood:
- Frontend: Vue 3 + Vite + Bootstrap 5.
- Backend: Node.js (≥20.4) serving monitor logic and the Socket.IO layer.
- Database: SQLite via Knex.js, persisted on a mounted volume. (An embedded MariaDB option exists for larger deployments.)
- Realtime: Socket.IO events, not HTTP polling.
- Notifications: 90+ providers, each a self-contained module under
src/components/notifications/.
The minimum check interval is
20 seconds — fast enough for almost any human-facing alerting, and free, unlike the tiered SaaS tools that gate short intervals behind paid plans. A single container with no external database dependency means you can run it on a Raspberry Pi, a $5/mo VPS, or alongside other services on your homelab.
The flip side of "no REST API" is the project's most-upvoted issue (#118, hundreds of votes): there is no first-class external HTTP interface for automation. If you want to script monitor creation or pull data into another system, you are working against the grain. For most users that is fine; for platform teams it is the reason to reach for Prometheus instead.
3. The Status Page: Your Public Face
The feature that turns Uptime Kuma from a personal pager into a real product is the
public status page. You pick a set of monitors, map them to a branded page on a custom domain, and publish it. Your users or customers then see green/orange/red bars without logging into anything.

This is the direct replacement for the status-page add-on you would otherwise pay UptimeRobot or Statuspage.io for. Unlimited status pages, unlimited monitors, unlimited notification channels — all free, all local. For a self-hoster who runs a service other people depend on (a game server, a family photo share, a client site), a self-hosted status page is the difference between "trust me, it's up" and a link you can send.
One honest caveat: the status page is served from
where Kuma runs. If Kuma is on the same VPS as the thing it monitors, and that VPS dies, your status page dies with it — showing "down" for everything including itself. The fix is the same as for any monitor: run Kuma somewhere independent of what it watches, or pair it with a cheap external SaaS purely as a "is Kuma itself up" canary.
4. Notifications: 90+ Ways to Get Yelled At
Alerting is only as good as the channel that reaches you at 3 a.m., and this is where Uptime Kuma is genuinely generous. The 90+ integrations include the obvious —
Slack, Discord, Telegram, email/SMTP, Microsoft Teams, PagerDuty, OpsGenie, webhook — plus a long tail of regional and niche services. Each is configured in the web UI; you rarely write webhook code.
The honest limitation is
escalation logic. Kuma sends a notification when a monitor goes down and another when it recovers. It does not, out of the box, model on-call rotations, multi-step escalation, or "page the secondary if the primary doesn't ack in five minutes." Teams needing that should bolt on a dedicated incident layer (or just live with simple alerts — most homelabs should).
5. The Cost, Honestly
The software is free under MIT. The total cost of ownership is the hardware and the discipline:
Software: $0. No tier, no seat, no per-monitor billing, no status-page surcharge. This alone is the headline.
Compute: A container needs almost nothing — a Raspberry Pi or a tiny VPS slice handles hundreds of monitors. Call it
$0–$5/month if you need external hosting, or $0 on existing hardware.
Storage: SQLite on a mounted volume. Tiny for uptime data; grows with history retention. Back it up.
Your time: Low. The DEV.co deployment-complexity rating is 1/5 — a single
docker run or Compose file, a volume mount, done. The "Day 2" work is picking notification channels and remembering to back up the database.
The hidden cost everyone forgets: you must monitor the monitor. If Kuma's host reboots silently or its volume corrupts, you lose visibility exactly when you need it. A 30-second Cron job on another machine that pings Kuma's own URL closes the loop. This is the self-hoster's version of "who watches the watchers" — and it is the one recurring chore.
Against UptimeRobot's ~$15–$100+/month for comparable monitor counts and status pages, Kuma's $0 is not just cheaper, it is structurally different: your monitoring telemetry never transits a third-party cloud. That is the data-sovereignty argument in one sentence.
6. Honest Limitations
A real deep-dive names the walls:
- Single-instance by design. Kuma monitors from one network vantage point — where it is installed. It cannot do multi-region synthetic checks (probe from Tokyo, Frankfurt, and Virginia simultaneously) without you standing up multiple instances and stitching them yourself. If your SLA depends on "is it reachable globally," a commercial service or a self-hosted orchestration layer is required.
- No RBAC. There is one admin login. You can enable 2FA, but there is no roles model — no "read-only viewer" or "on-call-only" account. Fine for a home; awkward for a team.
- SQLite ceiling. Under very high check frequency or alert volume, the embedded database can bottleneck. The MariaDB option exists; most users never need it.
- Not a metrics tool. No CPU graphs, no tracing, no long-term retention story. Pair it with Prometheus/Grafana for depth; Kuma owns availability, not observability.
- Community-only support. Maintained primarily by one developer (louislam, based in Hong Kong). No SLA, no commercial support contract. The project is healthy and active, but "who do I call" has the answer "the GitHub issues page."
- Internet-facing needs hardening. The default setup exposes the dashboard on port 3001 unauthenticated. Put it behind a reverse proxy with TLS and a strong password before any external exposure.
None of these are surprises once stated. They are the difference between a tool you chose knowingly and one you outgrew without warning.
7. Getting Started
The supported path is a single Compose file:
``
yaml
services:
uptime-kuma:
image: louislam/uptime-kuma:2.4.0
container_name: uptime-kuma
volumes:
- ./uptime-kuma-data:/app/data
ports:
- "3001:3001"
restart: always
`
Then open http://your-host:3001
, create the admin account (default password is literally Password
— change it immediately), add a monitor, and wire a Telegram bot. Five to fifteen minutes to a working check; another fifteen to make the status page presentable.
Production notes: mount the volume on real storage (not a flaky SD card), run it behind Nginx/Caddy with TLS, enable 2FA, and point it at endpoints outside its own host where possible.
8. Uptime Kuma vs the Alternatives
| | Uptime Kuma | UptimeRobot | Prometheus + Grafana |
|---|---|---|---|
| Cost | $0 (MIT) | $15–100+/mo | free, self-hosted |
| Self-hosted | ✅ | ❌ SaaS | ✅ |
| Status pages | unlimited, free | tier-gated | manual |
| Multi-region | ❌ single instance | ✅ | ✅ (with work) |
| Metrics/depth | ❌ availability only | ❌ | ✅ full |
| RBAC | ❌ | ✅ paid | ✅ |
| Setup | 1/5 | 1/5 | 4/5 |
The short version: for internal infrastructure, a VPC, or a homelab where you want zero cost and zero data leaving your network, Uptime Kuma is a strong buy. For global synthetic monitoring or enterprise on-call workflows, it is the wrong shape — use a commercial service or Prometheus. Most self-hosters run Kuma for the former and never regret it.
9. Who Should Run It
Run it if: you pay a monitoring SaaS and resent it, you run any self-hosted service other people rely on, you want a public status page without a subscription, or you simply like the idea of your uptime data never touching a vendor.
Skip it if: you need multi-region probes, formal on-call escalation, RBAC, or deep metrics — those are different tools. Also skip it if you will not remember to back up the volume and monitor the monitor; an unmonitored monitor is worse than no monitor, because it lies silently.
For this blog's readers — the ones already running Immich, Vaultwarden, Home Assistant, and a Docker host — Uptime Kuma is the cheap, local, private watchdog that sits next to everything else and tells you the moment one of them blinks off. It is the "own it, don't rent it" principle applied to the most boring, most essential layer: knowing whether your stuff is up.
10. A Concrete Monitoring Example
Beyond theory, here is a realistic setup for a self-hoster running a few services on a VPS:
https://mysite.example
with a keyword check for "Welcome" and SSL expiry alert at 21 days. Catches both outage and cert rot.
Monitor 2 — TCP on postgres:5432
so you know if the database port dies even when the web app technically answers.
Monitor 3 — Ping on the VPS gateway to separate "my app is down" from "the whole box is down."
Monitor 4 — Docker container health for the Immich container, so a crashed container pages you before users do.
Notification — Telegram for instant, PagerDuty (or OpsGenie) for anything tagged "production."
Push the lot to a public status page at status.example
. Now your users see the same green bars you do, updated live, with no SaaS line item.
11. Backup & False-Positive Playbook
Two chores separate a reliable monitor from a noisy one.
Backups. The SQLite volume is your only state. Snapshot it daily to object storage or another host. A corrupted data
directory with no backup means re-adding every monitor by hand — tedious and exactly when you are stressed.
False positives. "Kuma says down but I can reach it" is almost always a local networking issue, not a service issue: a firewall rule changed, the container lost outbound, or DNS on the Kuma host differs from yours. Debug from inside the Kuma container with curl
and ping
before blaming the target. Another classic: a monitor behind Cloudflare's challenge gets a 403 instead of 200 — set the expected status code or use a keyword check. The fix is configuration, not a bug.
The deeper lesson: a monitor is only as trustworthy as the vantage point it sits on. Run Kuma on hardware independent of what it watches, and it will tell you the truth.
12. Running Kuma Inside Your Homelab Stack
Kuma is rarely the only thing you self-host, so here is a realistic Compose that places it next to the services it watches — note the deliberate separation: Kuma runs on host B, the services it monitors run on host A, so a host-A failure doesn't take the watcher down with it.
`
yaml
On host B (independent of what you monitor)
services:
uptime-kuma:
image: louislam/uptime-kuma:2.4.0
container_name: uptime-kuma
volumes:
- ./kuma-data:/app/data
ports:
- "3001:3001"
restart: always
# Optional: watch Kuma's own host health
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --schedule "0 4 " uptime-kuma
``
What to monitor first
, in priority order: (1) your DNS resolver and gateway, because everything depends on them; (2) your critical public service (the one users notice); (3) the database port behind it; (4) TLS certificate expiry on each public endpoint. That four-item list catches the overwhelming majority of real outages before users do. Add the nice-to-haves — game server, media box, random container — later.
The broader point: Kuma is the canary for the rest of your "own it, don't rent it" stack. It is cheap, local, and private, and it is the first thing a mature self-hoster stands up after the services themselves.
13. Where Kuma Ends and Prometheus Begins
A mature self-hoster eventually asks: "do I need Prometheus too?" The honest answer is sometimes*, and the boundary is clean. Kuma answers one question — "is this endpoint up right now?" Prometheus answers a different one — "how is this system behaving over time, and why is it slow?" They are not competitors; they are layers.
Run Kuma alone if you need availability alerts and a status page, and you don't care about CPU graphs or request-latency histograms. That covers most homelabs and small teams completely.
Add Prometheus + Grafana when you need: historical charts, quantile latency, custom metrics from your own app, alerting on "p99 latency crept above 400ms" rather than just "it's down," or multi-region probing stitched from several Kuma instances. Prometheus scrapes metrics; Kuma watches endpoints; Grafana draws both. The pattern seasoned operators use is Kuma for the human-facing "is it up" page and the pager, Prometheus for the engineering-facing "why is it slow" dashboard.
The mistake is forcing Kuma to be an observability platform — it will frustrate you, because it was never built for it. And the opposite mistake is standing up a full Prometheus stack to watch three containers, which is overkill. Start with Kuma. Add Prometheus when a graph would actually change a decision. That sequencing respects both your time and the "own it, don't rent it" budget.
14. Tuning the Check Interval (the 20-Second Trade-off)
Kuma's minimum interval is 20 seconds, and that is usually the right default — fast enough to catch a real outage within half a minute, slow enough to be gentle on target and host. But the interval is per-monitor, and tuning it is a small art.
Set
20 seconds for the handful of things where downtime costs money: your public site, the payment endpoint, the database port. Set
60–120 seconds for the "nice to know" monitors — a game server, a media box, a container you'd notice anyway. The reason is load: every monitor openes a connection on its interval, and a few hundred monitors at 20 seconds each is meaningful CPU and outbound traffic on a tiny VPS. Spreading intervals is also how you avoid a synchronized "everything just checked at once" spike.
One trap: don't set a 20-second interval and then wonder why a flaky target pages you constantly. A monitor reflects reality; if the target flaps, that is a target problem, not a Kuma problem. Use the "retries" and "retry interval" settings to absorb brief blips before alerting — Kuma will only notify after N consecutive failures, which filters the noise that turns a good monitor into a boy who cried wolf.
Related
Comments (0)
No comments yet. Be the first to comment!