Add self-hosted Healthchecks stack for internal job monitoring (hybrid)
Self-hosted Healthchecks (ops/healthchecks/) as the hub for internal cron/job heartbeats. The three host-down/backup watchdogs (Borg pre-hook, baerchen nearline pull, monitoring watchdog #8) deliberately stay on healthchecks.io cloud, since an on-host watcher cannot report a host outage. - frontend_net + dedicated PostgreSQL 18 in healthchecks_internal - native Healthchecks auth; ping/API exempt from Authelia (n8n/Komodo pattern) - registered as middleware_exempt in ops/policy-checks/exceptions.json - docs: DECISIONS, ARCHITECTURE (3.1/4.2/7.6/10), SERVICE_CATALOG, SECRETS_MAP, MASTER_TODO, README index docker compose config validated (exit 0). Not yet deployed: host secret file, appdata dir, Komodo stack + ENV and Gitea webhook remain operator steps. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,46 @@ in `HOMELAB_ARCHITECTURE_MASTER_V2.md` §13, `docs/MASTER_TODO.md` (Geparkt),
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-23 - Healthchecks Hybrid: self-hosted fuer interne Jobs, Cloud fuer Host-down-Waechter
|
||||
|
||||
**Entscheidung:** Job-/Cron-Monitoring per Healthchecks (Dead-Man's-Switch) wird
|
||||
hybrid betrieben. Ein **self-gehosteter** Healthchecks-Stack (`ops/healthchecks/`,
|
||||
`hc.kaleschke.info`) ist der Hub fuer die vielen **internen** Checks auf einem
|
||||
laufenden Host ("lief Job X heute?": posture-check, restore-tests, Dump-Erzeugung,
|
||||
gitea-bundle-mirror). Die drei host-down-/backup-still-Waechter
|
||||
(Borg-Pre-Hook `ops/borg-ui/scripts/pre-borg.sh`, baerchen-Nearline-Pull
|
||||
`ops/h-drive-nearline/pull-critical-backups.ps1`, geplanter Monitoring-Watchdog
|
||||
Empf. #8) bleiben bewusst **extern** auf healthchecks.io-Cloud (Free-Tier).
|
||||
|
||||
**Kontext:** Die zwei bestehenden Borg-/Nearline-Pings waren bereits
|
||||
endpoint-agnostisch verdrahtet (`docs/SECRETS_MAP.md`), nur die Spielart
|
||||
(Cloud vs. self-host) war offen (`docs/homelab-optimierung.md` Offene Frage #4).
|
||||
Ein Waechter, der auf demselben Unraid-Host laeuft, den er ueberwacht, kann einen
|
||||
Host-Ausfall nicht melden — er ist dann selbst tot, Stille ist nicht von "alles
|
||||
gut" unterscheidbar. Genau dafuer existieren diese drei Checks, daher muessen sie
|
||||
extern bleiben. Fuer "lief Job X auf einem lebenden Host?" ist Self-Hosting
|
||||
dagegen unbedenklich (Host-down ist separat ueber die externen Pings abgedeckt)
|
||||
und bringt Datenhoheit + unbegrenzte Checks (Cloud-Free = 20).
|
||||
|
||||
**Umsetzung / Ausnahme:** `healthchecks` haengt in `frontend_net` (Traefik, native
|
||||
Healthchecks-Auth, **ohne** pauschale `authelia@file`: Ping-`/ping/*`- und
|
||||
API-Endpunkte muessen ohne ForwardAuth erreichbar sein, analog n8n/Komodo — in
|
||||
`ops/policy-checks/exceptions.json` als `middleware_exempt_identities` registriert).
|
||||
Dedizierte PostgreSQL 18 nur in `healthchecks_internal` (`internal: true`).
|
||||
SMTP bewusst aus (Login via Superuser, Alerts via ntfy-Integration nach
|
||||
`homelab-alerts`). Secrets: `SECRET_KEY`/`DB_PASSWORD`/Superuser als
|
||||
Komodo-Stack-ENV, Postgres zusaetzlich als Datei-Secret.
|
||||
|
||||
**Alternativen:** (a) Nur Cloud fuer alles — schlanker (kein Stack, kein Postgres),
|
||||
aber 20-Check-Limit und Metadaten-Abfluss; (b) alles self-host inkl. Backup-Waechter
|
||||
— verworfen wegen des Host-down-Blind-Spots; (c) ntfy-Heartbeat von einem zweiten
|
||||
Geraet statt Cloud (Optionsnotiz in Empf. #4) — bleibt moeglich, falls die
|
||||
Cloud-Abhaengigkeit spaeter unerwuenscht ist. **Review-Trigger:** mehr als ~20
|
||||
externe Checks noetig, Wunsch null Cloud-Abhaengigkeit, oder zweite Hardware (dann
|
||||
koennte der interne Hub dorthin und auch Host-down abdecken).
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-23 - Komodo nur aus vertrauenswuerdigen Netzen (IP-Allowlist statt public)
|
||||
|
||||
**Entscheidung:** Der Komodo-Router (`komodo.kaleschke.info`) bekommt eine
|
||||
|
||||
@@ -27,6 +27,7 @@ Host-Reports (`/mnt/user/backups/restore-reports/`) und in der Git-Historie.
|
||||
| Home Assistant Tibber | Operator/Codex | Tibber per HA-UI-Config-Flow verbinden. Danach Energy-Dashboard um echte Kosten/Preisquelle ergaenzen; SolarEdge-PV, Netz und Speicher sind bereits konfiguriert und validiert | `docs/runbooks/smart-home-bootstrap.md`, `docs/DECISIONS.md` |
|
||||
| Nearline-Pull Dead-Man's-Switch | Operator | **S4U-Root-Cause 2026-06-21 behoben + verifiziert:** Task `KalliLab H Drive Nearline Pull` von S4U auf LogonType `Interactive` ("Nur wenn Benutzer angemeldet") umgestellt (kein Passwort noetig, da `michi` Dauer-Konsolen-User) -> per Planer mit `0x0` bestaetigt. Spiegel frisch, Exit-Code-Leak gefixt, Heartbeat-Pings gepusht. **Verbleibt (optional, niedrige Dringlichkeit):** je einen Healthchecks-Check anlegen + Capability-URL hinterlegen (baerchen ENV `HEALTHCHECKS_NEARLINE_URL`/Datei; Unraid `/mnt/user/appdata/secrets/healthchecks_borg_url`) | `ops/h-drive-nearline/README.md` |
|
||||
| Monitoring Single-File-Bind-Mount Hardening | Operator/Claude | alertmanager/blackbox/loki/promtail + alertmanager-ntfy-bridge lokal auf Directory-Mounts umgestellt (grafana-provisioning war bereits Directory-Mount); `docker compose config` gruen. **Verbleibt:** Push + Komodo-Redeploy des monitoring-Stacks mit `--force-recreate` (Mount-Pfade aendern sich), danach Reload-/Alert-Smoke | `monitoring/docker-compose.yml` |
|
||||
| Healthchecks self-hosted (interne Jobs) | Operator | Stack vorbereitet (`ops/healthchecks/`). Pre-Deploy: Appdata `/mnt/user/appdata/healthchecks/postgres18/` + Datei-Secret `healthchecks_postgres_password.txt` + 4 Komodo-Stack-ENV. Dann Komodo-Stack aus Gitea + Pflicht-Gitea-Webhook anlegen, danach interne Jobs (posture-check, restore-tests, Dumps) als Checks verdrahten. Externe Backup-/Host-down-Waechter bleiben auf healthchecks.io-Cloud | `ops/healthchecks/README.md` |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ geloescht (Git-Historie ist das Archiv). Verbindliche Doku-Regeln:
|
||||
| `RENOVATE.md` | Self-hosted Renovate gegen Gitea |
|
||||
| `runbooks/komodo-bulk-deploy-dns.md` | Bulk-Deploy-Pulls scheitern an DNS bei AdGuard-Recreate |
|
||||
| `../ops/h-drive-nearline/README.md` | Windows-H:/ Nearline-Pull fuer kritische Restore-Artefakte |
|
||||
| `../ops/healthchecks/README.md` | Self-hosted Healthchecks (interne Job-Heartbeats); externe Host-down-/Backup-Waechter bleiben Cloud |
|
||||
|
||||
## Nutzer- und Statusdoku
|
||||
|
||||
|
||||
@@ -50,6 +50,10 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
|
||||
| Borg Repo | Borg-Passphrase fuer Restore-Tests und Notfallzugriff | `/mnt/user/appdata/secrets/borg_repo_passphrase.txt` -> Host-Secret-Datei, nicht im Repo | aktiv |
|
||||
| Healthchecks Dead-Man's-Switch (Borg Pre-Hook) | Ping-/Capability-URL | `/mnt/user/appdata/secrets/healthchecks_borg_url` (chmod 600) **oder** ENV `HEALTHCHECKS_BORG_URL`/`HEALTHCHECKS_URL`, gelesen von `ops/borg-ui/scripts/pre-borg.sh`; URL ist eine Capability-URL -> wie Secret behandeln, nie ins Repo | aktiv nach Operator-Setup |
|
||||
| Healthchecks Dead-Man's-Switch (Nearline-Pull) | Ping-/Capability-URL | baerchen: ENV `HEALTHCHECKS_NEARLINE_URL` **oder** `%USERPROFILE%\.kallilab\healthchecks-nearline-url.txt`, gelesen von `ops/h-drive-nearline/pull-critical-backups.ps1`; URL ist eine Capability-URL -> wie Secret behandeln, nie ins Repo | aktiv nach Operator-Setup |
|
||||
| Healthchecks self-hosted (`ops/healthchecks/`) | Django `SECRET_KEY` | Komodo Stack-ENV `${HEALTHCHECKS_SECRET_KEY}` (Image hat keinen `_FILE`-Support) | vorbereitet |
|
||||
| Healthchecks self-hosted | DB Password | Komodo Stack-ENV `${HEALTHCHECKS_DB_PASSWORD}` (= Wert von `healthchecks_postgres_password.txt`) | vorbereitet |
|
||||
| Healthchecks self-hosted | Superuser Login | Komodo Stack-ENV `${HEALTHCHECKS_SUPERUSER_EMAIL}`, `${HEALTHCHECKS_SUPERUSER_PASSWORD}` | vorbereitet |
|
||||
| healthchecks-postgres | DB Password | `/mnt/user/appdata/secrets/healthchecks_postgres_password.txt` -> `POSTGRES_PASSWORD_FILE` | vorbereitet |
|
||||
| Unraid Flash Backup | Boot-/Array-/Share-/Plugin-Konfiguration, ggf. Hashes/Keys/Templates | `/mnt/user/backups/borg/dumps/latest/unraid-flash-config.tar.gz`, via Borg/Hetzner gesichert | aktiv; wie Secret-Material behandeln |
|
||||
| Hermes Agent | Provider-Keys, Bot-Tokens, API-Server-Key | `/mnt/user/appdata/hermes-agent/data/.env` | VM-seitig offen |
|
||||
| Hermes Agent | SSH-Runner Private Key | `/mnt/user/appdata/secrets/hermes_runner_id_ed25519` -> `/root/.ssh/id_ed25519` | VM-seitig offen |
|
||||
@@ -118,6 +122,7 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
|
||||
|-- dawarich_secret_key_base.txt
|
||||
|-- dawarich_metrics_password.txt
|
||||
|-- dawarich_grafana_ro_password.txt
|
||||
|-- healthchecks_postgres_password.txt
|
||||
`-- vaultwarden_admin_token.txt
|
||||
```
|
||||
|
||||
@@ -162,6 +167,7 @@ Einige Secrets liegen bewusst nur als Komodo Stack Environment Variables vor, we
|
||||
| `hermes-agent` | `HERMES_DASHBOARD_HOST` plus Provider-/API-/Home-Assistant-Tokens in Host-`.env` | Vaultwarden -> externe Notiz | Stack ist aktuell geparkt (Review 2026-07-25); ohne Werte bleibt der Stack deaktiviert, kein Schaden am Rest |
|
||||
| `glance` | `GLANCE_IMMICH_API_KEY`, `GLANCE_ADGUARD_USERNAME`, `GLANCE_ADGUARD_PASSWORD`, `GLANCE_SPEEDTEST_API_KEY`, `GLANCE_KOMODO_API_KEY`, `GLANCE_KOMODO_API_SECRET`, `GLANCE_GITEA_TOKEN`, `GLANCE_PAPERLESS_TOKEN`, `GLANCE_MEALIE_TOKEN`, `GLANCE_HA_TOKEN` | Provider-UIs (Immich, AdGuard, Speedtest-Tracker, Komodo, Gitea, Paperless, Mealie, Home Assistant) neu erzeugen | rebuildbar; Widgets bleiben leer bis Tokens neu erzeugt sind, kein kritischer Datentopf; `GLANCE_HA_TOKEN` muss zusaetzlich in `ops/glance/docker-compose.yml` durchgereicht werden |
|
||||
| `n8n` | `N8N_ENCRYPTION_KEY` | Host-Secret-Datei `/mnt/user/appdata/secrets/n8n_encryption_key.txt` -> Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | Bei Verlust aller Quellen: n8n startet, aber **alle gespeicherten Credentials sind unbrauchbar** (Re-Eingabe noetig: GMX IMAP, OpenAI, Gitea PAT). Workflows bleiben strukturell erhalten. |
|
||||
| `healthchecks` | `HEALTHCHECKS_SECRET_KEY`, `HEALTHCHECKS_DB_PASSWORD`, `HEALTHCHECKS_SUPERUSER_EMAIL`, `HEALTHCHECKS_SUPERUSER_PASSWORD` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | `SECRET_KEY`-Verlust invalidiert Sessions/Signaturen (neu setzen, alle Logins neu); DB-Passwort gemeinsam in Postgres + Stack-ENV zuruecksetzen; Superuser-Account ist via SUPERUSER-ENV reproduzierbar. Check-Metadaten gehen nur verloren, wenn auch das DB-Volume weg ist; die Pings selbst leben in den Jobs |
|
||||
|
||||
### Komodo-Sonderfall
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
|
||||
| `hermes-gateway` | Hermes Agent Gateway/API intern | `ops/hermes-agent/docker-compose.yml` | intern `8642` auf `hermes_net` | SSH Runner (VM 192.168.178.143), LLM Provider, optional Home Assistant | `/mnt/user/appdata/hermes-agent/data`, SSH key path | Tier 3, Borg/Share | nein | NAS-Stack bleibt deaktiviert, solange die separate Hermes-VM/Runner-Seite nicht wiederhergestellt ist; kein Docker-Socket |
|
||||
| `hermes-dashboard` | Hermes Dashboard | `ops/hermes-agent/docker-compose.yml` | `https://hermes.kaleschke.info` via `${HERMES_DASHBOARD_HOST}` | `hermes-gateway`, Traefik + Authelia | shared read-only data mount | Tier 3, Borg/Share | ja + Authelia | Compose-Profil `dashboard`; aktuell VM-seitig offen, nicht Teil des NAS-Finalstarts |
|
||||
| `n8n` | Workflow-Automation; aktuell genutzt fuer Mail->LLM->Gitea-Issue (Inbox `Micha/mails`) | `apps/n8n/docker-compose.yml`, `apps/n8n/workflows/*.json` | `https://n8n.kaleschke.info` | Traefik (ohne pauschale Authelia, analog Komodo/Nextcloud), GMX IMAP, OpenAI API, Gitea API | `/mnt/user/appdata/n8n/data` (SQLite, Credentials, Workflows) | Tier 2, Borg + `n8n-data` (Credentials sind nur mit `N8N_ENCRYPTION_KEY` entschluesselbar) | ja, native Auth | Wegen Webhook-Endpunkten (`/webhook/*`) bewusst ohne `authelia@file`; eigene Login-/Owner-Auth bleibt Pflicht; `N8N_ENCRYPTION_KEY` ist Stack-ENV-Pflichtsecret, Verlust macht Credentials unbrauchbar. |
|
||||
| `healthchecks` | Self-hosted Cron-/Job-Heartbeat-Monitor (Dead-Man's-Switch) fuer interne Jobs/Scripte | `ops/healthchecks/docker-compose.yml`, `ops/healthchecks/README.md` | `https://hc.kaleschke.info` | Traefik (native Auth, ohne pauschale Authelia), `healthchecks-postgres`, ntfy | keine kritische App-Persistenz (Check-Metadaten in der DB) | Tier 3, rebuildbar | ja, native Auth | Hub fuer INTERNE Checks; die externen Host-down-/Backup-Waechter (Borg-Pre-Hook, Nearline-Pull, Monitoring-Watchdog #8) bleiben bewusst auf healthchecks.io-Cloud (ein On-Host-Waechter kann Host-Down nicht melden). Ping-/API-Endpunkte ohne ForwardAuth (analog n8n). Stack-ENV: `HEALTHCHECKS_SECRET_KEY`, `HEALTHCHECKS_DB_PASSWORD`, `HEALTHCHECKS_SUPERUSER_EMAIL/PASSWORD`. Vorbereitet, noch nicht deployed |
|
||||
| `healthchecks-postgres` | Healthchecks-Datenbank | `ops/healthchecks/docker-compose.yml` | intern | `healthchecks_internal` | `/mnt/user/appdata/healthchecks/postgres18`, `healthchecks_postgres_password.txt` | Check-Metadaten, rebuildbar | nein | interne DB; PostgreSQL 18; nie `frontend_net` |
|
||||
|
||||
## Smart Home
|
||||
|
||||
|
||||
Reference in New Issue
Block a user