Skip to content
nobloatPublic

About

Minimal alternative to uptimekuma

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

43 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

][• up

A minimal alternative to Uptime Kuma: HTTP, Prometheus and push checks, notifications and status pages, configured in plain key = value files.

  • One static binary, Go standard library only (go.mod), in the spirit of nobloat.org
  • No database: one append-only CSV audit log per monitor
  • Config as code: one file per monitor, notifier and status page, checked with up -check, reloaded on change

monitor list, desktop and phone, light and dark

Features

HTTP checks status codes, body regex, JSON match, headers, basic auth, redirects, TLS expiry
Prometheus checks one metric of a /metrics endpoint, or a PromQL query (Thanos, Mimir, VictoriaMetrics work too)
Push monitors dead man switch for cron jobs and backups; Uptime Kuma and healthchecks.io compatible URLs
Notifications Slack / Mattermost webhooks, mail, ilert; reminders while red
Status pages public, per tag, custom templates
Web UI nobloat/ui look (graphite or paper), English and German, live updates, filters, search, keyboard shortcuts and command palette (?, Ctrl+K), pause with reason and end, create, edit and delete monitors and status pages (editors within their tags; the config directory must be writable, not :ro), dark mode, phone friendly, installable on the home screen
Heartbeat pings an external URL so something notices when up itself is down

Not included: editing notifiers and up.conf in the UI, graphs, user management (that is the IdP's job, see single sign-on).

Deployment

compose.yaml with Caddy for TLS:

services:
  up:
    image: ghcr.io/nobloat/up:latest
    restart: unless-stopped
    environment: {TZ: Europe/Vienna}
    volumes: [./config:/config:ro, ./data:/data]
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports: ["80:80", "443:443", "443:443/udp"]
    volumes: [./Caddyfile:/etc/caddy/Caddyfile:ro, caddy:/data]
volumes:
  caddy:

Caddyfile:

up.nobloat.org {
	reverse_proxy up:7493
}
  • ./data must be writable by uid 65534: sudo chown 65534:65534 data
  • up -check -config <dir> validates a config, e.g. in CI (exit code 1 on any error)
  • A damaged audit log stops startup instead of being reset (-check reports it with file and line): back it up and repair it

Backup

The data dir and the config dir are the backup. The UI writes the config dir, so back it up too.

  • Copy both with any tool while up runs, full or incremental (rsync -a --delete, restic, borg, volume snapshots): audit logs only grow by appended, synced records, and config files are replaced by atomic renames, so a copy is never half a file. Skip .tmp-* files.
  • Or export through up for a consistent cut (admin): GET /api/export streams a tar.gz with manifest.json first (app, version, created, every file with path, size, mtime, sha256), then config/<file> for every file of the config dir, then data/<file>. ?since=<created of an earlier manifest> sends only the files changed since then, plus the full manifest, so deletions show.
export UP_URL=https://up.nobloat.org UP_USER=admin UP_PASSWORD=…
up export > up-full.tgz
up export -since 2026-11-05T10:00:00.123456789Z > up-inc.tgz   # created from up-full.tgz's manifest.json
up restore -data ./data -config ./config up-full.tgz up-inc.tgz  # offline

up restore needs an empty or missing data dir, applies the archives in order (deleting files missing from each manifest), never overwrites an existing config file, verifies sha256 against the last manifest and runs the checks of -check. Without -config only the data is restored. Untarring by hand works too.

Formats: up.conf and <name>.<kind>.conf are key = value text; data/<monitor>.csv (dots in the name become _) is CSV with the header timestamp,event,state,message.

Configuration

A directory (-config, /config in the image): up.conf plus one file per entity, named <name>.<kind>.conf. Start from example/config, or see config for every feature (make run).

config/
  up.conf
  website.monitor.conf
  api.monitor.conf
  ops-chat.notifier.conf
  public.page.conf
  • One key = value per line, # starts a comment, lists are comma separated, nested keys are dotted (headers.X-Api-Key)
  • Durations: Go syntax plus days (30s, 1h, 7d, 1d12h)
  • Unknown keys are errors. A broken entity file is skipped and logged; only a broken up.conf stops startup
  • The directory holds credentials: treat it as secret

up.conf

listen = :7493
base_url = https://up.nobloat.org
data_dir = /data
auth.user = admin
auth.password = secret
heartbeat.urls = https://hc-ping.com/<uuid>
Option Default
base_url required public URL, for links in notifications
data_dir required audit logs, one CSV per monitor
auth.user, auth.password required without role.* basic auth for the UI and API, always admin
trusted_proxies CIDRs whose Remote-User / Remote-Groups headers are believed, see single sign-on
role.viewer, role.editor, role.admin IdP groups per role
access.<group> tags whose monitors the group sees, * for all
logout_url, account_url IdP links next to the signed-in user's name
design graphite look of the UI: graphite or paper (nobloat/ui)
brand_color, brand_color_dark the design's #rrggbb accent color; the dark one defaults to a lighter shade of brand_color
listen :7493 plain HTTP, put a TLS proxy in front
proxy HTTP proxy for all checks and notifications
evaluation_interval 30s how often notifications are evaluated and batched
heartbeat.urls, heartbeat.interval 1m URLs to GET while up runs

Single sign-on

Optional: with only auth.user / auth.password everyone shares one admin login, as before. Single sign-on works the same as in bill and track: caddy's forward_auth asks nobloat/auth (or another IdP) to log the user in and forwards Remote-User and Remote-Groups. up believes those headers only from trusted_proxies; anyone else needs basic auth.

trusted_proxies = 10.0.0.0/8
role.viewer     = up-viewer
role.editor     = up-editor
role.admin      = up-admin
access.up-all   = *
access.team-a   = prod, api
logout_url      = https://auth.example.com/logout
account_url     = https://auth.example.com/settings
Role May
viewer see the monitors of their tags, with config (secrets masked) and log
editor also check now, pause and resume them; create, edit and delete their monitors and status pages (shows their secrets), keeping tags within their own and the existing ones
admin every monitor regardless of tags, notifier failure banners

A user needs a role group and, below admin, an access.* group: up-editor + team-a may pause the monitors tagged prod or api; other monitors answer 404. The highest role wins, tags add up. Status pages and push URLs stay public: route /push/*, /api/push/*, /ping/*, /status/*, /static/* and Authorization: Basic past the IdP (see Caddyfile).

GET /api/me answers {user, role, tags} for the signed-in user (tags is ["*"] for every monitor), like bill's and track's.

Monitors

type = http
description = Home page answers with 2xx
tags = public
interval = 1m
retry_count = 2
notifiers = ops-chat
url = https://example.com/health
cert_min_valid_days = 14
Type Checks Options
http an HTTP(S) endpoint HTTP options
metric one metric of a Prometheus text format endpoint HTTP options, metric, labels.<name>, value (< 80, ops > >= < <=); every matching series must pass, none fails
promql an instant query; url is the API base HTTP options, query, value; every series must pass, empty fails
push something reports in token (16+ characters, unique), see push monitors
Option Default
type, interval required interval: between checks, or expected between pushes
description public, shown on status pages
tags UI filters and status pages
retry_count 0 failures after the first before red; yellow until then
retry_interval interval between checks while yellow
timeout 10s per check
grace push only: extra time before a missing push fails
notifiers notifier names; unknown ones are skipped and logged

HTTP options

For http, metric and promql (promql always uses GET).

Option Default
url required
method GET GET, POST, HEAD
headers.<name> Host overrides the host header
basic_auth.user, basic_auth.password
body request body
accepted_status any 2xx e.g. 200, 204
body_regex RE2 syntax
json_match.path, json_match.equals data.0.status = ok; 1 is a number, "1" a string
max_redirects 10
skip_verify false skip TLS verification
cert_min_valid_days red without retries when the certificate expires sooner
  • Redirects never downgrade HTTPS. With credentials, headers, a body or a query string only same-origin redirects are followed
  • Secrets are masked on the detail page; errors never contain the URL

Push monitors

curl -fsS https://up.nobloat.org/push/backup/<token>
curl -fsS -d '{"files": 12}' "https://up.nobloat.org/push/backup/<token>?status=down"

curl -fsS "https://up.nobloat.org/api/push/<token>?status=down&msg=disk%20full"

some-job > job.log 2>&1; rc=$?; curl -fsS --data-raw "$(tail -c 4000 job.log)" https://up.nobloat.org/ping/<token>/$rc

No push within interval + grace is a failure; the token is the only auth.

Notifiers

Sent when a monitor turns red or recovers, batched every evaluation_interval. Failed deliveries retry, also after a restart.

type = webhook
url = https://chat.example.com/hooks/xyz
reminder_interval = 1h
Type Options
webhook url, headers.<name>; Slack / Mattermost format
smtp host, port, tls (starttls · tls · none), user, password, from, to, subject_prefix ([up])
ilert integration_key of an "API" alert source; red opens an alert, recovery resolves it

All but ilert take reminder_interval; ilert escalates on its own.

Status pages

public.page.conf serves /status/public with every monitor tagged public:

title = Example Status
tag = public

template points to a custom html/template (relative to the config directory) receiving StatusPage{Title, State, Monitors}, e.g. config/templates/minimal.html.

Development

make run
make nomail
make test
make build
make package
make screenshots
make ui           # copy ui.css, ui.js, partials.html and their texts from ../ui (nobloat/ui), unchanged

About

Minimal alternative to uptimekuma

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages