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 KumaGatus
ConfigurationWeb UI, stored in SQLiteSingle YAML file
Status pagesMultiple, branded, built by clickingGenerated from config
Check typesHTTP, TCP, ping, DNS, Docker, certs, 90+ notifiersHTTP, TCP, DNS, ICMP, certs, conditions DSL
Resource use~150–250MB~20–30MB
Backup/rebuild storyExport or copy the SQLite filegit clone, done
Best fitHumans who like dashboardsGitOps 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.