Contents

Uptime Kuma: Monitoring That Takes Ten Minutes

The monitoring you'll actually finish setting up, and where its ceiling is

Contents

The best monitoring system is the one you finish configuring. I have started a Prometheus and Grafana setup three times and abandoned it twice, both times somewhere in the exporter wiring, with a beautiful dashboard showing node CPU and absolutely no alert that would tell me a service had died.

Uptime Kuma took eleven minutes from docker compose up to twelve services being watched with push notifications to my phone. That comparison is unfair to Prometheus in every technical dimension and completely fair in the only one that mattered: after eleven minutes I had monitoring, and after two weekends of Prometheus I had a hobby.

What it does, precisely

Advertisement

Uptime Kuma checks whether things are up. That is the whole product, and its discipline about that is why it works.

A monitor is a target, a check type, an interval, and a set of notification channels. Every 60 seconds — or whatever you set — it runs the check, records the result and the response time in a SQLite database, and if the state flips it fires your notifications. There is a status page you can publish, and a dashboard with response-time graphs.

The check types cover more than you’d expect:

  • HTTP(s) with expected status codes, keyword matching in the body, JSON queries, and basic or bearer auth
  • TCP port, for anything that opens a socket
  • Ping, for boxes
  • DNS, resolving a record against a specific resolver and checking the answer
  • Docker container, via the socket, checking the container is actually running
  • Push, where the monitor waits for your thing to call it — the dead-man’s-switch pattern
  • Certificate expiry, which is free on every HTTPS monitor and has saved me twice

That list is the ceiling as well as the floor. Uptime Kuma has no concept of a metric. It cannot tell you disk usage, or memory pressure, or that a queue is backing up. It knows up and down, and response time, and nothing else.

Ten minutes, honestly

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
services:
  uptime-kuma:
    container_name: uptime-kuma
    image: louislam/uptime-kuma:1.23.13
    restart: unless-stopped
    volumes:
      - ./data:/app/data
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - "3001:3001"

That is it. Open port 3001, create an admin account on first visit, start adding monitors. There is no config file and no exporters.

The Docker socket mount deserves a pause. Mounting the socket read-only into a container gives that container the ability to enumerate and inspect everything Docker runs, and read-only on the socket does far less than the flag implies — the Docker API does not neatly separate reads from writes at the socket level. If you want the container monitor type, do it through a socket proxy that whitelists the /containers/json endpoint and denies everything else. The wider argument — that handing the daemon socket to a container hands it root on the host — is made in Podman for people who distrust the Docker daemon. If you skip container monitors, drop the mount entirely and lose nothing else.

Once it’s running, the API is available for anyone who prefers not to click:

1
2
3
4
5
6
$ curl -s "http://192.168.1.20:3001/metrics" -u ":$KUMA_API_KEY" | grep -E '^monitor_status'
monitor_status{monitor_name="Nextcloud",monitor_type="http"} 1
monitor_status{monitor_name="Vaultwarden",monitor_type="http"} 1
monitor_status{monitor_name="Broker",monitor_type="port"} 1
monitor_status{monitor_name="NAS",monitor_type="ping"} 1
monitor_status{monitor_name="Backup ran",monitor_type="push"} 0

Yes — that is a Prometheus endpoint. Uptime Kuma exposes its own state in Prometheus format, which means the “ten minute” tool and the “weekend” tool are compatible, and you can start with one and add the other without throwing anything away.

The settings that separate signal from noise

Advertisement

Default Uptime Kuma will page you at 3am because a DNS lookup hiccuped. Four settings fix that, and they are the difference between a tool you keep and a tool you mute.

Retries. Set it to 2 or 3, never 0. A single failed check is a network blip. Three consecutive failed checks is an outage. This alone removes most false alarms.

Heartbeat Retry Interval. When a check fails, Uptime Kuma switches to this shorter interval to confirm. 20 seconds is sensible — it means a real outage is confirmed in a minute rather than three.

Resend Notification if Down X times. Set it. Without it, you get one notification and then silence, which is fine if you act immediately and terrible if the alert arrived while you were asleep. Set it to resend every 10 failures and a genuine outage will keep nudging you.

Upside Down Mode. Ignore this until the day you need it, and then it is magic: it inverts the check, so “up” means the target is unreachable. I use it to confirm that a service which should be firewalled off actually is. If the check goes green, something opened a hole.

The push monitor is the underrated one

Everything above answers “is this service responding?”. The push monitor answers a different and often more important question: “did this thing that should have happened actually happen?”

You create a push monitor, Uptime Kuma gives you a URL with a token, and the monitor goes down if nothing calls that URL within the interval. Then your backup script calls it on success:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/usr/bin/env bash
set -euo pipefail

KUMA_PUSH="https://status.mylab.local/api/push/AbC123xY"

restic backup /srv /home --tag nightly
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check --read-data-subset=5%

# Only reached if every command above succeeded, thanks to set -e
curl -fsS --retry 3 --max-time 10 "${KUMA_PUSH}?status=up&msg=OK" > /dev/null

Set that monitor’s interval to 26 hours. The backup runs nightly; if it fails, crashes, or the machine is off, nothing calls the URL and you get an alert the next morning.

