Typ: Runbook · Stand: 2026-06-23 · Status: live (Komodo-Stack-ID `6a3acf2ca7867a4fbab9bfc1`); offen nur der Gitea->Komodo-Webhook # Healthchecks (self-hosted) — Cron-/Job-Heartbeat-Monitor Self-gehostete Instanz von [Healthchecks](https://github.com/healthchecks/healthchecks) als zentraler **Dead-Man's-Switch** fuer die internen Jobs und Scripte des Homelabs: ein Job pingt beim erfolgreichen Lauf eine URL; bleibt der Ping aus, alarmiert Healthchecks. Damit werden stille Job-Ausfaelle sichtbar, die Docker ("Up"), Prometheus-Blackbox (nur HTTP-Routen) und der Critical-Events-Watcher (nur `die`/`oom`) nicht sehen. ## Scope-Entscheidung (wichtig) Dieser Stack ist bewusst der Hub fuer **interne** Checks auf einem **laufenden** Host — Frage: "Lief Job X heute?". Beispiele: - `services/posture-check/posture-check.sh` (stuendlich / pre-borg) - `ops/restore-tests/run-restore-checks.sh` (Kadenz aus `schedule.md`) - `ops/borg-ui/scripts/pre-backup-dumps.sh` (Dump-Erzeugung) - `ops/borg-ui/scripts/gitea-bundle-mirror.sh` **Nicht hier:** die host-down-/backup-still-Waechter bleiben **extern** auf healthchecks.io-Cloud (Free-Tier): | Check | Quelle | Endpoint | |---|---|---| | Borg-Pre-Hook | `ops/borg-ui/scripts/pre-borg.sh` | healthchecks.io-Cloud | | baerchen Nearline-Pull | `ops/h-drive-nearline/pull-critical-backups.ps1` | healthchecks.io-Cloud | | Monitoring-Watchdog (#8) | `monitoring/prometheus/alerts.yml` (geplant) | healthchecks.io-Cloud | **Begruendung:** Ein Waechter, der auf demselben Unraid-Host laeuft, den er ueberwacht, kann einen Host-Ausfall nicht melden — er ist dann selbst tot, und Stille ist nicht von "alles gut" unterscheidbar. Genau diese drei Checks existieren fuer den Host-/Backup-Stillstand, deshalb muessen sie extern bleiben. Die Skripte sind endpoint-agnostisch (siehe `docs/SECRETS_MAP.md`), eine spaetere Umstellung waere reine URL-Frage — die Architektur-Empfehlung bleibt aber extern. ## Architektur - `healthchecks` — Web-UI + Ping-Listener, `frontend_net`, Traefik via `https://hc.kaleschke.info`, **native Healthchecks-Auth ohne pauschale Authelia** (analog n8n/Komodo): die Ping-Endpunkte `/ping/*` und die API muessen ohne ForwardAuth erreichbar sein, sonst koennen Jobs nicht melden. - `healthchecks-postgres` — dedizierte PostgreSQL 18, nur `healthchecks_internal` (`internal: true`), nie `frontend_net`. - SMTP ist bewusst **nicht** konfiguriert: Login laeuft ueber das Superuser-Passwort, Benachrichtigung ueber die ntfy-Integration. SMTP (GMX) kann spaeter additiv ergaenzt werden, falls E-Mail-Alerts gewuenscht sind. ## Secrets (siehe `docs/SECRETS_MAP.md`) | Secret | Mechanik | |---|---| | `HEALTHCHECKS_SECRET_KEY` | Komodo Stack-ENV (Django Secret Key) | | `HEALTHCHECKS_DB_PASSWORD` | Komodo Stack-ENV (gleicher Wert wie Datei-Secret) | | `HEALTHCHECKS_SUPERUSER_EMAIL` | Komodo Stack-ENV (Login-Mail des Erst-Admins) | | `HEALTHCHECKS_SUPERUSER_PASSWORD` | Komodo Stack-ENV (Login-Passwort des Erst-Admins) | | `healthchecks_postgres_password.txt` | Datei-Secret `/mnt/user/appdata/secrets/` → `POSTGRES_PASSWORD_FILE` | `SECRET_KEY` und `DB_PASSWORD` unterstuetzt das Image nicht als `_FILE` → Stack-ENV (Regel aus `docs/SECRETS_MAP.md`). Das Postgres-Passwort liegt zusaetzlich als Datei-Secret vor; beide Werte muessen identisch sein. ## Pre-Deploy (einmalig, Operator) 1. Appdata anlegen: `/mnt/user/appdata/healthchecks/postgres18/`. 2. Datei-Secret erzeugen: `/mnt/user/appdata/secrets/healthchecks_postgres_password.txt` (`chmod 600`), Wert = `HEALTHCHECKS_DB_PASSWORD`. 3. In Komodo die vier Stack-ENV-Variablen setzen (`SECRET_KEY` z. B. via `python -c "import secrets;print(secrets.token_urlsafe(64))"`). ## Deploy + Pflicht-Webhook 1. Stack in Komodo aus Gitea `Micha/homelab-infra` anlegen, `webhook_enabled` an. 2. Gitea-Webhook auf die neue Stack-ID anlegen (`http://komodo-core:9120/listener/github/stack//deploy`), Branch-Filter `master`. **Pflicht fuer jeden neuen produktiven Stack** (`docs/WORKFLOW.md`). 3. Test-Delivery ausloesen, `last_status`/Komodo-Deploy pruefen. ## Post-Deploy 1. Login auf `https://hc.kaleschke.info` mit Superuser-Mail/-Passwort. 2. Pro Job einen Check anlegen (Period + Grace passend zur Job-Kadenz, gern als Cron-Ausdruck). Ping-URL kopieren. 3. **ntfy-Integration**: im Check unter Integrations ntfy hinzufuegen, Server `https://ntfy.kaleschke.info`, Topic `homelab-alerts` (Problem-Alerts) — konsistent mit der bestehenden Alert-Schiene. 4. Im Job am Ende des erfolgreichen Laufs pingen, z. B.: ```bash curl -fsS -m 10 --retry 3 "https://hc.kaleschke.info/ping/" >/dev/null || true ``` Optional `/start` am Anfang (misst Laufzeit) und `//fail` im Trap. ## Rollback - Letzter stabiler Git-Stand: Stack existiert noch nicht — Rollback = Stack in Komodo stoppen/destroyen, Repo-Pfad `ops/healthchecks/` per `git rm` zuruecknehmen, Gitea-Webhook deaktivieren. - Datenpfad `/mnt/user/appdata/healthchecks/postgres18` bleibt unberuehrt und ist jederzeit loeschbar (reine Check-Metadaten, kein kritischer Datentopf — die Pings selbst sind in den Jobs definiert). - Secrets/ENV: bei Abbau die vier Stack-ENV + die Datei-Secret entfernen. ## Image-Pinning `healthchecks/healthchecks:v4.2@sha256:6b5f59…` ist auf den am 2026-06-23 ueber die Docker-Hub-API ermittelten Manifest-Digest gepinnt. Beim ersten Pull den real laufenden Digest gegenpruefen und bei Abweichung im Repo nachziehen (`docs/WORKFLOW.md` Abschnitt Image-Versionierung).