Blog

Self-hosted uptime monitoring: one compose file, and the logs come with it

5 min read ยท published 2026-10-11

The short version

Self-hosted uptime monitoring used to mean picking between two shapes: a single-purpose uptime tool that never grows past green and red, or a monitoring stack that can graph anything once you have spent a week assembling it. UpControl's core is a third shape. It is AGPL-3.0, runs from one compose file, and does not stop at uptime: heartbeats for jobs, a log ingest endpoint, events and analytics, public status pages. The hosted service at upcontrol.io runs the same code and answers the same CLI, so nothing you wire up is thrown away if you ever stop operating the box.

What the self-hosted package is, from the project's README as of 2026-10:

The self-hosted core
LicenseAGPL-3.0 core, MIT CLI
Setupone compose file, Docker with Compose v2
The box1GB RAM recommended (512MB with swap minimum), 10GB disk
Website checksfrom 1-minute intervals, SSL and domain expiry on every check
Heartbeatsfor cron jobs and workers, never counted toward the check limit
Logsone ingest endpoint, POST /i, NDJSON; SDK, CLI or any sender
Events and analyticsfunnels, retention, breakdowns, A/B tests built from events
Status pagespublic, one per project, with real uptime bars
AlertsTelegram, email through your own SMTP, Slack, Discord, any webhook
Telemetrynone: no version pings, no usage beacons

Why run your own

Three reasons show up every time. Some teams want the data to never leave their network: customer URLs, log lines, alert targets all staying inside. Others have a box that is already paid for and want the monitoring line item to stay at zero. And some want the monitor working even when the vendor's own page is red.

The self-hosted package does not call home, and that is a documented promise rather than a default nobody checked: no version pings, no usage beacons, and if it ever changes the project says it will be opt-in and loudly documented.

One counterpoint belongs here, and the README says it too: a one-box self-host cannot watch the box it runs on. If the box dies, the monitor dies with it. The honest advice is to let something outside the box watch the box, and the free hosted plan covers exactly that: three checks, every 5 minutes, no card.

The install, in one command

  1. Put Docker with Compose v2 on the box. 1GB of RAM is the recommendation; 512MB with active swap is the floor, and the installer refuses to start below it rather than fall over later.
  2. Clone the repo and run the installer: git clone https://github.com/upcontrol-io/upcontrol, cd upcontrol/infra, ./install.sh.
  3. Answer four questions while the images pull. When it finishes, https://localhost is a working instance: website checks every minute, a log ingest endpoint, Telegram and email alerts.
  4. No account with anyone is created, and nothing phones home at any point in this flow.

Single-user is the default: UC_AUTH=none boots one owner account with no sign-in, which is right for a private box. Set UC_AUTH=magic-link before exposing the instance to the internet.

Wiring the app for logs and events

Checks need nothing from your code. Logs do, and one command hands the wiring to the coding agent you already use (Claude Code, Cursor, Codex, Gemini CLI, Copilot, Windsurf, Amp, Aider, Cline, opencode):

npx upcontrol --endpoint https://your-box

The CLI points wherever you tell it; the hosted service is only the default. You ask in plain words, "send all my logs to upcontrol" or "track my users from first visit to purchase", the agent stages a diff for your review and commits nothing, and npx upcontrol verify waits until data provably arrives, naming the failure precisely when it does not.

Your code never leaves the machine. The SDK sends only what the reviewed log points emit, scrubbed client-side before anything is sent. And the SDK is optional: the wire is plain NDJSON over one HTTP door, so a Go, Rust or browser sender needs no package at all.

The why, not just down

Uptime tells you the site broke. The interesting question is what it was doing when it did, and that is the part most self-hosted setups never get to. The core correlates checks with logs, deploys and events: an incident page carries the deploy that landed before it and the log lines around the failure, not only "down since 12:04". Error-rate detection runs over your own logs and fires alerts on new errors, and a missed heartbeat opens an incident like any failed check, at most an hour past its due time.

That is the lane the README claims for it, between the two usual shapes: Uptime Kuma is genuinely lighter if uptime checks are all you need, and a Grafana stack is more powerful if you have the time to assemble and query it. Logs, checks and the why of an incident on one box is the middle.

The honest limits

  • One owner account by default, no sign-in. Right for a private box, and you must switch auth modes yourself before putting it on the internet.
  • No synthetic probes advertised from many cities. The fleet checks from its regions and stores the response phases (dns, tcp, tls, wait) per check; a fixed region list is what a self-host gets.
  • Younger product, fewer integrations than the decade-old incumbents. Telegram, email, Slack, Discord and webhooks cover the alerting; a large existing toolchain may miss a connector it relied on elsewhere.
  • Web analytics on a self-host reaches back at most 31 days, and there are no session recordings. Tools built for analytics alone go deeper and further back.
  • It cannot watch its own box. Pair it with the free hosted tier, or accept that a dead machine reports nothing.

One command starts it, and the same command wires your app to it: [get the compose file](https://upcontrol.io/?utm_source=blog&utm_medium=vs&utm_campaign=engine).