This catches the failure mode that kills people: a cron job that silently stopped running. The service is up. The disk is fine. The backup has not run since February and nothing anywhere is unhappy about it. A push monitor turns silence into an alert, which is the single highest-value monitor in my install. Self-hosted dead man switches for your cron jobs goes deeper on the pattern.

Note the --retry 3 and --max-time 10 on that curl. Without them, a hung network call at the end of a successful backup script blocks forever or fails silently, and you get paged for a backup that worked.

Notifications that reach you

Uptime Kuma supports about ninety notification providers. Ignore most of them. The question worth asking is: what path to my phone survives my own infrastructure being down?

Email through a self-hosted SMTP server is a trap — if the box is down, the alert about the box being down cannot leave. Same for a self-hosted push service if it lives on the same host.

My arrangement: ntfy as the primary, self-hosted, for everything routine. Plus one channel on an external service for the monitors that watch the infrastructure itself, so the “your house is offline” alert does not depend on your house. It costs nothing and it is the difference between monitoring and theatre.

Also: create a notification, tick “Default enabled”, and it attaches automatically to every new monitor. The number of monitors I have created and forgotten to wire to a notification, back when I did it manually, was not zero.

Status pages and maintenance

Two features I ignored for a year and now use constantly.

Status pages are public (or password-protected) views of a chosen subset of monitors, grouped, with a custom domain and an incident banner you can post to. For a homelab this sounds like theatre — I am the only user — and it turns out to be genuinely useful for the household. When someone says “the photos thing isn’t working”, a bookmark that says whether the photos thing is working answers the question without me opening a laptop. The status page is also the one part of Uptime Kuma I would consider exposing publicly, and it has its own read-only rendering path with none of the admin surface.

Maintenance windows suppress alerts for chosen monitors on a schedule or an ad-hoc window. Set one before you start upgrading the NAS and your phone stays quiet. Without this, the natural response to “I’m about to break things on purpose” is to mute notifications entirely, and the natural consequence of that is a monitoring system that has been muted since March. A maintenance window ends by itself, which is precisely why it works and a mute does not.

The broader argument for status pages, and what a self-hosted one is genuinely for, is in Uptime Kuma: a status page for services only you use.

Troubleshooting

Everything shows down after a container restart. Uptime Kuma inside Docker resolves DNS through Docker’s embedded resolver, which does not know about your LAN’s split-horizon names. Either point monitors at IPs, or give the container your internal resolver with a dns: key in the compose file. The split-horizon problem generally is covered in split-horizon DNS at home.

A monitor for a service on the same host fails, though the service works. localhost inside the container is the container. Use the host’s LAN IP, or host.docker.internal with the appropriate extra_hosts entry.

Certificate expiry warnings for a cert you just renewed. Uptime Kuma caches the TLS session. It clears on the next check cycle, or immediately if you toggle the monitor off and on.

The UI gets slow after a few months. The SQLite database is accumulating heartbeats — one row per check per monitor, so 20 monitors at 60 seconds is 28,800 rows a day. Settings → Monitor History has a retention setting; 90 days is plenty. Then run the “Shrink Database” button, which is a VACUUM and reclaims real space. Version 2.x moved to a different storage backend that handles this far better; on 1.x, set the retention.

Notifications stop arriving with no error. Test the notification channel from its edit screen. Uptime Kuma reports a send failure in the monitor’s event log rather than anywhere prominent, so a token that expired three weeks ago produces total, confident silence.

Where the ceiling is

I want to be clear about what you are giving up, because “ten minutes” has a price.

There is no metric collection. You will not learn that the disk fills up in nine days, that memory has been climbing since Tuesday, or that response times have doubled since a deploy. Uptime Kuma tells you a thing is down, at which point you go and find out why with other tools.

There is no alert routing. No severity levels, no escalation, no grouping. If a router dies and takes twelve services with it, you get twelve notifications. Alertmanager exists precisely for this and tuning it properly is a real skill.

There is no history worth analysing. Ninety days of up/down at one-minute resolution in SQLite is a status log, and any question of the form “what is the trend” is out of scope.

And there is no configuration as code. Everything lives in a SQLite database behind a UI. You can back it up — you must back it up — and you cannot review a change to it in a diff. For a homelab I have made peace with this. For something I had to hand over to someone else, it would bother me.

Verdict

Uptime Kuma is worth running for basically everyone with more than three services, and it is the correct first monitoring tool for essentially every homelab. The ten minutes is real. The push monitor alone justifies the container. The certificate expiry checks come free and will eventually save you a Saturday.

It is the wrong tool if you need to answer “why” rather than “whether”, if you need alert routing, or if you need to see a trend. Those are Prometheus’s job, and Prometheus and Grafana without the enterprise baggage makes the case for when that weekend becomes worth spending. The two coexist happily — Kuma’s Prometheus endpoint means it can become a data source for the bigger stack rather than a thing you replace.

Mine has run for two years, watches thirty-one things, uses 90 MB of RAM, and has never once been the reason I was in the rack. It is the only monitoring I have ever set up and then kept.

Advertisement
Advertisement
Smarc
Written by Smarc

Founder and editor of vo.rs. A lifelong tinkerer who self-hosts far more than is sensible, hardens Linux boxes for fun, and prods the latest AI tools to see what they can really do. The how-to guides here are the notes Smarc wishes had existed the first time round.