Self-hosted uptime monitoring with a TUI over SSH.
857
Self-hosted uptime monitoring with a TUI over SSH.
No browser. No client install. Just ssh -p 23234 your-server.
An uptime monitor you manage entirely from the terminal. It runs as a server, exposes an SSH endpoint, and drops you into a full TUI — monitors, alerts, logs, nodes, all there.
Built on RDGames/go-upkeep. Rewritten for clustering, config-as-code, and a proper dashboard.
Canonical repo: gitea.lerkolabs.com/lerkolabs/uptop — GitHub is a mirror; releases are published to both.
/metrics endpoint, wire it straight to GrafanaGroup monitors roll up child status for display but don't fire their own alerts yet — attach alerts to the children.
![]() | ![]() |
![]() | ![]() |
![]() |
UPTOP_ADMIN_KEY="$(cat ~/.ssh/id_ed25519.pub)" go run ./cmd/uptop
ssh -p 23234 localhost
Want some data to look at first:
UPTOP_ADMIN_KEY="$(cat ~/.ssh/id_ed25519.pub)" go run ./cmd/uptop -demo
services:
uptop:
image: lerkolabs/uptop:latest
restart: unless-stopped
ports:
- "23234:23234"
- "8080:8080"
environment:
- UPTOP_DB_TYPE=sqlite
- UPTOP_DB_DSN=/data/uptop.db
- UPTOP_STATUS_ENABLED=true
# - UPTOP_ADMIN_KEY=ssh-ed25519 AAAA... you@host
volumes:
- ./data:/data
sysctls:
- net.ipv4.ping_group_range=0 2147483647
First run: set UPTOP_ADMIN_KEY to your SSH public key.
The sysctls line enables unprivileged ICMP inside the container — without it, ping monitors get no response and silently report DOWN.
Download from Releases — amd64 and arm64 tarballs (zip for Windows), plus .deb/.rpm packages and checksums.txt.
go install gitea.lerkolabs.com/lerkolabs/uptop/cmd/uptop@latest
Upgrading: Pull the new image (or binary) and restart. Database migrations run automatically on startup.
Export your current monitors:
uptop export -o monitors.yaml
Apply a config file:
uptop apply -f monitors.yaml
uptop apply -f monitors.yaml --dry-run # see what would change
uptop apply -f monitors.yaml --prune # delete anything not in the YAML
Full reference in docs/config-as-code.md.
| Variable | Default | Description |
|---|---|---|
UPTOP_PORT | 23234 | SSH server port |
UPTOP_HTTP_PORT | 8080 | HTTP server port (status page, push, metrics) |
UPTOP_DB_TYPE | sqlite | sqlite or postgres |
UPTOP_DB_DSN | uptop.db | Database path or connection string |
UPTOP_STATUS_ENABLED | false | Enable public status page |
UPTOP_STATUS_TITLE | System Status | Status page title |
UPTOP_ENCRYPTION_KEY | AES-256-GCM key for alert credentials (details) | |
UPTOP_CLUSTER_MODE | leader | leader, follower, or probe |
UPTOP_PEER_URL | Leader URL for follower and probe nodes | |
UPTOP_CLUSTER_SECRET | Shared key for cluster + API auth | |
UPTOP_INSECURE_SKIP_VERIFY | false | Skip TLS verification for checks |
UPTOP_ALLOW_PRIVATE_TARGETS | false | Allow monitoring RFC1918/loopback addresses |
UPTOP_ADMIN_KEY | SSH public key seeded as first admin on startup | |
UPTOP_TRUSTED_PROXIES | Comma-separated CIDRs/IPs whose X-Forwarded-For is trusted (details) |
See .env.example for all options including TLS, probes, and advanced settings.
By default uptop ignores the X-Forwarded-For header and rate-limits by the direct connection address — so a client can't spoof the header to bypass limits. If uptop sits behind a reverse proxy (nginx, Caddy, Cloudflare, an ALB), set UPTOP_TRUSTED_PROXIES to the proxy's address(es) so the real client IP is used instead:
# single nginx/Caddy on the same host
UPTOP_TRUSTED_PROXIES=127.0.0.1
# a proxy subnet, or Cloudflare ranges
UPTOP_TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12
Only requests whose immediate peer is in this list have their X-Forwarded-For honored (right-most non-trusted hop wins). Bare IPs are treated as single hosts; invalid entries are warned about and skipped. Leave it unset if uptop is exposed directly.
Set UPTOP_ENCRYPTION_KEY to encrypt alert credentials (SMTP passwords, webhook URLs, API tokens) at rest with AES-256-GCM. Generate a key:
openssl rand -hex 32
Without this, credentials are stored as plaintext in the database. uptop warns on startup if unset. To encrypt credentials on an existing install, run uptop migrate-secrets with the key set.
uptop prunes its own history in the background — no external cleanup jobs needed:
| Data | Kept |
|---|---|
| Check history | newest 1,000 checks per monitor |
| State changes (UP/DOWN transitions) | newest 5,000 per monitor |
| Logs | newest 200 entries |
| Maintenance windows | 7 days after they end (configurable) |
Sparklines, uptime percentages, and SLA reports are computed from these windows, so very long-horizon stats aren't retained. Export to Prometheus via /metrics if you need unlimited history.
uptop supports three modes: leader (default single node), follower (HA failover — takes over if the leader goes down), and probe (stateless distributed checks from multiple regions).
See docs/clustering.md for setup guides, or the working examples in deploy/.
Export your Kuma backup JSON, then:
curl -X POST http://localhost:8080/api/import/kuma \
-H "X-Uptop-Secret: your-secret" \
-H "Content-Type: application/json" \
-d @kuma-backup.json
MIT — see LICENSE.
Content type
Image
Digest
sha256:612e303f0…
Size
13.5 MB
Last updated
about 1 month ago
docker pull lerkolabs/uptop