Self-Hosted Uptime Monitoring: Who Watches the Watcher
Self-hosted uptime monitoring is a solved technical problem with an unsolved operational one. The install is ten minutes. The part nobody prices is what happens in month fourteen, when the container is still running, the alert channel has rotted, and the dashboard has become a thing you look at rather than a thing that tells you.
That is worth being precise about, because the failure mode is not “the monitor stopped working.” It is “the monitor is working and you have stopped believing it.”
What Uptime Kuma actually is
Start with the facts, since they are all verifiable from the project’s own repository:
| Item | Detail |
|---|---|
| License | MIT |
| Monitor types | HTTP(s), TCP, HTTP(s) Keyword, HTTP(s) JSON Query, Websocket, Ping, DNS Record, Push, Steam Game Server, Docker Containers |
| Notifications | README states “Telegram, Discord, Gotify, Slack, Pushover, Email (SMTP), and 90+ notification services” |
| Deployment | Docker Compose, docker run, or bare metal (Node.js ≥ 20.4 with pm2) |
| Datastore | SQLite by default; MariaDB or embedded MariaDB as alternatives |
Two corrections to things I had assumed. First, the licence is MIT, not a copyleft licence — so the usual argument about self-hosting as a hedge against a project going closed-source is weaker here than people imply. Second, the “90+” figure is the README’s own approximation; there is no enumerated official count, so do not quote a precise number.
Two documented limitations worth knowing before you install: FreeBSD, OpenBSD, and NetBSD are explicitly unsupported, and NFS is explicitly not supported as the data volume. That last one disqualifies a common homelab setup where the data directory lives on a NAS, which is exactly the kind of thing discovered after the install.
The project’s single-connection SQLite default is also documented in code with a warning that multiple connections produce SQLITE_BUSY: database is locked. Fine for a personal deployment; a real constraint if you scale up.
The obvious problem
A self-hosted monitor runs on your infrastructure. If your infrastructure goes down — the VPS, the homelab, the home network — the monitor goes down with it, and the thing it was supposed to tell you about is precisely the thing it can no longer report.
This is not a bug and there is no version of self-hosting that fixes it. Every monitoring system needs a vantage point that is not inside the failure domain, and a self-hosted monitor has a vantage point inside it by construction.
The problem nobody documents
Search the Uptime Kuma repository and wiki for guidance on how you would know if Uptime Kuma itself died, and you will not find it. Not in the README, not on the wiki home.
That absence is not an oversight in the project — it is an absence across the whole category. The commercial services document how to reduce false positives; they do not document how a self-hosted deployment avoids producing false negatives, because for them, the monitor being up is their problem, not yours.
So the question “how do I know my monitor is still running?” has no vendor answer, and the answer you derive yourself has a shape: you need a second observer, outside the same failure domain.
What the commercial services do instead
The multi-vantage-point problem is well documented by the services that sell against it:
- UptimeRobot states it “uses a distributed monitoring system to minimize false-positives,” verifying downtime “by conducting additional checks from different servers and providers within the same region.”
- StatusCake documents “Confirmation Tests” that “help eliminate these false alerts by requiring additional checks before the website is marked as down,” and recommends “at least three IPs per uptime test.”
- Better Stack frames the principle: checks “run against your service from the outside, reaching it the way a real user would.”
Read the UptimeRobot wording carefully, though, because there is a limitation hidden in it: the additional checks come from “different servers and providers within the same region.” Multi-vantage-point does not mean global coverage. A regional network problem can still read to that service as your site being down. No amount of paid monitoring removes the general problem that a check reflects one point’s view of the world.
The dead-man’s-switch pattern
The one monitoring idea that genuinely covers the “the watcher is dead” case is inversion: instead of your monitor asking “are you up?”, your server periodically tells the monitor “I’m still here.” Absence of the message is the alarm.
Healthchecks.io documents the model precisely: “It keeps silent as long as pings arrive on time. It raises an alert as soon as a ping does not arrive on time.”
Uptime Kuma supports this natively as a Push monitor type — the same pattern UptimeRobot sells as “Heartbeat” monitoring.
The elegant property is that it survives the failure it is designed for. If your server dies, the pings stop, and the alert fires from somewhere else. If your network dies, the pings stop, and the alert still fires from somewhere else.
The catch: it monitors liveness, not correctness. A server that is running but serving 500s still sends its ping and stays silent. So you need both patterns — a push heartbeat for “is the machine alive,” and a plain HTTP check for “is the site actually working.”
Alert fatigue is the real cost
The reason a monitor ends up ignored is documented better by Google’s SRE book than by any monitoring vendor. Its chapter on monitoring distributed systems makes two points that map directly onto a personal site’s setup:
Alerts should fire on symptoms, not causes — page on the thing a user would notice, not on every internal condition you happen to be able to measure. And there is a hard human limit, stated as plainly as it gets: “Every time the pager goes off, I should be able to react with a sense of urgency. I can only react with a sense of urgency a few times a day before I become fatigued.”
For a solo site owner, the arithmetic is worse than for a team, because there is no rotation and no second person to notice that nobody has responded in a while. Three false alarms on a Saturday morning and you will mute the channel — after which your monitor is decorative.
The mitigations are structural, not motivational:
- Require consecutive failures before alerting. Every commercial service documents some version of this. In Uptime Kuma it is the retry/interval configuration on the monitor.
- Use a channel you actually act on. A notification channel you have muted is not a channel.
- Separate “the site is down” from “the site is slow.” Different urgency, and merging them trains you to ignore both.
- Use maintenance windows. Announced downtime you have flagged is not an incident.
One thing to tune that the README doesn’t mention
Uptime Kuma’s history retention is not documented in the README. The default in the current code is 365 days, and setting the retention value below 1 disables deletion entirely — infinite retention, which was the behaviour in older 1.x releases.
The settings UI exposes the retention field, a database size reading, and a “Shrink Database” button that runs a VACUUM. That is the maintenance ritual nobody mentions: a monitor that has been running for two years on SQLite has accumulated two years of check results, and if retention was ever set to infinite, the database will keep growing until something notices.
For a personal deployment, 365 days is generous. Ninety days is plenty for answering “when did this start happening.”
A setup that survives being ignored
Four things, and none of them are about which tool you pick:
- Self-hosted monitor for HTTP checks on your own domain — the detailed, fast signal.
- A push heartbeat from the server to an external service, for “the machine is alive.”
- A free external check on the domain, from a provider on different infrastructure, purely as the historical record of uptime. You will use it in an argument with a host, and you will want it to be somewhere other than on the machine in question.
- A calendar reminder to look at the monitor once a quarter. Not to check the site — to check the monitor: is the alert channel still valid, is the database still growing, are there monitors pointing at things that no longer exist.
The tool choice is the cheap decision. Whether you are still paying attention in eighteen months is the expensive one, and it is not a feature any uptime monitor ships with.
Written by TestedHost. Every recommendation on this site comes from running the setup described, on a live deployment — not from a vendor spec sheet. Spotted something out of date? Tell us.