# uptime-kuma — the fleet's SERVICE-layer monitor. # # REBUILT FROM SCRATCH 2026-09-21 (operator-authorised: "uptime-kuma was never # really used... you can even dump the existing container and config and start # over from scratch"). The previous instance carried four monitors, all of them # firewall pings, and 21-month-old code. Nothing was migrated. # # ⚠️ IMAGE TAG — DO NOT USE `:latest` HERE. Upstream keeps `latest` pointing at # the 1.x line, so a pull in August 2026 handed us an image BUILT 2024-12-20 # (1.23.16). Measured, not assumed: `latest` and `1` resolve to the same # digest, while `2`/`next` carry 2.5.5. All development is on 2.x, which has # been stable since 2.2.0 (2026-03-05) across twelve releases with zero # prereleases. Pinned EXACTLY rather than floating on `2` for the same reason # `latest` burned us: a floating tag is a version you did not choose. # # MOVED esh-docker-vm -> ana-docker in the same rebuild, for two reasons: # 1. House placement rule (CLAUDE.md): "Cross-site services (e.g. Beszel hub, # Dozzle hub) live on ana-docker and pull from agents on the other hosts." # A fleet-wide service monitor is exactly that, and it now sits beside the # Beszel hub it complements. # 2. esh-docker-vm has wedged unkillably TWICE in four months (2026-06-03 and # 2026-09-18, both homepage in D-state). The fleet's service monitor should # not live on the least reliable box in the fleet — and a monitor cannot # report the failure of the host it runs on. Beszel covers the host layer; # this covers the service layer; they should not share a failure domain. # # THE LANE SPLIT this service exists to fill (measured 2026-09-21): # Beszel -> 18 hosts x {Status, CPU, Memory, Disk, Temperature}. Its alerts # bind to a SYSTEM with a threshold; there is no URL column, so it # is structurally incapable of "this endpoint should return 200". # Kuma -> is the service actually serving. This file. # Homepage-> DISPLAY ONLY. It polls 38 URLs and alerts nobody; it is a # dashboard, never a monitor. # The gap between the first two is where homepage sat dead for three days while # both tools reported correctly. name: uptimekuma services: uptime-kuma: image: louislam/uptime-kuma:2.5.5 container_name: uptime-kuma # Normalised from the adopted-as-run `always` — the 2026-08-18 README said # this was "worth normalising on the next deliberate touch", and a rebuild # from scratch is that touch. `always` revives a container that was stopped # ON PURPOSE, which is the wrong behaviour for a service we may deliberately # take down during maintenance. restart: unless-stopped environment: # Skips 2.x's interactive "choose a database" first-run screen. # setup-database.js: UPTIME_KUMA_DB_TYPE overrides db-config.json and # writes it, so the stack comes up ready for the admin-account step # instead of parking on a form. SQLite is right here -- one operator, # a few dozen monitors; MariaDB is for the multi-thousand-check case. UPTIME_KUMA_DB_TYPE: sqlite ports: - "3001:3001" volumes: - uptime-kuma:/app/data labels: # Monitoring, NOT Apps — this is the group the dashboard's layout reserves # for Backrest / Beszel / Dozzle / this. - homepage.group=Monitoring - homepage.name=Uptime Kuma - homepage.icon=mdi-arrow-up-bold-circle - homepage.description=Service monitoring (fleet) - homepage.href=http://10.250.50.70:3001 - homepage.siteMonitor=http://10.250.50.70:3001 # The widget reads a PUBLISHED status page, not the admin API: # /api/status-page/ and /api/status-page/heartbeat/. These # labels were deliberately absent from the 2026-09-21 rebuild until that # page existed, because a dashboard widget pointed at a 404 is the # suspected mechanism behind BOTH of Homepage's unkillable D-state wedges # (incident_esh_docker_nfs_boot_race, 2026-06-03) -- shipping one on # purpose would have been daft. # # The page is defined in monitors.yaml (`status_page:`) and applied by # `scripts/kuma seed`, so a from-scratch rebuild restores the slug this # points at. Slug `nethealth` is the one the pre-rebuild instance used. - homepage.widget.type=uptimekuma - homepage.widget.url=http://10.250.50.70:3001 - homepage.widget.slug=nethealth networks: - tnet volumes: uptime-kuma: {} networks: tnet: name: traefik-net external: true