A status page has one job: answering "is it down for everyone or just me?" before anyone messages you. To do that job it must satisfy one non-negotiable rule — it cannot live on the infrastructure it reports on. A status page that dies with your server is a monument, not a tool. So the architecture is fixed before the software choice: the page runs somewhere else (a $4/month VPS, a free-tier container host, a Pi at a relative's house), checking your services from the outside. Uptime Kuma if you want to configure it by clicking; Gatus if you want the config in git.
Outside-in checking is a feature, not just insurance
Hosting the checker off-site does more than survive outages: it tests the path your users actually take. DNS resolution, certificate validity, your ISP's routing, the reverse proxy — an internal monitor sees none of that, and "all green internally, unreachable from the world" is a genuinely common failure shape (expired cert and broken dynamic DNS being the classic causes). The cheapest viable homes: the smallest VPS tier at any provider ($3–5/month gets you far more than a status page needs — Gatus runs in ~20MB of RAM), or a spare Pi on someone else's broadband with Tailscale back to you. I use the VPS, because it also gives the page a clean public URL that doesn't advertise my home network.
Uptime Kuma vs Gatus
| Uptime Kuma | Gatus | |
|---|---|---|
| Configuration | Web UI, stored in SQLite | Single YAML file |
| Status pages | Multiple, branded, built by clicking | Generated from config |
| Check types | HTTP, TCP, ping, DNS, Docker, certs, 90+ notifiers | HTTP, TCP, DNS, ICMP, certs, conditions DSL |
| Resource use | ~150–250MB | ~20–30MB |
| Backup/rebuild story | Export or copy the SQLite file | git clone, done |
| Best fit | Humans who like dashboards | GitOps people |
Kuma is the friendlier product and its notifier catalogue is unmatched — if your alert destination exists, Kuma ships an integration for it. Gatus is the more disciplined one: the entire deployment is one YAML file in a repo, which means the VPS it runs on is disposable. Both render clean public status pages; neither embarrasses you in front of users.
A Gatus config that covers the essentials
endpoints:
- name: Photos
group: family
url: https://photos.example.com/api/server/ping
interval: 60s
conditions:
- "[STATUS] == 200"
- "[RESPONSE_TIME] < 800"
- "[CERTIFICATE_EXPIRATION] > 72h"
alerts:
- type: ntfy
failure-threshold: 3
send-on-resolved: true
Two details in there do disproportionate work. The certificate-expiration condition catches the single most common self-inflicted outage three days before it happens. And failure-threshold: 3 means one blip doesn't page you — a 60-second interval with a three-strike rule alerts within four minutes of a real outage and never for a transient. Check health endpoints where apps offer them (Immich's /api/server/ping, Jellyfin's /health) rather than login pages, which can 200 while the app is broken behind them.
Public or private, and what to show
For a homelab serving family and friends, an unlisted-but-public page is the right default: no login (a status page behind your SSO fails exactly when SSO does), no internal hostnames or ports on display, service names written for civilians ("Photo backup", not "immich-server-prod"). Show per-service state, response times if you like, and incident notes. Anything with actual external users should treat the page as a real product surface and link it from the app's error pages — that link is what intercepts the support messages.
Incident notes that actually calm people
The status light says something is down; the note is what stops the messages. The template that works is four facts in two sentences: what's affected, since when, whether data is safe, when you'll update next.
Photo backup is down since 14:10 for a disk replacement.
All photos are safe; uploads will queue and sync automatically.
Next update by 18:00.
The load-bearing parts are "data is safe" (the only thing non-technical users are actually asking) and the timestamped promise of a next update, which is what prevents the follow-up message at 16:30. Post the note within minutes even when you know nothing yet — "investigating, next update in an hour" outperforms silence by a wide margin. Both tools support incident banners; Kuma's are easier to post from a phone, which is where you'll be when it matters.
A status page is not monitoring
The page is the public face; it tells people what's broken. It doesn't tell you why, and it shouldn't try — that's the job of the internal stack, and the homelab monitoring maturity path covers that tier properly. The clean division: Gatus or Kuma outside checking the user-visible surface and feeding the status page; whatever depth of internal monitoring you enjoy on the inside. Small labs can stretch one Kuma instance across both roles, but keep the instance off-site regardless — the rule from paragraph one outranks convenience.
What I'd do
Gatus, from the config above, on the cheapest VPS you can find, with ntfy notifications and the three-strike threshold; Uptime Kuma instead if YAML-averse people will help run it. Health endpoints not homepages, cert-expiry conditions on everything public, civilian service names, and the two-sentence incident template pinned somewhere you can copy-paste it from a phone. Total cost: about $48 a year and an afternoon — cheap for never again explaining, mid-restore, that yes, you know it's down.