Your homelab doesn't page you. Your VPS doesn't email you when it's dead. Here's the open-source monitor that does — and the setup that keeps it from lying to you.

I found out my home server was down because a friend messaged me: "hey, is your site down?" That is, technically, a monitoring system. A terrible one. Free tier: public embarrassment. Paid tier: also public embarrassment, but faster.

Uptime Kuma is the fix most self-hosters land on. It's an open-source uptime monitor — HTTP checks, ping, DNS, certificate expiry, port probes — wrapped in a genuinely pleasant dashboard, with one standout feature the big SaaS monitors charge you for: unlimited public status pages. One binary (or one Docker container), SQLite by default, MariaDB if you grow into hundreds of monitors in the 2.x line. The standard advice is "install it and add your URLs." The standard advice is incomplete. Here's the operator's version: the install, the five monitors that actually matter, notifications that can wake you up, and the traps that make self-monitoring lie to you.

What you'll need

  • A VPS (or a spare machine) with Docker and Docker Compose installed
  • A domain or subdomain for the dashboard — status.example.com
  • A reverse proxy for HTTPS (Caddy makes this a three-line config)

Install it with Compose, not a bare docker run. The day you need to change something, you'll thank yourself for having a file:

services:
  uptime-kuma:
    image: louislam/uptime-kuma:2
    container_name: uptime-kuma
    restart: always
    ports:
      - "3001:3001"
    volumes:
      - uptime-kuma-data:/app/data

volumes:
  uptime-kuma-data:

docker compose up -d, then open http://your-server:3001. First visit asks you to create the admin account — do this over SSH port-forwarding, not the open internet, because this panel has no login until you create one and every exposed port is a temptation. Then put it behind Caddy immediately:

status.example.com {
    reverse_proxy 127.0.0.1:3001
}

Automatic HTTPS, done. Kuma behind TLS, never raw on the internet again.

The five monitors that earn their keep

Beginners add fifty URLs and check every 60 seconds. Veterans add five things and tune the intervals. Every monitor costs battery, bandwidth, and — most importantly — your attention. Here's the set that covers 90% of real outages:

  1. Your homepage, HTTPS with keyword check. Don't just check for HTTP 200 — check that the page contains a string that proves your app actually rendered (your site name, a footer snippet). A 200 from a broken reverse proxy is a lie your monitor will happily report as up. Enable Certificate Expiry on this monitor too, with a 14-day warning. Certs are the single dumbest cause of "the site is down" in self-hosting.
  2. Ping to your gateway and your VPS. Ping is the cheapest signal there is. If ping fails but HTTPS works, you've learned something. If everything fails at once, it's the network, not your app.
  3. DNS for your domain. Add a DNS monitor for your apex domain. Authoritative DNS outages are rare but total, and your other monitors can't even resolve their targets when DNS breaks — which means they all fail identically and tell you nothing.
  4. TCP port checks for services with no web UI. SSH (22), your WireGuard UDP port can't be TCP-checked so monitor the WireGuard endpoint with a ping instead, database ports your apps need. The services without dashboards are exactly the ones that die silently.
  5. A push monitor for your backup cron job. This one is the pro move: Kuma gives you a unique heartbeat URL, and your nightly backup script curls it on success. If the backup job silently dies — disk full, lock file, changed password — the absence of the heartbeat is what alerts you. Pull monitors can't catch a job that never started.

Set sensible intervals: 60 seconds for the homepage, 120 for the rest. The default 60 on everything is fine for five monitors and wasteful for fifty.

Notifications that can actually wake you up

A monitor that can't reach you is a screensaver. Two rules:

Rule one: the alert path must not share fate with the thing being monitored. If Uptime Kuma runs on your homelab and your homelab loses internet, nothing arrives — no check results, no alerts, nothing. Put at least one monitor's notification on a path that survives your outage. Telegram is the usual pick: create a bot via @BotFather, get your chat ID from @userinfobot, paste the token into Kuma's Telegram notification settings. It works from anywhere with internet, survives your homelab going dark (the bot API is Telegram's infrastructure), and pushes to your phone.

Rule two: add a fallback channel with different failure modes. Telegram down is rare but not impossible. Email through a real SMTP provider (not your own mail server — which may live on the same dying box) is the classic second channel. NTFY is a good lightweight third: ntfy.sh hosted or self-hosted, one HTTP call, apps on every platform.

Then do the unglamorous part: set retries before alerting. Kuma lets you require 2–3 consecutive failures before firing. One failed check is usually a blip — a garbage-collected pause, a one-second route flap. Alerting on the first failure is how you train yourself to ignore alerts, and ignored alerts are worse than none. Set "notification on up" too, so the all-clear closes the loop instead of leaving you wondering at 4 AM whether it fixed itself.

The public status page (your trust move)

Kuma's killer feature: a status page you can publish at status.example.com/status/your-page. Turn it on for anything with users — even if "users" means two friends and a client. It takes ten minutes, and it converts "is it down?" messages into zero. Show overall uptime, per-service status, and the incident history Kuma records automatically. The discipline it forces is the real value: you start caring about the incident log because other people can see it.

Back up the monitor and upgrade without fear

Uptime Kuma's entire state lives in /app/data inside the container — one SQLite file (or your MariaDB if you graduated). Backup is one rsync of the named volume:

docker run --rm -v uptime-kuma-data:/data -v ~/backups:/backup \
  alpine tar czf /backup/uptime-kuma-$(date +%F).tar.gz -C /data .

Run that nightly alongside your other backups (and add a push monitor for it — yes, the monitor watches the backup that backs up the monitor; turtles all the way down).

Upgrades: pull the new image, recreate the container, keep the volume. docker compose pull && docker compose up -d. Always check the release notes first — the 1.x to 2.x jump changed the database options and rootless Docker behavior, and "just re-pull" without reading is how people discover breaking changes at 2 AM. Test the dashboard loads, confirm one monitor flips green, and you're done.

Three traps that make monitoring lie

  1. Monitoring from the same network you're watching. If Kuma lives on your LAN and checks your LAN services, it will report everything green during an ISP outage — because it can't reach the internet either, and its "up" verdicts are stale. At least one external perspective matters: a $4 VPS running a second Kuma instance, or a friend's server, cross-checking each other.
  2. Cert-expiry monitors pointed at the wrong thing. Point the expiry check at the domain your users actually type, behind the same proxy they hit. Checking https://localhost from inside the box verifies a cert nobody uses.
  3. Maintenance windows you forgot to set. Upgrading your own server at midnight and getting paged by your own monitor is a rite of passage exactly once. Kuma has maintenance schedules — use them, or disable notifications during planned work. Alert fatigue from your own upgrades is how people start ignoring real pages.

The bottom line

Five monitors, two notification channels that don't share fate with your servers, one public status page, and a backup of the monitor itself. That's an afternoon's work, and it replaces the world's worst monitoring system — your friends texting you "is it down?" — with one that pages you first.

Sources