Compare commits
1 Commits
master
..
ca78990449
| Author | SHA1 | Date | |
|---|---|---|---|
| ca78990449 |
@@ -1,6 +0,0 @@
|
||||
*.sh text eol=lf
|
||||
*.ps1 text eol=crlf
|
||||
*.md text
|
||||
*.json text
|
||||
*.yml text
|
||||
*.yaml text
|
||||
@@ -22,14 +22,9 @@
|
||||
**/*.tgz
|
||||
**/*.zip
|
||||
|
||||
# Generated reports
|
||||
ops/policy-checks/last-report.md
|
||||
|
||||
# Local/editor noise
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*.tmp
|
||||
*.log
|
||||
.serena/
|
||||
.claude/settings.local.json
|
||||
memory/
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Agent Context - Homelab Infra
|
||||
|
||||
Typ: Einstieg/Index · Stand: 2026-06-11 · Status: aktiv
|
||||
|
||||
Einstiegspunkt fuer KI-Agenten (Codex, Gemini u. a.; Claude nutzt zusaetzlich
|
||||
`CLAUDE.md`). Kein eigener Inhalt - nur Pflichtpfade.
|
||||
|
||||
## Vor jeder Arbeit lesen
|
||||
|
||||
1. `docs/AI_CONTEXT.md` - Systembild, harte Regeln, Ausnahmen-Kurzliste
|
||||
2. `HOMELAB_ARCHITECTURE_MASTER_V2.md` - Architektur-Zielbild
|
||||
3. `docs/WORKFLOW.md` - verbindlicher GitOps-/No-Drift-Ablauf
|
||||
4. die betroffene `docker-compose.yml` bzw. das betroffene Runbook (Index: `docs/README.md`)
|
||||
|
||||
## Nicht verhandelbar
|
||||
|
||||
- Keine Secret-Werte lesen, zitieren oder schreiben - nur Namen und Pfade.
|
||||
- Keine Deployments, Host-Hotfixes oder Docker-Schreibbefehle ohne ausdrueckliche Anweisung.
|
||||
- Doku-Regeln aus `docs/REPO_MAP.md` einhalten: ein Fakt, ein Zuhause. Status nur in `docs/MASTER_TODO.md`, Entscheidungen nur in `docs/DECISIONS.md`.
|
||||
- Bei Drift oder zwei fehlgeschlagenen Reparaturversuchen: stoppen, `docs/GITOPS_DRIFT_RUNBOOK.md`.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Claude Code Context - Homelab Infra
|
||||
|
||||
Stand: 2026-06-11
|
||||
Stand: 2026-05-04
|
||||
|
||||
Dieses Repository ist die GitOps-Quelle fuer das KalliLab CORE Homelab auf einem Unraid-Host. Es verwaltet Docker-Compose-Stacks fuer Core-Dienste, Security, Infrastruktur, Apps, Operations-Tools, Host-nahe Dienste und Traefik. Gitea Online ist die operative Quelle der Wahrheit; Komodo konsumiert den Git-Stand und deployed daraus.
|
||||
|
||||
@@ -10,10 +10,9 @@ Claude muss vor jeder fachlichen oder technischen Aenderung mindestens diese Dat
|
||||
|
||||
1. `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
2. `docs/WORKFLOW.md`
|
||||
3. `docs/README.md`
|
||||
4. `docs/REPO_MAP.md`
|
||||
5. `docs/SERVICE_CATALOG.md`
|
||||
6. die betroffene `docker-compose.yml`
|
||||
3. `docs/REPO_MAP.md`
|
||||
4. `docs/SERVICE_CATALOG.md`
|
||||
5. die betroffene `docker-compose.yml`
|
||||
|
||||
Zusaetzlich je nach Thema:
|
||||
|
||||
@@ -22,7 +21,7 @@ Zusaetzlich je nach Thema:
|
||||
- Secrets: `docs/SECRETS_MAP.md`
|
||||
- GitOps-/Komodo-/Runtime-Drift: `docs/GITOPS_DRIFT_RUNBOOK.md`
|
||||
- Gesamtbild fuer KI-Agenten: `docs/AI_CONTEXT.md`
|
||||
- Architektur-/Betriebsentscheidungen mit Begruendung: `docs/DECISIONS.md`
|
||||
- Home Assistant / Ecowitt / InfluxDB: `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md`
|
||||
|
||||
## Projektbeschreibung
|
||||
|
||||
@@ -90,7 +89,7 @@ Wenn Drift vermutet wird, nicht raten. Erst die Pflichtmatrix in `docs/GITOPS_DR
|
||||
- `traefik`: Host-Ports 80/443
|
||||
- `gitea`: SSH-Port 222
|
||||
- `AdGuard Home`: DNS-Port 53 und LAN-Admin-Port 8082
|
||||
- `tailscale`: natives Unraid-Plugin (`tailscale.plg`, Interface `tailscale1`), Subnet-Router fuers LAN; nicht repo-/Komodo-verwaltet. Der frueher repo-verwaltete userspace-Docker-Stack `host-services/tailscale/` wurde am 2026-06-06 entfernt.
|
||||
- `tailscale`: `network_mode: host`
|
||||
- `Plex-Media-Server`: historischer Host-Netz-Sonderfall, nicht als Repo-Stack enthalten
|
||||
- `scrutiny`: `privileged: true` fuer SMART/Laufwerkszugriff
|
||||
- `Komodo`: Docker-Socket und native Auth ohne pauschale ForwardAuth
|
||||
@@ -123,7 +122,6 @@ Standard-Rollback ist ein Ruecknahme-Commit oder gezielte Rueckaenderung mit Pus
|
||||
## Arbeitsweise fuer Claude
|
||||
|
||||
- Erst lesen, dann handeln.
|
||||
- Doku-Regeln aus `docs/REPO_MAP.md` einhalten: ein Fakt, ein Zuhause. Status nur in `docs/MASTER_TODO.md`, Entscheidungen nur in `docs/DECISIONS.md`, Erledigtes verlaesst die Arbeitskopie.
|
||||
- Bei Unsicherheit Zustand messen, nicht erraten.
|
||||
- Aenderungen klein halten und nur den betroffenen Bereich anfassen.
|
||||
- Bestehende Doku und Repo-Konventionen bevorzugen.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> **Single Source of Truth** für Docker-Netzwerkarchitektur, Sicherheitsregeln, Zielbild und Migration des Kallilabcore-Homelabs.
|
||||
> **Arbeitsregel für KI-Assistenten:** Dieses Dokument immer zuerst lesen, bevor Fragen zu Containern, Netzwerken, Traefik, Tailscale, Migration oder Security beantwortet werden.
|
||||
|
||||
**Stand:** 2026-06-11 | **Aktueller Schwerpunkt:** GitOps / Doku-Synchronisierung / Reproduzierbare Deployments
|
||||
**Stand:** 2026-05-23 | **Aktueller Schwerpunkt:** GitOps / Doku-Synchronisierung / Reproduzierbare Deployments
|
||||
|
||||
---
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
10. [Bekannte Ausnahmen und Begründungen](#10-bekannte-ausnahmen-und-begründungen)
|
||||
11. [Projektorganisation und Arbeitsmodus](#11-projektorganisation-und-arbeitsmodus)
|
||||
12. [Nutzung mit KI / Kontext-Regel](#12-nutzung-mit-ki--kontext-regel)
|
||||
13. [Betriebserfahrungen und Entscheidungs-Log (ausgelagert)](#13-betriebserfahrungen-und-entscheidungs-log-ausgelagert)
|
||||
13. [Betriebserfahrungen und Entscheidungs-Log](#13-betriebserfahrungen-und-entscheidungs-log)
|
||||
|
||||
---
|
||||
|
||||
@@ -93,7 +93,6 @@ Jeder produktive Container nutzt `restart: unless-stopped`, außer eine Ausnahme
|
||||
| `monitoring_net` | Compose-intern, bridge | zentraler Observability-Stack fuer Prometheus, Loki, Grafana, Promtail, Exporter und InfluxDB | Zielzustand |
|
||||
| `monitoring_influx_lan` | Compose-intern, bridge | nicht-oeffentliches Zusatznetz nur fuer Docker Host-Port-Publishing von InfluxDB 8181 | Zielzustand |
|
||||
| `glance_socket_net` | Compose-intern, `internal: true` | interner Zugriff von Glance auf den Docker-Socket-Proxy | umgesetzt |
|
||||
| `smarthome_net` | bridge, `internal: true` | interne Smart-Home-Kommunikation zwischen Home Assistant, Mosquitto, spaeter Zigbee2MQTT/ESPHome | vorbereitet |
|
||||
| `host` | host | nur für echte Sonderfälle | begründet |
|
||||
|
||||
### 3.2 Finales Diagramm (vereinfacht)
|
||||
@@ -124,8 +123,7 @@ App-interne Netze
|
||||
├── immich_default (internal: true) ✅
|
||||
├── nextcloud_internal (internal: true) ✅
|
||||
├── monitoring_net (zentraler Observability-Stack)
|
||||
├── monitoring_influx_lan (Bridge fuer LAN-Port-Publishing, keine Traefik-Route)
|
||||
└── smarthome_net (HA, Mosquitto, spaeter Zigbee2MQTT/ESPHome)
|
||||
└── monitoring_influx_lan (Bridge fuer LAN-Port-Publishing, keine Traefik-Route)
|
||||
|
||||
Host-Sonderfälle
|
||||
├── tailscale
|
||||
@@ -147,8 +145,6 @@ Diese Dienste sind über echte `*.kaleschke.info`-Domains erreichbar:
|
||||
- `gitea` (Web) — git.kaleschke.info
|
||||
- `immich_server` — immich.kaleschke.info
|
||||
- `nextcloud` — cloud.kaleschke.info
|
||||
- `plex` — plex.kaleschke.info (Traefik, native Plex-Auth; Plex Remote Access/Port 32400 bleibt aus)
|
||||
- `homeassistant` — home.kaleschke.info (Traefik, native Home-Assistant-Auth)
|
||||
|
||||
### 4.2 Nicht öffentlich / nur Tailscale oder Traefik + Middleware
|
||||
Diese Dienste sind **keine Public Apps**:
|
||||
@@ -166,8 +162,6 @@ Diese Dienste sind **keine Public Apps**:
|
||||
- `bentopdf` — pdf.kaleschke.info (Middleware)
|
||||
- `monitoring-grafana` — monitoring.kaleschke.info (Middleware)
|
||||
- `hermes-dashboard` — hermes.kaleschke.info (Middleware)
|
||||
- `super-productivity` — sp.kaleschke.info (Middleware)
|
||||
- `n8n` — n8n.kaleschke.info (Traefik ohne pauschale Middleware, native Auth + Webhook-Ausnahme analog Komodo)
|
||||
- `Traefik-Dashboard`
|
||||
- `AdGuard Home` — Admin-UI auf Port 8082 (`80` im Container), kein Traefik, nur Tailscale-IP `100.80.98.33`; 2026-05-26 bewusst keine 2FA-/Traefik-Umstellung
|
||||
|
||||
@@ -244,7 +238,7 @@ Legende Status:
|
||||
| `AdGuard Home` | ✅ | `dns_net` (172.23.0.3), `frontend_net` | Port 53 DNS direkt, Port 8082 Admin nur auf Tailscale-IP `100.80.98.33` | DNS-Server + Upstream zu unbound; kein Traefik fuer Admin-UI | Admin-Port bleibt bewusst ohne Traefik/2FA, aber nicht mehr auf allen LAN-Interfaces |
|
||||
| `unbound` | ✅ | `dns_net` | intern | Upstream-Resolver für AdGuard, isoliert | — |
|
||||
| `ddns-updater` | ✅ | `frontend_net` | intern | Cloudflare DNS API; bleibt in `frontend_net` | Dokumentierte Ausnahme |
|
||||
| `tailscale` | ✅ | `host` | VPN-Zugang / Subnet-Router | **Natives Unraid-Plugin** (`tailscale.plg`, Interface `tailscale1`, State `/boot/config/plugins/tailscale/state`) — **nicht** repo-/Komodo-verwaltet | Subnet-Router fuer `192.168.178.0/24`; der redundante userspace-Docker-Stack `host-services/tailscale/` wurde am 2026-06-06 entfernt |
|
||||
| `tailscale` | ✅ | `host` | VPN-Zugang | Git-Stack (`host-services/tailscale/`) | nutzt `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` als dokumentierte VPN-Ausnahme |
|
||||
|
||||
### 7.2 Sicherheit / Identity
|
||||
|
||||
@@ -264,7 +258,6 @@ Legende Status:
|
||||
| `immich_redis` | ⏳ | `immich_default` | intern | intern-only | anonymes Volume → named volume |
|
||||
| `nextcloud-postgres` | ✅ | `nextcloud_internal` | intern | app-eigene Nextcloud-Datenbank mit `_FILE`-Secret | — |
|
||||
| `nextcloud-redis` | ✅ | `nextcloud_internal` | intern | app-eigener Cache fuer File Locking / Sessions | — |
|
||||
| `smarthome-mosquitto` | ✅ vorbereitet | `smarthome_net` | intern `1883`, kein Host-Port in Phase 1 | MQTT-Datenbus fuer Home Assistant, spaeter ESPHome und Zigbee2MQTT; Passwortdatei und ACLs in `/mnt/user/appdata/mosquitto/config` | LAN-Port erst in ESPHome-Phase mit ACLs/per-Device-Usern |
|
||||
|
||||
### 7.4 Produktive Apps
|
||||
|
||||
@@ -278,10 +271,7 @@ Legende Status:
|
||||
| `immich_server` | ✅ | `immich_default`, `frontend_net` | Traefik | aktiv via `immich.kaleschke.info` | — |
|
||||
| `immich_machine_learning` | ✅ | `immich_default` | intern | bleibt intern | — |
|
||||
| `nextcloud` | ✅ | `frontend_net`, `nextcloud_internal` | Traefik | aktiv via `cloud.kaleschke.info`, nativer Nextcloud-Login, WebDAV/CardDAV faehig | CalDAV/CardDAV-Redirect via Traefik-Labels |
|
||||
| `homeassistant` | ✅ vorbereitet | `frontend_net`, `smarthome_net` | Traefik via `home.kaleschke.info`, native HA-Auth | Home Assistant Container im GitOps-Stack `smart-home/`; kein HAOS, kein Supervised; Fach-YAML kommt aus `smart-home-kalli`, `.storage` bleibt in `/mnt/user/appdata/homeassistant` | Deploy, Onboarding, Restore-Probe, Cloud-Integrationen |
|
||||
| `plex` | ✅ | `host` | Traefik via `plex.kaleschke.info` + Plex native Auth; LAN direkt `:32400` | Compose-Stack unter `host-services/plex/`; Host-Netz bleibt fuer Discovery / Plex GDM dokumentierte Ausnahme; Traefik routet per File-Provider-Ausnahme auf `http://192.168.178.58:32400`, weil Docker-Labels Host-Netz-Container aus Traefik heraus auf `127.0.0.1` routen wuerden; kein direkter WAN-Port 32400 und Plex Remote Access bleibt aus; Server geclaimt von `Xeridos`; Smart-TVs (Schlafzimmer, Wohnzimmer) ueber WLAN-LAN per mDNS | — |
|
||||
| `super-productivity` | ✅ vorbereitet | `frontend_net` | Traefik + Middleware | Persoenliche Task-PWA des Operators; Issues kommen aus Gitea `Micha/mails` via n8n-Mail-Workflow | Deploy + Webhook + DNS-Eintrag offen |
|
||||
| `n8n` | ✅ vorbereitet | `frontend_net` | Traefik, native Auth (keine pauschale Authelia) | Workflow-Automation; erster Workflow: GMX-Mail -> OpenAI-Extraktion -> Gitea-Issue in `Micha/mails`; `N8N_ENCRYPTION_KEY` ist Stack-ENV-Pflichtsecret | Deploy + Webhook + Owner-Setup offen |
|
||||
| `plex` | ✅ | `host` | Plex native, **LAN/Tailscale-only** (Remote Access aus seit 2026-05-28) | Compose-Stack unter `host-services/plex/`; Host-Netz bleibt fuer Discovery / Plex GDM dokumentierte Ausnahme; Server geclaimt von `Xeridos`; Smart-TVs (Schlafzimmer, Wohnzimmer) ueber WLAN-LAN per mDNS | — |
|
||||
|
||||
### 7.5 Admin / Operations
|
||||
|
||||
@@ -314,7 +304,7 @@ Legende Status:
|
||||
|
||||
| Container | Status | Ziel |
|
||||
|---|---|---|
|
||||
| — | — | Plex ist nicht mehr direkt offen: der Dienst ist als Repo-Compose-Stack unter `host-services/plex/` dokumentiert; `host`-Netz bleibt als Discovery-Ausnahme. Externer Zugriff laeuft ausschliesslich ueber Traefik/443 auf `plex.kaleschke.info`; keine direkte 32400-WAN-Freigabe. Technisch nutzt Plex als einzige Host-Netz-Route `traefik/dynamic/plex.yml`, weil Docker-Labels fuer `network_mode: host` in Traefik auf `127.0.0.1:32400` zeigen. |
|
||||
| — | — | Plex ist nicht mehr offen: der Dienst ist als Repo-Compose-Stack unter `host-services/plex/` dokumentiert; `host`-Netz bleibt als Discovery-Ausnahme. |
|
||||
|
||||
### 7.8 Entfernte Container
|
||||
|
||||
@@ -376,7 +366,23 @@ labels:
|
||||
|
||||
## 9. Historische Migration (abgeschlossen)
|
||||
|
||||
Die Blockmigration aus der Portainer-/Dockerman-Phase ist abgeschlossen: Traefik laeuft labelbasiert ohne File-Provider-Service-Routen, Komodo ist alleiniger Stack-Manager, Portainer CE ist entfernt, Borg/Dumps/Restore-Tests sind produktiv. Entscheidungen und Hintergruende stehen in `docs/DECISIONS.md`; die Sprint-Historie liegt in Git.
|
||||
Die frühere Blockmigration aus der Portainer-/Dockerman-Phase ist fachlich abgeschlossen.
|
||||
|
||||
Dieser Abschnitt dient nur noch als **historischer Vermerk**:
|
||||
|
||||
- Traefik läuft labelbasiert ohne Service-Routen im File-Provider.
|
||||
- Komodo ist der einzige aktive Stack-Manager.
|
||||
- Portainer CE ist entfernt.
|
||||
- Borg/Borg UI, Dump-Automatisierung und Restore-Test sind produktiv eingeführt.
|
||||
- Frühere Sprint-/Block-Checklisten werden hier **nicht mehr operativ gepflegt**.
|
||||
|
||||
Für den laufenden Betrieb gilt stattdessen:
|
||||
|
||||
- Zielbild und Architektur in diesem Dokument
|
||||
- Git-/Komodo-Ablauf in `docs/WORKFLOW.md`
|
||||
- fachliche Änderungen in der jeweils betroffenen Stack-Doku
|
||||
- Entscheidungen und besondere Umstellungen im Entscheidungs-Log unten
|
||||
|
||||
## 10. Bekannte Ausnahmen und Begründungen
|
||||
|
||||
| Container | Ausnahme | Begründung |
|
||||
@@ -394,12 +400,8 @@ Die Blockmigration aus der Portainer-/Dockerman-Phase ist abgeschlossen: Traefik
|
||||
| `mail-archiver` | `frontend_net` + `backend_net` | braucht Internetzugang für IMAP-Abruf (GMX, Gmail) und DB-Zugang |
|
||||
| `traefik/dynamic/*` | manueller Host-Sync trotz GitOps | File-Provider bleibt bewusst fuer `middlewares.yml`, `tls.yml` und `dashboards.yml`; Komodo deployed diese Dateien nicht automatisch |
|
||||
| `nextcloud` | keine zentrale ForwardAuth-Middleware | Nextcloud bringt eigene Auth, Clients und WebDAV/CardDAV-Endpunkte mit; Traefik bleibt Reverse Proxy, Auth bleibt app-nativ |
|
||||
| `monitoring-influxdb3-core` | Host-Port 8181 auf LAN-IP; `user: "0"` | Home Assistant schreibt spaeter Langzeitdaten. Nach der HA-Container-Entscheidung muss der Writer-Pfad in der Influx-Phase explizit gewaehlt werden: entweder LAN-Bind via `INFLUXDB_BIND_IP` oder gezieltes gemeinsames internes Netz. Keine Traefik-Route, Zugriff nur ueber Token; InfluxDB 3 Core benoetigt im aktuellen Container-Setup Root-Rechte fuer den lokalen Object-Store-Pfad im named volume |
|
||||
| `monitoring-influxdb3-core` | Host-Port 8181 auf LAN-IP; `user: "0"` | Home Assistant laeuft in einer VM ausserhalb des Compose-Netzes und muss Metriken schreiben koennen; keine Traefik-Route, kein `frontend_net`, Zugriff nur ueber Token und LAN-IP `INFLUXDB_BIND_IP`; InfluxDB 3 Core benoetigt im aktuellen Container-Setup Root-Rechte fuer den lokalen Object-Store-Pfad im named volume |
|
||||
| `monitoring-promtail` | Docker-Socket read-only | Docker-Log-Discovery fuer Loki; keine Schreibrechte, keine Appdaten-Persistenz ueber den Socket |
|
||||
| `n8n` | keine pauschale Authelia-Middleware | Webhook-Endpunkte (`/webhook/*`, `/webhook-test/*`) muessen ohne ForwardAuth erreichbar bleiben; n8n bringt eigene Owner-/Login-Auth mit (analog Komodo/Nextcloud) |
|
||||
| `plex` | Traefik ohne Authelia, File-Provider-Ausnahme trotz Host-Netz | Plex bringt native Konto-/Client-Auth mit; vorgeschaltete ForwardAuth wuerde Plex Web, Apps und Client-Flows stoeren. Docker-Labels sind fuer diesen Host-Netz-Container ungeeignet, weil Traefik sonst `127.0.0.1:32400` nutzt; daher `traefik/dynamic/plex.yml` mit Ziel `192.168.178.58:32400`. Route nur ueber Traefik/443 (`plex.kaleschke.info`), direkter Plex-WAN-Port 32400 und Plex Remote Access bleiben deaktiviert. |
|
||||
| `homeassistant` | Traefik ohne Authelia, Fach-YAML aus separatem Repo | Home Assistant bringt eigene Auth, mobile Apps, Webhooks und Integrationsfluesse mit. Der Container haengt in `frontend_net` fuer Traefik und in `smarthome_net` fuer MQTT/Zigbee2MQTT/ESPHome. `.storage` und Secrets bleiben in Appdata und werden per Borg gesichert, nicht versioniert. |
|
||||
| `Ecowitt` | spaetere HTTP-Ausnahme offen | Ecowitt kann nur HTTP. Wegen globalem Traefik-HTTP-Redirect wird in Phase 2 entschieden, ob Traefik eine selektive Webhook-Ausnahme bekommt oder ob ein LAN-only HA-Port `8123` als dokumentierte Host-Port-Ausnahme noetig wird. |
|
||||
|
||||
---
|
||||
|
||||
@@ -455,15 +457,159 @@ Damit ist sofort klar:
|
||||
|
||||
---
|
||||
|
||||
## 13. Betriebserfahrungen und Entscheidungs-Log (ausgelagert)
|
||||
## 13. Betriebserfahrungen und Entscheidungs-Log
|
||||
|
||||
Architektur- und Betriebsentscheidungen werden seit 2026-06-11 zentral in
|
||||
`docs/DECISIONS.md` gefuehrt (ADR-light: Entscheidung, Kontext, Review-Trigger).
|
||||
Dieses Dokument haelt nur noch das Zielbild. Neue Entscheidungen werden dort
|
||||
eingetragen; hier aendert sich nur etwas, wenn das Zielbild selbst betroffen
|
||||
ist (Netze, Zugangsmodell, Ausnahmen in Sektion 10).
|
||||
### Plex Server Reclaim und LAN-only-Profil (2026-05-28)
|
||||
|
||||
Befund: Die `Preferences.xml` des Plex-Servers war seit dem 18.05.2026 13:18 jungfraeulich (391 Bytes, ohne `PlexOnlineMail`/`PlexOnlineUsername`/`PlexOnlineToken`). Der Server war damit nicht mit einem Plex.tv-Account geclaimt, obwohl die Smart-TVs ueber LAN-Discovery (mDNS/Plex-GDM) weiter funktionierten. Beim Login als `Xeridos` ueber `app.plex.tv` meldete der Server "Keine Berechtigung", weil kein Owner registriert war. Zusaetzlich war die `library_sections`-Konfiguration leer (Backups vom 19./22./28.05. ebenfalls ~370 KB statt MBs/GBs); die Bibliotheks-Konfiguration war seit dem 18.05. weg, die Filmdateien unter `/mnt/user/media/*` blieben aber intakt (~833 Verzeichnisse, davon `movies/` 1.4 TB und `Heimatfilme/` 300 GB).
|
||||
|
||||
Reclaim:
|
||||
|
||||
- Operator-Claim-Token via `https://www.plex.tv/claim` als `Xeridos` erzeugt.
|
||||
- Plex-Container per `PLEX_CLAIM=claim-... docker compose up -d --force-recreate plex` am Host-Pfad `/mnt/user/services/stacks/plex/host-services/plex` neu erstellt. Token wurde **nur** als Shell-Inline-ENV mitgegeben, **nicht** in eine `.env`-Datei, **nicht** in die Compose, **nicht** in die Komodo-Stack-ENV geschrieben.
|
||||
- Nach Erfolg: zweiter `docker compose up -d --force-recreate plex` ohne `PLEX_CLAIM`, damit der verbrauchte Token nicht im `docker inspect`-ENV-Snapshot persistiert.
|
||||
- Bash-History defensiv geleert.
|
||||
|
||||
Endstand:
|
||||
|
||||
- `PlexOnlineUsername="Xeridos"`, `PlexOnlineMail="michideheld@gmx.de"`, `PlexOnlineHome="1"`.
|
||||
- Bibliotheken neu angelegt via Plex-Web → Verwalte Mediatheken → `/data/movies`, `/data/Heimatfilme` etc.
|
||||
- `PublishServerOnPlexOnlineKey="0"` (Remote Access deaktiviert), Plex-Relay aus → Plex bleibt strikt LAN/Tailscale-only, konsistent zum Tailscale-First-Operator-Modell.
|
||||
|
||||
Konsequenzen fuer Doku/Betrieb:
|
||||
|
||||
- Plex-Home-Familien-Profil ("Familie") muss bei Bedarf neu eingeladen werden; war ohnehin nicht aktiv genutzt.
|
||||
- Watch-State aus der Zeit vor dem 18.05. ist nicht recoverbar; Filme/Serien laufen bei Wiederaufruf bei 00:00 los.
|
||||
- `host-services/plex/docker-compose.yml` enthaelt weiter `PLEX_CLAIM: ${PLEX_CLAIM:-}`, damit ein zukuenftiger Reclaim ohne Repo-Aenderung moeglich ist.
|
||||
|
||||
### Traefik — Wechsel zu reinen Docker-Labels (2026-03-28)
|
||||
Die statischen File-Provider-Konfigurationen in `/mnt/user/appdata/traefik/dynamic/` wurden vollständig bereinigt:
|
||||
- **Gelöscht:** `immich.yml`, `gitea.yml`, `mealie.yml`, `scrutiny.yml`, `vaultwarden.yml.bak`
|
||||
- **Verbleibend (notwendig):** `middlewares.yml`, `tls.yml`, `dashboards.yml`
|
||||
|
||||
**Hintergrund:** Die alten File-Provider-Configs haben `@file`-Routen mit `@docker`-Routen konkurrieren lassen. In Traefik v3 gewinnt der File-Provider und hat z.B. Immich auf die falsche IP geroutet (Bad Gateway). Nach Löschung läuft Traefik ausschließlich auf Docker-Labels.
|
||||
|
||||
**Regel:** Neue Dienste ausschließlich via Docker Compose Labels konfigurieren. Keine neuen `.yml`-Dateien im `dynamic/`-Verzeichnis für Service-Routen anlegen.
|
||||
|
||||
### Komodo — Ablösung von Portainer als Stack-Manager (2026-03-28)
|
||||
Komodo ist nun der primäre GitOps-Stack-Manager:
|
||||
- **Komodo Core** läuft als Docker-Stack (`ops/komodo/docker-compose.yml`)
|
||||
- **Komodo Periphery** läuft auf dem Unraid-Host für direktes Server-Management
|
||||
- Stacks werden via Gitea synchronisiert und über Komodo deployed
|
||||
- Portainer CE ist abgeschaltet; Komodo ist der alleinige aktive Stack-Manager
|
||||
|
||||
**Betriebsregel:** Alle Stack-Änderungen laufen über Git; Komodo konsumiert nur den Stand aus Gitea.
|
||||
|
||||
**Zugangsregel:** Komodo bleibt bewusst bei nativer Authentifizierung ohne pauschal vorgeschaltete ForwardAuth-Middleware vor dem gesamten Router. Hintergrund sind die gemischten UI-, API-, Webhook- und Periphery-Endpunkte unter derselben Domain.
|
||||
|
||||
### Komodo Self-Stack Drift-Recovery (2026-05-04)
|
||||
- Befund: `komodo-core` und `komodo-periphery` liefen aus temporaeren `/tmp/*repair.yml`-Dateien, waehrend `komodo-mongo` auf den fehlenden persistenten Pfad `/mnt/user/services/stacks/komodo/compose.yaml` verwies.
|
||||
- Recovery: Repair-YAMLs und Runtime-ENV wurden unter `/mnt/user/appdata/komodo/_drift_backup_2026-05-04/` gesichert; eine zusaetzliche Recovery-ENV liegt unter `/mnt/user/appdata/secrets/_komodo_stack_env_recovery_2026-05-04.env` und ist als temporaeres Tier-1-Secret-Material zu behandeln.
|
||||
- Der persistente Self-Stack wurde unter `/mnt/user/services/stacks/komodo/compose.yaml` aus `ops/komodo/docker-compose.yml` wiederhergestellt. Die hostseitige `.env` bleibt ausserhalb von Git.
|
||||
- Reconcile-Regel: Bei Self-Stack-Drift keinen pauschalen `docker compose up -d` ausfuehren, wenn der Dry-run `komodo-mongo` recreaten wuerde. Core und Periphery koennen gezielt mit `--no-deps` neu erstellt werden, Mongo bleibt dabei unangetastet.
|
||||
- Ergebnis: Alle drei Komodo-Container zeigen wieder auf `/mnt/user/services/stacks/komodo/compose.yaml`; Mongo blieb waehrend der Rueckfuehrung healthy.
|
||||
|
||||
### AdGuard Home — Ablösung von Pi-hole (2026-03-28)
|
||||
`binhex-official-pihole` wurde entfernt und durch `AdGuard Home` + `unbound` ersetzt:
|
||||
- AdGuard läuft als Git-Stack (`host-services/Adguard/docker-compose.yml`)
|
||||
- Netzwerke: `dns_net` (feste IP 172.23.0.3) + `frontend_net`
|
||||
- Port 53 (DNS) direkt gebunden — dokumentierte Ausnahme
|
||||
- Admin-UI direkt gebunden via Tailscale-IP `100.80.98.33:8082` auf Container-Port 80 — 2026-05-26 bewusst als einfache Operator-Entscheidung ohne Traefik-/2FA-Umstellung
|
||||
- `unbound` läuft weiterhin als Upstream-Resolver in `dns_net`
|
||||
|
||||
### diun — Entfernung (2026-03-28)
|
||||
`diun` (Docker Image Update Notifier) wurde deinstalliert:
|
||||
- Stack gelöscht
|
||||
- Orphan-Netzwerk `diun_diun_default` bereinigt
|
||||
- Repo-Eintrag `infra/diun/` aus Git entfernt
|
||||
|
||||
Update-Monitoring kann über Komodo's eingebaute Update-Notifications abgedeckt werden.
|
||||
|
||||
### ntfy — Push-Notifications (Git-Stack)
|
||||
`ntfy` läuft als Git-Stack (`apps/ntfy/docker-compose.yml`):
|
||||
- `ntfy.kaleschke.info` via Traefik
|
||||
- `NTFY_UPSTREAM_BASE_URL: https://ntfy.sh` für mobile Push-Notifications
|
||||
- `NTFY_BEHIND_PROXY: true` korrekt gesetzt
|
||||
|
||||
### immich_default — internal: true gesetzt (2026-03-29)
|
||||
`immich_default` wurde von `external: true` auf ein Compose-verwaltetes internes Netz umgestellt:
|
||||
- **Vorher:** `external: true` (manuell erstellt, falsche Labels `com.docker.compose.network=default`)
|
||||
- **Nachher:** Compose-managed, `internal: true`, `driver: bridge`, korrekte Labels
|
||||
- Durchgeführt via: manuelles `docker stop` der Containers → `docker network rm immich_default` → Komodo Redeploy
|
||||
- Ergebnis: alle Immich-Container (`immich_postgres`, `immich_redis`, `immich_machine_learning`) sind jetzt vom Internet isoliert; nur `immich_server` hat zusätzlich `frontend_net` für Traefik
|
||||
|
||||
### Secrets in Komodo Stacks
|
||||
Host-Pfade in `env_file` (z.B. `/mnt/...`) sind in Git-Stacks nicht verfügbar. Standardlösung: Stack Environment Variables + `${VARIABLE_NAME}` in der Compose.
|
||||
|
||||
**Regel:** Wenn `_FILE` nicht unterstützt wird → Stack Environment Variable. Kein Secret im Git.
|
||||
|
||||
**Bewusste Ausnahme:** `paperless-ngx` bleibt fuer `PAPERLESS_DBPASS` und `PAPERLESS_REDIS` vorerst bei Stack Environment Variables. Eine Umstellung auf `_FILE` ist fachlich denkbar, wird aber nicht gegen den aktuell stabilen Produktionsstand erzwungen.
|
||||
|
||||
### Borg UI / BorgBase (2026-04-12)
|
||||
- `borg-ui` läuft als Admin-Dienst in `ops/borg-ui/docker-compose.yml`
|
||||
- nur `frontend_net`, weil Web-UI + externer SSH-Zugang zu BorgBase benötigt werden
|
||||
- keine direkten Host-Ports; Zugriff ausschließlich via Traefik + Middleware über `borg.kaleschke.info`
|
||||
- breite Restore-/Backup-Mounts bewusst gesetzt; inklusive `/local/secrets` fuer Disaster Recovery, separates Restore-Ziel unter `/mnt/user/appdata/borg-ui/restore`
|
||||
- kein separater Borg-CLI-Container nötig, da Borg UI die Borg-CLI bereits im Container mitbringt
|
||||
|
||||
| Container | `_FILE` Support |
|
||||
|---|---|
|
||||
| Vaultwarden | ✅ ja |
|
||||
| PostgreSQL | ✅ ja |
|
||||
| code-server | ✅ ja (`PASSWORD_FILE`) |
|
||||
| Immich Postgres | ✅ ja (`POSTGRES_PASSWORD_FILE`) |
|
||||
| Mealie | ✅ ja (`POSTGRES_PASSWORD_FILE`) |
|
||||
| paperless-ngx | ❌ nein für DB-Pass → Stack ENV |
|
||||
|
||||
### Reproduzierbare Deployments (2026-04-17)
|
||||
Mutable Tags wie `latest`, `stable`, `release` oder reine Major-Tags wurden auf die **aktuell laufenden Digests** eingefroren. Das ist bewusst **kein Upgrade-Mechanismus**, sondern dient dazu, den heute funktionierenden Laufzeitstand exakt im Repo festzuhalten. Echte Versions-Upgrades bleiben ein eigener, geplanter Schritt.
|
||||
|
||||
### Stateful Digest-Pinning (2026-05-05, ergaenzt 2026-05-16)
|
||||
- Tier-1/stateful Basisdienste werden bevorzugt mit sprechendem Minor-/Patch-Tag plus Digest gepinnt, z. B. `postgres:17.9@sha256:...` oder `mongo:7.0.32@sha256:...`.
|
||||
- Redis-Caches sind seit dem Hardening-Sprint 2026-05-16 auf `redis:7.4-alpine@sha256:...` vereinheitlicht. Updates erfolgen bewusst stackweise mit Smoke-Test.
|
||||
- Bereits versionierte Apps koennen optional spaeter ebenfalls Digests erhalten; dieser Schritt ist getrennt vom Datenhalter-Pinning.
|
||||
|
||||
### Nextcloud und Stirling-PDF (2026-04-19)
|
||||
- `nextcloud` wird bewusst **nicht** als AIO-Stack gebaut, sondern als klassischer Docker-Microservice-Stack mit eigenem PostgreSQL und eigenem Redis. Das passt besser zum bestehenden GitOps-/Compose-Modell des Repos.
|
||||
- `nextcloud` bleibt bei nativer App-Authentifizierung ohne zentrale ForwardAuth-Middleware vor dem Router, damit Browser-Login, Desktop-/Mobile-Clients sowie WebDAV/CardDAV sauber funktionieren.
|
||||
- `stirling-pdf` wird als geschuetzter Tool-Stack hinter `authelia@file,secure-headers@file` betrieben; die interne Stirling-Login-Funktion bleibt deaktiviert, um Doppel-Login zu vermeiden.
|
||||
|
||||
### BentoPDF und Monitoring-Zielstack (2026-04-30, aktualisiert 2026-05-17)
|
||||
- `bentopdf` ersetzt repo-seitig `stirling-pdf` auf der bestehenden Domain `pdf.kaleschke.info`, bleibt aber bis zum bewussten Komodo-Deploy nur vorbereitet.
|
||||
- BentoPDF benoetigt fuer Office-Konvertierung die Cross-Origin-Isolation-Header `Cross-Origin-Opener-Policy: same-origin` und `Cross-Origin-Embedder-Policy: require-corp`; diese werden per Traefik-Docker-Middleware gesetzt.
|
||||
- `monitoring/` ist der zentrale Zielstack fuer Prometheus, Loki, Promtail, Grafana, node-exporter, cAdvisor und InfluxDB 3 Core.
|
||||
- `monitoring-grafana` wird als geschuetztes Monitoring-UI unter `monitoring.kaleschke.info` betrieben.
|
||||
- `monitoring-influxdb3-core` bleibt ohne Traefik-/Public-Route; fuer interne Writer wie Home Assistant kann Port `8181` per `INFLUXDB_BIND_IP` auf eine LAN-Adresse gebunden werden.
|
||||
- Fuer dieses Port-Publishing nutzt `monitoring-influxdb3-core` zusaetzlich `monitoring_influx_lan`. Das ist keine Public-App-Freigabe und ersetzt nicht die Token-Authentifizierung.
|
||||
- InfluxDB 3 Core nutzt einen festen Versionstag statt `latest`, weil der InfluxDB-`latest`-Tag versionsstrategisch im Umbruch ist.
|
||||
- Die alten Pfade `ops/grafana-influxdb` und `ops/loki` wurden am 2026-05-26 aus dem aktiven Repo entfernt; `monitoring/` ist der einzige Observability-Zielstack.
|
||||
- Uptime Kuma wurde nach erfolgreichem Blackbox-/Grafana-Smoke-Test entfernt; `monitoring/` ist die Quelle fuer HTTP-Erreichbarkeit und Alerts.
|
||||
|
||||
### Monitoring-Logging-Baseline (2026-05-17)
|
||||
- `monitoring-loki` laeuft intern auf `monitoring_net`, ohne Traefik-Route und ohne Host-Port.
|
||||
- `monitoring-promtail` sammelt Docker-Logs ueber `/var/run/docker.sock:ro` und `/var/lib/docker/containers:ro` und schreibt sie an Loki.
|
||||
- `monitoring-grafana` bekommt provisionierte Datasources fuer Prometheus, Loki und InfluxDB 3 Core.
|
||||
- Loki-Logdaten sind Diagnosematerial mit begrenzter Retention, keine primaere Restore-Quelle.
|
||||
|
||||
### Authelia ohne Redis-Session-Backend (2026-05-04)
|
||||
- Authelia nutzt PostgreSQL fuer persistente Storage-Daten, aber bewusst kein Redis-Session-Backend.
|
||||
- Das haelt den Tier-1-Auth-Pfad einfacher; nach einem Authelia-Restart muessen aktive Sessions neu aufgebaut werden.
|
||||
- `infra/redis` ist historisch als "shared Cache" angelegt, wird aber faktisch nur von Paperless als App-Cache genutzt. Immich, Nextcloud und Mealie betreiben jeweils eigene Redis-Instanzen in ihren App-internen Netzen; Authelia laeuft bewusst ohne Redis. Eine spaetere Konsolidierung in `apps/paperless/` (analog zu Mealie/Immich/Nextcloud) bleibt fachlich denkbar, ist aber kein priorisierter Schritt.
|
||||
|
||||
### ddns-updater — Netz-Ausnahme
|
||||
Bleibt bewusst in `frontend_net` statt `backend_net`, weil `backend_net` `internal: true` ist und ddns-updater die Cloudflare-API erreichen muss.
|
||||
|
||||
### mail-archiver — Hybrid-Dienst
|
||||
Benötigt `backend_net` (PostgreSQL) + `frontend_net` (IMAP-Abruf von GMX/Gmail). Kein reiner Backend-Dienst. Die Web-UI ist via Traefik unter `mail.kaleschke.info` erreichbar und wird durch `authelia@file,secure-headers@file` plus App-eigene Auth geschuetzt.
|
||||
|
||||
### Netzwerk-Standard für Apps mit Datenbanken
|
||||
- App → `frontend_net` + internes Netzwerk
|
||||
- Datenbank → nur internes Netzwerk (`internal: true`)
|
||||
|
||||
Beispiel (Mealie): `mealie` → `frontend_net` + `mealie_internal`, `mealie-postgres` → nur `mealie_internal`.
|
||||
|
||||
---
|
||||
|
||||
## Schlussformel
|
||||
|
||||
Dieses Dokument ist keine lose Notiz, sondern das **operative Masterdokument** für die Docker- und Zugriffsarchitektur des Homelabs.
|
||||
|
||||
@@ -8,20 +8,19 @@ Vor jeder Aenderung lesen:
|
||||
|
||||
1. `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
2. `docs/WORKFLOW.md`
|
||||
3. `docs/README.md`
|
||||
|
||||
Bei Restore-, Host-Ausfall- oder Wiederanlauf-Fragen zusaetzlich:
|
||||
|
||||
4. `docs/DISASTER_RECOVERY.md`
|
||||
5. `docs/RESTORE_MATRIX.md`
|
||||
6. `docs/SERVICES_RECOVERY.md`
|
||||
3. `docs/DISASTER_RECOVERY.md`
|
||||
4. `docs/RESTORE_MATRIX.md`
|
||||
5. `docs/SERVICES_RECOVERY.md`
|
||||
|
||||
Bei Hardware-, Netzwerk-, Provider- oder Kapazitaetsfragen zusaetzlich:
|
||||
|
||||
7. `docs/HARDWARE_INVENTORY.md`
|
||||
8. `docs/NETWORK_INVENTORY.md`
|
||||
9. `docs/EXTERNAL_DEPENDENCIES.md`
|
||||
10. `docs/CAPACITY_AND_LIFECYCLE.md`
|
||||
6. `docs/HARDWARE_INVENTORY.md`
|
||||
7. `docs/NETWORK_INVENTORY.md`
|
||||
8. `docs/EXTERNAL_DEPENDENCIES.md`
|
||||
9. `docs/CAPACITY_AND_LIFECYCLE.md`
|
||||
|
||||
## Architektur
|
||||
|
||||
@@ -66,7 +65,6 @@ Bei Hardware-, Netzwerk-, Provider- oder Kapazitaetsfragen zusaetzlich:
|
||||
|
||||
## Status
|
||||
|
||||
- Offene Punkte stehen ausschliesslich in `docs/MASTER_TODO.md`; Entscheidungen mit Begruendung in `docs/DECISIONS.md`.
|
||||
- Komodo ist der primaere und einzige produktive Stack-Manager.
|
||||
- Komodo bleibt bewusst bei nativer Authentifizierung; zentrale Traefik-Auth wird dort nicht pauschal vorgeschaltet.
|
||||
- Portainer CE ist abgeschaltet und kein Teil des aktiven Betriebs mehr.
|
||||
@@ -77,5 +75,4 @@ Bei Hardware-, Netzwerk-, Provider- oder Kapazitaetsfragen zusaetzlich:
|
||||
- Recovery-kritische Services-Pfade wie Gitea-Repositories, Komodo-Workspaces und Host-Automation sind in `docs/SERVICES_RECOVERY.md` beschrieben.
|
||||
- Hardware-, Netzwerk-, Provider- und Capacity-Inventare sind als operative Audit-Dokumente unter `docs/HARDWARE_INVENTORY.md`, `docs/NETWORK_INVENTORY.md`, `docs/EXTERNAL_DEPENDENCIES.md` und `docs/CAPACITY_AND_LIFECYCLE.md` vorbereitet.
|
||||
- Der verbindliche Detailablauf steht in `docs/WORKFLOW.md`.
|
||||
- Der Doku-Index mit aktiven und archivierten Dokumenten steht in `docs/README.md`.
|
||||
- `nextcloud`, `bentopdf` und `monitoring` folgen dem dokumentierten Netz-/Secret-/Traefik-Modell; der zentrale Monitoring-Stack buendelt Prometheus, Loki, Promtail, Grafana und InfluxDB 3 Core.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
bentopdf:
|
||||
image: bentopdfteam/bentopdf:2.8.5@sha256:2d867aacb8ab5b196d00ee86944b1899d09d72df355384c5e15cf974737963a0
|
||||
image: bentopdfteam/bentopdf:2.8.4@sha256:f54b9ed9c56b767e0098b525468206689b666323c2b500b9686c3cf41cdfa348
|
||||
container_name: bentopdf
|
||||
restart: unless-stopped
|
||||
tmpfs:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
image: ghcr.io/immich-app/immich-server:v2.7.5@sha256:c15bff75068effb03f4355997d03dc7e0fc58720c2b54ad6f7f10d1bc57efaa5
|
||||
image: ghcr.io/immich-app/immich-server:release@sha256:c15bff75068effb03f4355997d03dc7e0fc58720c2b54ad6f7f10d1bc57efaa5
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- redis
|
||||
@@ -32,19 +32,8 @@ services:
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich_machine_learning
|
||||
image: ghcr.io/immich-app/immich-machine-learning:v2.7.5@sha256:a2501141440f10516d329fdfba2c68082e19eb9ba6016c061ac80d23beadf7f3
|
||||
image: ghcr.io/immich-app/immich-machine-learning:release@sha256:a2501141440f10516d329fdfba2c68082e19eb9ba6016c061ac80d23beadf7f3
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
# Workaround fuer gunicorn-25.1.0-Control-Socket-Bug: der Worker haengt
|
||||
# nach "Control socket listening at /usr/src/gunicorn.ctl" und erreicht
|
||||
# nie "Application startup complete" -> Container bleibt dauerhaft
|
||||
# unhealthy, ML (Gesichtserkennung/CLIP/Smart-Search) ist tot.
|
||||
# --no-control-socket deaktiviert das fehlerhafte Feature. immich-ml
|
||||
# startet gunicorn als Subprozess, der GUNICORN_CMD_ARGS aus der Env
|
||||
# liest und anhaengt. Bestaetigte Upstream-Regression seit Immich 2.6
|
||||
# (immich#27228, gunicorn#3510). Re-check: bei Immich-Update, das
|
||||
# gunicorn auf >25.1.0/<25.1.0 mit Fix bringt, wieder entfernen.
|
||||
GUNICORN_CMD_ARGS: "--no-control-socket"
|
||||
volumes:
|
||||
- model-cache:/cache
|
||||
networks:
|
||||
@@ -54,7 +43,7 @@ services:
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:8.8.0-alpine@sha256:09160599abd229764c0fb44cb6be640294e1d360a54b19985ab4843dcf2d90f1
|
||||
image: redis:7.4-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- immich_default
|
||||
@@ -63,15 +52,14 @@ services:
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23
|
||||
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
|
||||
POSTGRES_USER: immich
|
||||
POSTGRES_DB: immich
|
||||
shm_size: 128mb
|
||||
volumes:
|
||||
- /mnt/user/appdata/immich_postgres_vectorchord:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/immich_postgres:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/secrets/immich_postgres_password.txt:/run/secrets/postgres_password:ro
|
||||
networks:
|
||||
- immich_default
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
mail-archiver:
|
||||
image: s1t5/mailarchiver@sha256:4ea7ecc47ad1dd2c523b85c3967574b61e39def1b6fd26edf874e21733c4018c
|
||||
image: s1t5/mailarchiver@sha256:94d7525db56b13154a14203f8fb7b53fac034f28a914c32da9d2e426b49328ed
|
||||
container_name: mail-archiver
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
services:
|
||||
mealie:
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.19.2@sha256:f68e959bf66f4f458893ea58facac71690fe6f2ac7a31466b5cecb41b4e99c02
|
||||
image: ghcr.io/mealie-recipes/mealie:v3.12.0@sha256:8d962f611390a1cca667eed32a29e9467e9c01c523e2db3ad00f667372067f9d
|
||||
container_name: mealie
|
||||
restart: unless-stopped
|
||||
|
||||
# OIDC: Authelia ueber Host-LAN-IP -> Traefik erreichbar (Container-DNS loest
|
||||
# auth.kaleschke.info sonst nicht; gleiches Muster wie Komodo. SNI bleibt der
|
||||
# Hostname, Let's-Encrypt-Cert validiert weiter.
|
||||
extra_hosts:
|
||||
- "auth.kaleschke.info:192.168.178.58"
|
||||
|
||||
environment:
|
||||
TZ: Europe/Berlin
|
||||
ALLOW_SIGNUP: "false"
|
||||
@@ -24,16 +18,6 @@ services:
|
||||
|
||||
BASE_URL: https://mealie.kaleschke.info
|
||||
|
||||
# --- Authelia OIDC SSO (additiv, 2026-06-06; lokaler Login bleibt) ---
|
||||
OIDC_AUTH_ENABLED: "true"
|
||||
OIDC_PROVIDER_NAME: Authelia
|
||||
OIDC_CONFIGURATION_URL: https://auth.kaleschke.info/.well-known/openid-configuration
|
||||
OIDC_CLIENT_ID: mealie
|
||||
OIDC_CLIENT_SECRET: ${MEALIE_OIDC_CLIENT_SECRET}
|
||||
OIDC_SIGNUP_ENABLED: "true"
|
||||
OIDC_AUTO_REDIRECT: "false"
|
||||
OIDC_REMEMBER_ME: "true"
|
||||
|
||||
volumes:
|
||||
- /mnt/user/appdata/mealie/data:/app/data
|
||||
|
||||
@@ -63,10 +47,10 @@ services:
|
||||
POSTGRES_USER: mealie
|
||||
POSTGRES_DB: mealie
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
|
||||
PGDATA: /var/lib/postgresql/18/docker
|
||||
PGDATA: /var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
- /mnt/user/appdata/mealie/postgres18:/var/lib/postgresql
|
||||
- /mnt/user/appdata/mealie/postgres:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/secrets/mealie_postgres_password.txt:/run/secrets/postgres_password:ro
|
||||
|
||||
networks:
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
services:
|
||||
n8n:
|
||||
image: docker.n8n.io/n8nio/n8n:2.26.2@sha256:61ba01bc5e39304bbc928c9dbecd938c3a5cc1331b68affba6a34d0f654c43d9
|
||||
container_name: n8n
|
||||
restart: unless-stopped
|
||||
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
dns:
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
|
||||
environment:
|
||||
TZ: Europe/Berlin
|
||||
GENERIC_TIMEZONE: Europe/Berlin
|
||||
|
||||
N8N_HOST: n8n.kaleschke.info
|
||||
N8N_PORT: "5678"
|
||||
N8N_PROTOCOL: https
|
||||
N8N_EDITOR_BASE_URL: https://n8n.kaleschke.info/
|
||||
WEBHOOK_URL: https://n8n.kaleschke.info/
|
||||
N8N_PROXY_HOPS: "1"
|
||||
|
||||
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
|
||||
|
||||
N8N_DIAGNOSTICS_ENABLED: "false"
|
||||
N8N_PERSONALIZATION_ENABLED: "false"
|
||||
N8N_HIRING_BANNER_ENABLED: "false"
|
||||
N8N_RUNNERS_ENABLED: "true"
|
||||
N8N_BLOCK_ENV_ACCESS_IN_NODE: "true"
|
||||
|
||||
volumes:
|
||||
- /mnt/user/appdata/n8n/data:/home/node/.n8n
|
||||
|
||||
networks:
|
||||
- frontend_net
|
||||
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=frontend_net"
|
||||
- "traefik.http.routers.n8n.rule=Host(`n8n.kaleschke.info`)"
|
||||
- "traefik.http.routers.n8n.entrypoints=websecure"
|
||||
- "traefik.http.routers.n8n.tls=true"
|
||||
- "traefik.http.routers.n8n.tls.certresolver=le"
|
||||
- "traefik.http.routers.n8n.middlewares=secure-headers@file"
|
||||
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
|
||||
|
||||
networks:
|
||||
frontend_net:
|
||||
external: true
|
||||
@@ -1,284 +0,0 @@
|
||||
{
|
||||
"name": "GMX -> OpenAI -> Gitea Issue (Super Productivity)",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"pollTimes": {
|
||||
"item": [
|
||||
{
|
||||
"mode": "everyMinute"
|
||||
}
|
||||
]
|
||||
},
|
||||
"format": "simple",
|
||||
"options": {
|
||||
"customEmailConfig": "[\"UNSEEN\"]",
|
||||
"forceReconnect": 15
|
||||
},
|
||||
"postProcessAction": "read"
|
||||
},
|
||||
"id": "11111111-1111-1111-1111-111111111111",
|
||||
"name": "IMAP: GMX UNSEEN",
|
||||
"type": "n8n-nodes-base.emailReadImap",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
240,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"imap": {
|
||||
"id": "REPLACE_GMX_IMAP_CRED_ID",
|
||||
"name": "GMX IMAP"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "a1",
|
||||
"name": "from",
|
||||
"value": "={{ $json.from }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "a2",
|
||||
"name": "subject",
|
||||
"value": "={{ $json.subject }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "a3",
|
||||
"name": "date",
|
||||
"value": "={{ $json.date }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "a4",
|
||||
"name": "messageId",
|
||||
"value": "={{ $json.messageId || $json['message-id'] || '' }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "a5",
|
||||
"name": "text",
|
||||
"value": "={{ ($json.text || $json.textPlain || '').toString().slice(0, 8000) }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "22222222-2222-2222-2222-222222222222",
|
||||
"name": "Extract mail fields",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
460,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://api.openai.com/v1/chat/completions",
|
||||
"authentication": "genericCredentialType",
|
||||
"genericAuthType": "httpHeaderAuth",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.2,\n \"response_format\": {\n \"type\": \"json_schema\",\n \"json_schema\": {\n \"name\": \"issue_extraction\",\n \"strict\": true,\n \"schema\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\"title\", \"body_md\", \"priority\", \"due_date\", \"category\"],\n \"properties\": {\n \"title\": { \"type\": \"string\", \"maxLength\": 80 },\n \"body_md\": { \"type\": \"string\" },\n \"priority\": { \"type\": \"string\", \"enum\": [\"niedrig\", \"normal\", \"hoch\"] },\n \"due_date\": { \"type\": [\"string\", \"null\"], \"description\": \"ISO YYYY-MM-DD oder null\" },\n \"category\": { \"type\": \"string\" }\n }\n }\n }\n },\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"Du extrahierst aus einer E-Mail eine Aufgabe fuer ein Issue-Tracking-System. Antworte ausschliesslich gemaess JSON-Schema. Sprache: Deutsch.\\n- title: imperativ, max. 80 Zeichen, ohne abschliessenden Punkt.\\n- body_md: 2 bis 6 Saetze. Was ist zu tun, warum, bis wann. Keine Begruessungen.\\n- priority: niedrig | normal | hoch.\\n- due_date: ISO YYYY-MM-DD wenn aus Mail ableitbar, sonst null.\\n- category: kurzes Schlagwort (rechnung, termin, technik, familie, sonstiges, ...).\"\n },\n {\n \"role\": \"user\",\n \"content\": {{ JSON.stringify('Absender: ' + $json.from + '\\nDatum: ' + $json.date + '\\nBetreff: ' + $json.subject + '\\n\\nMailtext:\\n' + $json.text) }}\n }\n ]\n}",
|
||||
"options": {
|
||||
"timeout": 60000
|
||||
}
|
||||
},
|
||||
"id": "33333333-3333-3333-3333-333333333333",
|
||||
"name": "OpenAI: extract issue",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
680,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"httpHeaderAuth": {
|
||||
"id": "REPLACE_OPENAI_HEADER_AUTH_CRED_ID",
|
||||
"name": "OpenAI Bearer"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "b1",
|
||||
"name": "extracted",
|
||||
"value": "={{ JSON.parse($json.choices[0].message.content) }}",
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"id": "b2",
|
||||
"name": "mail",
|
||||
"value": "={{ $('Extract mail fields').item.json }}",
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "44444444-4444-4444-4444-444444444444",
|
||||
"name": "Parse OpenAI JSON",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
900,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"assignments": {
|
||||
"assignments": [
|
||||
{
|
||||
"id": "c1",
|
||||
"name": "title",
|
||||
"value": "={{ ($json.extracted.priority === 'hoch' ? '[P1] ' : '') + $json.extracted.title }}",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"id": "c2",
|
||||
"name": "body",
|
||||
"value": "={{ $json.extracted.body_md + '\\n\\n---\\n**Kategorie:** ' + $json.extracted.category + '\\n**Prioritaet:** ' + $json.extracted.priority + ($json.extracted.due_date ? '\\n**Faellig:** ' + $json.extracted.due_date : '') + '\\n**Quelle:** Mail von ' + $json.mail.from + ' (' + $json.mail.date + ')\\n**Betreff:** ' + $json.mail.subject + '\\n**Message-ID:** ' + $json.mail.messageId }}",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "55555555-5555-5555-5555-555555555555",
|
||||
"name": "Build issue payload",
|
||||
"type": "n8n-nodes-base.set",
|
||||
"typeVersion": 3.4,
|
||||
"position": [
|
||||
1120,
|
||||
300
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://git.kaleschke.info/api/v1/repos/Micha/mails/issues",
|
||||
"authentication": "genericCredentialType",
|
||||
"genericAuthType": "httpHeaderAuth",
|
||||
"sendHeaders": true,
|
||||
"headerParameters": {
|
||||
"parameters": [
|
||||
{
|
||||
"name": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"name": "Accept",
|
||||
"value": "application/json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"title\": {{ JSON.stringify($json.title) }},\n \"body\": {{ JSON.stringify($json.body) }},\n \"assignees\": [\"Micha\"]\n}",
|
||||
"options": {
|
||||
"timeout": 30000
|
||||
}
|
||||
},
|
||||
"id": "66666666-6666-6666-6666-666666666666",
|
||||
"name": "Gitea: create issue",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.2,
|
||||
"position": [
|
||||
1340,
|
||||
300
|
||||
],
|
||||
"credentials": {
|
||||
"httpHeaderAuth": {
|
||||
"id": "REPLACE_GITEA_HEADER_AUTH_CRED_ID",
|
||||
"name": "Gitea Token"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"IMAP: GMX UNSEEN": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Extract mail fields",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Extract mail fields": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "OpenAI: extract issue",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"OpenAI: extract issue": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parse OpenAI JSON",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parse OpenAI JSON": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Build issue payload",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Build issue payload": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Gitea: create issue",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"meta": {
|
||||
"instanceId": "homelab-n8n"
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
nextcloud:
|
||||
image: nextcloud:33.0.5-apache@sha256:56bdc45109067500fd0832fa64832b7c77a167d9394cbf5f0f4b59740b94194d
|
||||
image: nextcloud:33.0.2-apache@sha256:39b2ba219271a22851f8409a7b1295d5892aba1696d9193500311c02e60591a4
|
||||
container_name: nextcloud
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
@@ -54,9 +54,9 @@ services:
|
||||
POSTGRES_DB: nextcloud
|
||||
POSTGRES_USER: nextcloud
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
|
||||
PGDATA: /var/lib/postgresql/18/docker
|
||||
PGDATA: /var/lib/postgresql/data
|
||||
volumes:
|
||||
- /mnt/user/appdata/nextcloud/postgres18:/var/lib/postgresql
|
||||
- /mnt/user/appdata/nextcloud/postgres:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/secrets/nextcloud_postgres_password.txt:/run/secrets/postgres_password:ro
|
||||
networks:
|
||||
- nextcloud_internal
|
||||
@@ -64,7 +64,7 @@ services:
|
||||
- no-new-privileges:true
|
||||
|
||||
nextcloud-redis:
|
||||
image: redis:8.8.0-alpine@sha256:09160599abd229764c0fb44cb6be640294e1d360a54b19985ab4843dcf2d90f1
|
||||
image: redis:7.4-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99
|
||||
container_name: nextcloud-redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --save 60 1 --loglevel warning
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
ntfy:
|
||||
image: binwiederhier/ntfy@sha256:f8a9b104313b87cc24ae4f775f39e6328205b57dff6ede3eaf098a91e5d79f59
|
||||
image: binwiederhier/ntfy@sha256:2b9e12d56a538f4402da51328eeca02696c4b207ab7fbe031c27e51a22ca9b86
|
||||
container_name: ntfy
|
||||
restart: unless-stopped
|
||||
dns:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
paperless-gpt:
|
||||
image: icereed/paperless-gpt:v0.25.1@sha256:c0ce6186028911101a2cfe68353f14a9dbb2653596f3f1cff94de4b6db3114ff
|
||||
image: icereed/paperless-gpt:v0.24.0@sha256:15bad5d455b98f21bb7b5d6615f56871ff67a8bb379dc0dd7ba411f4633071a6
|
||||
container_name: paperless-gpt
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
@@ -15,18 +15,15 @@ services:
|
||||
PAPERLESS_API_TOKEN: "${PAPERLESS_API_TOKEN}"
|
||||
MANUAL_TAG: "paperless-gpt"
|
||||
AUTO_TAG: "paperless-gpt-auto"
|
||||
LLM_PROVIDER: "openai"
|
||||
LLM_MODEL: "gpt-5.4-mini"
|
||||
OPENAI_API_KEY: "${OPENAI_API_KEY}"
|
||||
OPENAI_BASE_URL: "https://api.openai.com/v1"
|
||||
TOKEN_LIMIT: "12000"
|
||||
LLM_REQUESTS_PER_MINUTE: "30"
|
||||
LLM_PROVIDER: "ollama"
|
||||
LLM_MODEL: "qwen3:8b"
|
||||
OLLAMA_HOST: "http://192.168.178.103:11434"
|
||||
OLLAMA_CONTEXT_LENGTH: "4096"
|
||||
TOKEN_LIMIT: "1500"
|
||||
LLM_LANGUAGE: "German"
|
||||
OCR_PROVIDER: "llm"
|
||||
VISION_LLM_PROVIDER: "openai"
|
||||
VISION_LLM_MODEL: "gpt-5.4-mini"
|
||||
VISION_LLM_TEMPERATURE: "1.0"
|
||||
VISION_LLM_REQUESTS_PER_MINUTE: "20"
|
||||
VISION_LLM_PROVIDER: "ollama"
|
||||
VISION_LLM_MODEL: "minicpm-v:latest"
|
||||
OCR_PROCESS_MODE: "image"
|
||||
CREATE_NEW_TAGS: "true"
|
||||
AUTO_GENERATE_TITLE: "true"
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
services:
|
||||
paperless:
|
||||
image: ghcr.io/paperless-ngx/paperless-ngx:2.20.15@sha256:6c86cad803970ea782683a8e80e7403444c5bf3cf70de63b4d3c8e87500db92f
|
||||
image: ghcr.io/paperless-ngx/paperless-ngx:2.20.10@sha256:07a0b4ba01ce377c82a0636e16c0c3d931fde5b7e9304de6601986cc42d9b6e6
|
||||
container_name: paperless-ngx
|
||||
restart: unless-stopped
|
||||
# OIDC: Authelia ueber Host-LAN-IP -> Traefik erreichbar (Container-DNS sonst nicht)
|
||||
extra_hosts:
|
||||
- "auth.kaleschke.info:192.168.178.58"
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
environment:
|
||||
@@ -20,11 +17,6 @@ services:
|
||||
- PAPERLESS_OCR_LANGUAGE=deu+eng
|
||||
- PAPERLESS_URL=https://paperless.kaleschke.info
|
||||
|
||||
# --- Authelia OIDC SSO (additiv, 2026-06-06; lokaler Login bleibt) ---
|
||||
- PAPERLESS_APPS=allauth.socialaccount.providers.openid_connect
|
||||
- PAPERLESS_SOCIAL_AUTO_SIGNUP=true
|
||||
- 'PAPERLESS_SOCIALACCOUNT_PROVIDERS={"openid_connect":{"OAUTH_PKCE_ENABLED":true,"APPS":[{"provider_id":"authelia","name":"Authelia","client_id":"paperless","secret":"${PAPERLESS_OIDC_SECRET}","settings":{"server_url":"https://auth.kaleschke.info"}}]}}'
|
||||
|
||||
# Barcode / ASN
|
||||
- PAPERLESS_CONSUMER_ENABLE_BARCODES=1
|
||||
- PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE=1
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
services:
|
||||
super-productivity:
|
||||
image: johannesjo/super-productivity:v18.9.1@sha256:773760107344e739f4c29409f7842db66a1b167d50eb2c40248cb5b5b328652e
|
||||
container_name: super-productivity
|
||||
restart: unless-stopped
|
||||
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
networks:
|
||||
- frontend_net
|
||||
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=frontend_net"
|
||||
- "traefik.http.routers.super-productivity.rule=Host(`sp.kaleschke.info`)"
|
||||
- "traefik.http.routers.super-productivity.entrypoints=websecure"
|
||||
- "traefik.http.routers.super-productivity.tls=true"
|
||||
- "traefik.http.routers.super-productivity.tls.certresolver=le"
|
||||
- "traefik.http.routers.super-productivity.middlewares=authelia@file,secure-headers@file"
|
||||
- "traefik.http.services.super-productivity.loadbalancer.server.port=80"
|
||||
|
||||
networks:
|
||||
frontend_net:
|
||||
external: true
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
unbound:
|
||||
image: shaanmajid/unbound:1.25.1@sha256:f140db02a005904802bf5840093e95e675321aa060a00426fdffc2a3ac2eeb6b
|
||||
image: shaanmajid/unbound:1.24.2@sha256:d278b71c592b2555cc802911bb0757a6a24f4a8ad7f5848720296c04876eeb63
|
||||
container_name: unbound
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
### VOLUMES ###
|
||||
DriveLetter Label FS Size_GB Free_GB Health
|
||||
C (kein Label) NTFS 166.9 59.5 Healthy
|
||||
D Daten-Projekte NTFS 167.7 148.6 Healthy
|
||||
E Games NTFS 930.6 714.9 Healthy
|
||||
G M2 SSD NTFS 930.9 877.5 Healthy
|
||||
H Externe HDD NTFS 7452.0 3801.3 Healthy
|
||||
(kein BW) Recovery x5 NTFS diverse diverse Healthy
|
||||
|
||||
### DISKS ###
|
||||
Disk 0 INTEL SSDSC2BW180A3L SATA 167.68 GB GPT Healthy Serial: CVCV3105053K180EGN
|
||||
Disk 1 INTEL SSDSC2BW180A3L SATA 167.68 GB GPT Healthy Serial: CVCV311302TH180EGN
|
||||
Disk 2 Samsung SSD 980 PRO 1TB NVMe 931.51 GB GPT Healthy
|
||||
Disk 3 WDC WDS100T2B0C NVMe 931.51 GB GPT Healthy
|
||||
Disk 4 asmedia ASM235 USB 7.28 TB GPT Healthy
|
||||
|
||||
### PARTITIONS ###
|
||||
Disk 0: [Reserved 16MB] [C: 166.87 GB Basic] [Recovery 809 MB]
|
||||
Disk 1: [Reserved 15.98 MB] [D: 167.66 GB Basic]
|
||||
Disk 2: [Reserved 15.98 MB] [E: 930.63 GB Basic] [Recovery 885 MB] <- F: ist weg
|
||||
Disk 3: [System 100 MB] [Reserved 16 MB] [G: 930.89 GB Basic] [Recovery 524 MB]
|
||||
Disk 4: [Reserved 15.98 MB] [H: 7.28 TB Basic]
|
||||
@@ -1,52 +0,0 @@
|
||||
### D:\ TOP-LEVEL ###
|
||||
00_Inbox Directory 2026-06-04
|
||||
10_Dokumente Directory 2026-06-04
|
||||
11_Bilder Directory 2026-06-04 [ReadOnly-Attribut gesetzt]
|
||||
12_Videos Directory 2026-06-04
|
||||
13_Musik Directory 2026-06-04
|
||||
14_Downloads Directory 2026-06-04
|
||||
20_Projekte Directory 2026-06-04
|
||||
30_Finanzen Directory 2026-06-04
|
||||
90_Archiv Directory 2026-06-04
|
||||
Micha Directory 2026-06-05 [Altquelle, noch vorhanden]
|
||||
WSL Directory 2026-06-04 [nicht in Soll-Doku]
|
||||
DumpStack.log File
|
||||
|
||||
### D:\Micha INHALT ###
|
||||
Videos Directory 2026-06-05 [1 Datei, 0 MB - fast leer]
|
||||
(alle anderen Unterordner weg)
|
||||
|
||||
### D:\00_Inbox INHALT ###
|
||||
Desktop Directory 2026-06-05 [ReadOnly - das ist das Known-Folder-Ziel!]
|
||||
|
||||
### E:\ TOP-LEVEL ###
|
||||
BattleNet Directory 2026-06-04 [SOLL]
|
||||
EA Directory 2026-06-04 [SOLL]
|
||||
EpicGames Directory 2026-06-04 [SOLL]
|
||||
Riot Directory 2026-06-04 [SOLL]
|
||||
Steam Directory 2026-06-05 [SOLL]
|
||||
Ubisoft Directory 2026-06-04 [SOLL]
|
||||
_Standalone FEHLT! [SOLL laut Doku]
|
||||
|
||||
### G:\ TOP-LEVEL ###
|
||||
Apps Directory 2026-06-04 [nicht in Soll-Doku]
|
||||
Gitea_Clone Directory 2026-04-15 [nicht in Soll-Doku - bewusst, homelab-infra]
|
||||
repos Directory 2026-06-05 [SOLL]
|
||||
Tools Directory 2026-06-05 [SOLL - Doku schreibt 'tools' lowercase, NTFS case-insensitive]
|
||||
Workspace Directory 2026-06-04 [nicht in Soll-Doku]
|
||||
|
||||
### KNOWN FOLDER REDIRECTS (Ist) ###
|
||||
Desktop -> D:\00_Inbox\Desktop [ABWEICHUNG! Soll: D:\Micha\Desktop]
|
||||
Documents -> D:\10_Dokumente [OK]
|
||||
Downloads -> D:\14_Downloads [OK]
|
||||
Pictures -> D:\11_Bilder [OK]
|
||||
Music -> D:\13_Musik [OK]
|
||||
Videos -> D:\12_Videos [OK]
|
||||
|
||||
### DOPPELBESTAND D:\Micha\* vs D:\NN_* ###
|
||||
D:\Micha\Dokumente : NICHT VORHANDEN | D:\10_Dokumente : 4011 Dateien, 595 MB
|
||||
D:\Micha\Bilder : NICHT VORHANDEN | D:\11_Bilder : 7789 Dateien, 12367 MB
|
||||
D:\Micha\Videos : 1 Datei, 0 MB | D:\12_Videos : 1 Datei, 0 MB
|
||||
D:\Micha\Musik : NICHT VORHANDEN | D:\13_Musik : 0 Dateien
|
||||
D:\Micha\Downloads : NICHT VORHANDEN | D:\14_Downloads : 2186 Dateien, 2211 MB
|
||||
D:\Micha\Finanzen : NICHT VORHANDEN | D:\30_Finanzen : 126 Dateien, 123 MB
|
||||
@@ -1,63 +0,0 @@
|
||||
### OS BASELINE ###
|
||||
Caption: Microsoft Windows 11 Pro
|
||||
Build: 26200
|
||||
Version: 10.0.26200
|
||||
Architecture: 64-Bit
|
||||
InstallDate: 2026-05-10 13:11:27
|
||||
LastBoot: 2026-06-05 07:57:08
|
||||
Uptime: 0.04 Tage (~1 Stunde zum Audit-Zeitpunkt)
|
||||
Manufacturer: Micro-Star International Co., Ltd.
|
||||
Model: MS-7D32
|
||||
RAM: 31.79 GB
|
||||
CPU: Intel Core i5-14600KF, 14 Cores, 20 Threads, 3500 MHz
|
||||
|
||||
### AKTIVIERUNG ###
|
||||
Name: Windows(R), Professional edition
|
||||
LicenseStatus: 1 (Aktiv)
|
||||
Channel: OEM_DM
|
||||
|
||||
### AUSSTEHENDE UPDATES ###
|
||||
Windows Update pending: 0
|
||||
Reboot pending: Nein
|
||||
|
||||
### DEFENDER ###
|
||||
AMProductVersion: 4.18.26040.7
|
||||
AMServiceEnabled: True
|
||||
AntivirusEnabled: True
|
||||
AntispywareEnabled: True
|
||||
RealTimeProtection: True
|
||||
TamperProtection: True
|
||||
SignatureAge: 0 Tage (aktuell)
|
||||
Exclusions: KEIN ADMIN -> nicht lesbar
|
||||
ASR Rules: KEIN ADMIN -> nicht lesbar (Get-MpPreference liefert leer)
|
||||
|
||||
### FIREWALL ###
|
||||
Domain: Enabled, DefaultInboundAction: NotConfigured, DefaultOutboundAction: NotConfigured
|
||||
Private: Enabled, DefaultInboundAction: NotConfigured, DefaultOutboundAction: NotConfigured
|
||||
Public: Enabled, DefaultInboundAction: NotConfigured, DefaultOutboundAction: NotConfigured
|
||||
HINWEIS: NotConfigured = Windows-Default (eingehend blockieren, ausgehend erlauben)
|
||||
|
||||
### BITLOCKER ###
|
||||
KEIN ADMIN -> Get-BitLockerVolume verweigert (Access Denied). Status unbekannt.
|
||||
|
||||
### SECURE BOOT ###
|
||||
KEIN ADMIN -> Confirm-SecureBootUEFI verweigert. Status unbekannt.
|
||||
|
||||
### TPM ###
|
||||
KEIN ADMIN -> Get-Tpm liefert alle Felder leer. Status unbekannt.
|
||||
|
||||
### UAC ###
|
||||
EnableLUA: 1 (aktiv)
|
||||
ConsentPromptBehaviorAdmin: 5 (Nachfrage mit UI, ohne Secure Desktop laut Wert, aber...)
|
||||
PromptOnSecureDesktop: 1 (Secure Desktop ist AN - Standard-Konfiguration korrekt)
|
||||
|
||||
### LOKALE ADMINS ###
|
||||
Gruppe Administratoren: Administrator, michi
|
||||
|
||||
### BCD ###
|
||||
KEIN ADMIN -> bcdedit /enum verweigert.
|
||||
Letzte bekannte Aussage (Doku boot-cleanup-plan): Keine partition=F: Referenz nach Cleanup + Neustarttest.
|
||||
|
||||
### WinRE ###
|
||||
KEIN ADMIN -> reagentc /info verweigert.
|
||||
Letzte bekannte Aussage (Doku): WinRE Disabled.
|
||||
@@ -1,58 +0,0 @@
|
||||
### NETZWERK-ADAPTER (UP) ###
|
||||
Ethernet Intel I225-V MAC: 04-7C-16-53-04-E4 1 Gbps
|
||||
Tailscale Tunnel 100 Gbps (virtuell)
|
||||
vEthernet WSL (Hyper-V) MAC: 00-15-5D-F3-5F-C9 10 Gbps (virtuell)
|
||||
|
||||
### IP-ADRESSEN ###
|
||||
Ethernet: 192.168.178.103/24
|
||||
Tailscale: 100.78.133.37/32
|
||||
WSL bridge: 172.26.80.1/20
|
||||
(WLAN, Bluetooth etc.: APIPA 169.254.x.x - nicht konfiguriert/inaktiv)
|
||||
|
||||
### DNS ###
|
||||
Ethernet DNS: 192.168.178.58 (= Kallilabcore AdGuard Home)
|
||||
WLAN DNS: 192.168.178.58
|
||||
|
||||
### TAILSCALE STATUS ###
|
||||
100.78.133.37 baerchen-1 (dieser Rechner) online
|
||||
100.105.203.21 baerchen (alter Rechner) offline, last seen 20h ago
|
||||
100.73.83.55 iphone-14 iOS online
|
||||
100.112.0.90 kallilab-core linux online
|
||||
100.80.98.33 kallilabcore linux active; direct 192.168.178.58:49917
|
||||
|
||||
### LAUSCHENDE TCP-PORTS ###
|
||||
Port Adresse Prozess Bemerkung
|
||||
135 0.0.0.0/:: svchost RPC Endpoint Mapper
|
||||
139 192.168.178.103 System NetBIOS
|
||||
445 :: System SMB
|
||||
3000 ::1/:: wslrelay / docker Docker / WSL lokal
|
||||
5040 0.0.0.0 svchost WS-Discovery (WDAS)
|
||||
5357 :: System WSD HTTP
|
||||
7680 :: svchost WUDO (Delivery Optimization)
|
||||
11434 127.0.0.1 ollama Ollama API (lokal)
|
||||
22885 127.0.0.1 Battle.net lokal
|
||||
26822 127.0.0.1 MSI.TerminalServer MSI Center
|
||||
27036 0.0.0.0 steam Steam Remote Play (0.0.0.0 - offen!)
|
||||
27060 127.0.0.1 steam Steam lokal
|
||||
32683 127.0.0.1 MSI.CentralServer MSI Center
|
||||
33683 127.0.0.1 MSI.CentralServer MSI Center
|
||||
38810 fd7a:... tailscaled
|
||||
49553 100.78.133.37 tailscaled
|
||||
50123 127.0.0.1 iCUE Corsair lokal
|
||||
51037 127.0.0.1 RazerAppEngine
|
||||
55316 127.0.0.1 RazerAppEngine
|
||||
59686 127.0.0.1 steam
|
||||
60999 127.0.0.1 Agent Claude Code
|
||||
|
||||
### SSH ###
|
||||
~\.ssh\config: LEER (keine Host-Eintraege)
|
||||
~\.ssh\id_ed25519: vorhanden (411 Bytes, erstellt 2026-04-04)
|
||||
~\.ssh\id_ed25519.pub: vorhanden (97 Bytes)
|
||||
~\.ssh\known_hosts: vorhanden (4719 Bytes, zuletzt 2026-06-04)
|
||||
~\.ssh\known_hosts.old + .pre-port222-Backup: vorhanden
|
||||
|
||||
KEY PERMISSIONS id_ed25519:
|
||||
NT-AUTORITAET\SYSTEM FullControl Allow
|
||||
VORDEFINIERT\Administratoren FullControl Allow
|
||||
baerchen\michi FullControl Allow
|
||||
BEFUND: Zu viele Berechtigungen - Admins-Gruppe hat FullControl auf Private Key.
|
||||
@@ -1,66 +0,0 @@
|
||||
### DEV TOOLCHAIN ###
|
||||
git: 2.54.0.windows.1
|
||||
python: 3.13.13
|
||||
node: 24.16.0 (LTS)
|
||||
go: 1.26.4 windows/amd64
|
||||
|
||||
### GIT CONFIG ###
|
||||
user.name: michaelkaleschke-spec
|
||||
user.email: michaelkaleschke@googlemail.com
|
||||
commit.gpgsign: nicht gesetzt (Commits nicht signiert)
|
||||
|
||||
### WSL ###
|
||||
Ubuntu Stopped Version 2
|
||||
docker-desktop Running Version 2
|
||||
|
||||
### DOCKER CONTEXTS ###
|
||||
default npipe:////./pipe/docker_engine (nicht aktiv)
|
||||
desktop-linux* npipe:////./pipe/dockerDesktopLinuxEngine (aktiv)
|
||||
|
||||
### KUBECTL ###
|
||||
Keine Contexts konfiguriert.
|
||||
|
||||
### WINGET INVENTAR (158 Pakete, Auswahl) ###
|
||||
CPUID CPU-Z MSI 2.20.1
|
||||
CPUID HWMonitor 1.63
|
||||
CrystalDiskInfo 9.9.1
|
||||
Docker Desktop 4.76.0
|
||||
Git 2.54.0
|
||||
AusweisApp 2.5.1
|
||||
Node.js LTS 24.16.0
|
||||
Corsair iCUE5 5.46.67
|
||||
NVIDIA App 11.0.7.247 / Treiber 610.47
|
||||
WISO Steuer 2026 33.07.3410
|
||||
Go 1.26.4
|
||||
Microsoft Edge 148.0.3967.96
|
||||
Microsoft OneDrive 23.038 (Update verfuegbar: 26.078)
|
||||
RivaTuner Statistics Server 7.3.7
|
||||
Razer Synapse 4.0.683
|
||||
Steam 2.10.91.91
|
||||
Banking4 Home
|
||||
Battle.net / Hearthstone / Overwatch / World of Warcraft
|
||||
Microsoft 365 16.0.20026.20140
|
||||
|
||||
### AUTOSTART ###
|
||||
HKCU\Run:
|
||||
BraveSoftware Update -> BraveUpdateCore.exe
|
||||
Steam -> E:\Steam\steam.exe -silent
|
||||
RazerAppEngine -> Synapse autoStart
|
||||
Docker Desktop -> Docker Desktop.exe
|
||||
|
||||
HKLM\Run:
|
||||
SecurityHealth -> SecurityHealthSystray.exe
|
||||
Corsair iCUE5 -> iCUE Launcher.exe --autorun
|
||||
RtkAudUService -> Realtek Audio Service
|
||||
|
||||
Startup-Ordner (User): Ollama.lnk
|
||||
Startup-Ordner (Alle): Tailscale.lnk
|
||||
|
||||
### GEPLANTE TASKS (nicht-Microsoft, aktiv) ###
|
||||
OneDrive Reporting Task
|
||||
OneDrive Startup Task
|
||||
OneDrive Per-Machine Standalone Update Task
|
||||
PostponeDeviceSetupToast
|
||||
BraveSoftwareUpdateTask (2x User-Varianten)
|
||||
NVIDIA App SelfUpdate
|
||||
SoftLanding\CreativeManagementTask [UNBEKANNT - pruefen]
|
||||
@@ -1,45 +0,0 @@
|
||||
### HARDWARE ###
|
||||
CPU: Intel Core i5-14600KF, 14 Cores / 20 Threads, 3500 MHz Base
|
||||
RAM: 31.79 GB
|
||||
MB: MSI MS-7D32
|
||||
Energieplan: Ausbalanciert (381b4222) - aktiv
|
||||
Verfuegbare Plaene: Ausbalanciert, Ultimative Leistung, Hoechstleistung, Energiesparmodus
|
||||
|
||||
### PHYSICAL DISKS (SMART) ###
|
||||
INTEL SSDSC2BW180A3L SSD Healthy OK (Disk 0, C:)
|
||||
INTEL SSDSC2BW180A3L SSD Healthy OK (Disk 1, D:)
|
||||
Samsung SSD 980 PRO 1TB SSD Healthy OK (Disk 2, E:)
|
||||
WDC WDS100T2B0C SSD Healthy OK (Disk 3, G:)
|
||||
asmedia ASM235 Unspecified Healthy OK (Disk 4, H:)
|
||||
Get-StorageReliabilityCounter: keine Ausgabe (Wear-Daten nicht via WMI verfuegbar - typisch fuer SATA SSDs und USB)
|
||||
|
||||
### GERAETE MIT STATUS "Unknown" (PnP) ###
|
||||
MyBookLiveDuo (SoftwareDevice) - Netzwerkgeraet, nicht angebunden - erwartet
|
||||
HID-Tastatur (Keyboard) - ghosted device - harmlos
|
||||
Dell S2722DGM (DP) (Monitor) - Display-Enumeration Artefakt
|
||||
Generic Monitor x2 - Display-Enumeration Artefakt
|
||||
[LG] webOS TV OLED65G48LW x2 - Netzwerkgeraet, nicht lokal - erwartet
|
||||
Standard-Volumeschattenkopie x3 - VSS Snapshots - erwartet
|
||||
KEINE echten Fehlercodes (kein gelbes Ausrufezeichen).
|
||||
|
||||
### EVENT LOG FEHLER seit Installation (2026-05-10) ###
|
||||
ID 20 (70x): Defender KB4052623 Installation fehlgeschlagen (0x80240016)
|
||||
-> Timing-Problem bei Update-Kaskade, harmlos wenn aktuell
|
||||
ID 10010 (15x): DCOM Server-Timeout {3E11DF0F-...}
|
||||
-> bekanntes Windows-Hintergrundrauschen, harmlos
|
||||
ID 7000 (3x): Steam Client Service Start fehlgeschlagen
|
||||
-> Steam war beim Boot noch nicht bereit, harmlos
|
||||
ID 7023 (3x): Windows Modules Installer beendet mit Fehler
|
||||
-> Update-Installationsabbrueche, pruefbar nach Analyse der Zeitstempel
|
||||
ID 6008 (2x): Unerwartetes Herunterfahren am 2026-05-19 13:56:56
|
||||
-> Einmaliger Vorfall (BSOD oder Stromausfall) kurz nach Installation
|
||||
ID 7034 (2x): MSI Center Service unerwartet beendet
|
||||
-> bekannte Instabilitaet MSI Center, harmlos wenn kein Datenverlust
|
||||
ID 7043 (1x): Dienst konnte nicht gestoppt werden
|
||||
ID 1012 (3x): unbekannte ID - weitere Analyse noetig
|
||||
ID 36 (2x): unbekannte ID - weitere Analyse noetig
|
||||
|
||||
### CRASH DUMPS ###
|
||||
C:\Windows\Minidump: nicht vorhanden
|
||||
C:\Windows\MEMORY.DMP: nicht vorhanden
|
||||
Bewertung: kein BSOD-Dump vorhanden (ggf. Dump-Einstellung "automatisch neu starten" ohne Dump-Schreiben)
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
gitea:
|
||||
image: docker.gitea.com/gitea:1.26.2@sha256:7d13848af12645600a5f9d93ee2560daa9c6fa6b5b859b7bff3a5e1c0b661031
|
||||
image: docker.gitea.com/gitea:1.25.4@sha256:17d18218be2dad1f8ed402a4f906989505c90ab8b66ee9befcecfb5d470133e7
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
|
||||
+198
-38
@@ -1,53 +1,213 @@
|
||||
# AI Context
|
||||
|
||||
Typ: Einstieg/Index · Stand: 2026-06-11 · Status: aktiv
|
||||
Stand: 2026-05-04
|
||||
|
||||
Kurzer Kontext fuer KI-Agenten. Nicht als Ersatz fuer die echten Runbooks lesen.
|
||||
Diese Datei enthaelt bewusst **keinen** Arbeitsstand mehr — Status nur in
|
||||
`docs/MASTER_TODO.md`, Entscheidungen nur in `docs/DECISIONS.md`.
|
||||
Diese Datei ist fuer KI-Agenten gedacht, die das Homelab-Repo schnell verstehen muessen. Sie ersetzt nicht die Detaildokumente, sondern fasst Zielbild, Betriebsmodell und Risiken zusammen.
|
||||
|
||||
## Systembild
|
||||
## Kurzfassung
|
||||
|
||||
- Host: Unraid `Kallilabcore`
|
||||
- Betriebsmodell: GitOps mit Gitea `origin/master` als Sollzustand
|
||||
- Deploy: Komodo zieht aus Gitea und startet Compose-Stacks
|
||||
- Ingress: Traefik; WAN-seitig bewusst nur `443/tcp`
|
||||
- Secrets: nie im Repo, meist unter `/mnt/user/appdata/secrets/`
|
||||
- Backup: Borg plus host-seitige Dumps; Hetzner ist Offsite, H:/ ist lokale Nearline-Kopie
|
||||
Dieses Repository beschreibt ein Unraid-basiertes Homelab namens `Kallilabcore`. Der Betrieb folgt GitOps: Gitea `origin/master` ist die Quelle der Wahrheit, der lokale Clone ist Arbeitskopie, Komodo deployed aus Gitea, Docker Runtime und Host sind Ergebnis, nicht Bearbeitungsort.
|
||||
|
||||
## Vor jeder Aenderung lesen
|
||||
Traefik ist der zentrale Web-Einstieg fuer HTTP(S). Admin-/Ops-UIs liegen entweder hinter Authelia/secure headers oder sind als Ausnahme dokumentiert. Secrets liegen ausserhalb des Repos auf dem Host, meistens unter `/mnt/user/appdata/secrets/`.
|
||||
|
||||
1. `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
2. `docs/WORKFLOW.md`
|
||||
3. betroffene Compose-Datei
|
||||
4. bei Service-Fragen `docs/SERVICE_CATALOG.md`
|
||||
5. bei Restore/DR `docs/DISASTER_RECOVERY.md` und `docs/RESTORE_MATRIX.md`
|
||||
6. bei "warum ist das so?"-Fragen `docs/DECISIONS.md`
|
||||
## Zielbild des Homelabs
|
||||
|
||||
## Harte Regeln
|
||||
- stabile Compose-first Infrastruktur
|
||||
- keine produktiven Dockerman-/Ad-hoc-Container als Dauerzustand
|
||||
- Traefik als einziger oeffentlicher Web-Eingang
|
||||
- GitOps ueber Gitea + Komodo
|
||||
- klare Trennung von Web-Netz, Backend-Netz und app-internen Netzen
|
||||
- saubere Backup-/Restore-Faehigkeit ueber Borg, Dumps und dokumentierte Pfade
|
||||
- keine stillen Host-Hotfixes ohne Repo-/Doku-Abgleich
|
||||
|
||||
## Architekturblocke
|
||||
|
||||
### Ingress / Netzwerk
|
||||
|
||||
- `traefik` nimmt 80/443 entgegen.
|
||||
- Docker-Labels definieren Service-Routing.
|
||||
- `traefik/dynamic/*` bleibt nur fuer Middlewares, TLS und Dashboards.
|
||||
- Neue Service-Routen gehoeren nicht in den File-Provider.
|
||||
|
||||
### DNS / Remote
|
||||
|
||||
- AdGuard Home beantwortet LAN-DNS und nutzt Unbound als Upstream.
|
||||
- Tailscale stellt Remote-Zugang bereit und nutzt `network_mode: host`.
|
||||
|
||||
### GitOps
|
||||
|
||||
- Gitea hostet das Repo unter `git.kaleschke.info`.
|
||||
- Komodo ist Stack-Manager und Deploy-Consumer.
|
||||
- Komodo Periphery braucht Docker-Socket und `/mnt/user/services` Mount, um Stacks reproduzierbar zu deployen.
|
||||
- Neue produktive Komodo-Stacks aus `Micha/homelab-infra` muessen einen aktiven Gitea->Komodo-Webhook auf die aktuelle Stack-ID haben; Ausnahmen wie deaktivierte/pausierte Stacks muessen dokumentiert werden.
|
||||
- Der `komodo`-Self-Stack ist eine dokumentierte Ausnahme ohne aktiven Gitea-Webhook; Bootstrap/Recovery laeuft ueber `docs/SERVICES_RECOVERY.md`.
|
||||
|
||||
### Identity / Security
|
||||
|
||||
- Authelia stellt ForwardAuth fuer viele Admin-UIs bereit.
|
||||
- Authelia nutzt GMX SMTP fuer Identity-/2FA-Benachrichtigungen; Passwort liegt als Host-Secret `authelia_smtp_password.txt`.
|
||||
- Vaultwarden ist ein separater Passwort-Tresor.
|
||||
- Komodo ist bewusst nicht pauschal hinter Authelia, weil UI, API, Webhooks und Periphery-WebSocket sonst leicht gebrochen werden koennen.
|
||||
- Komodo-Compose, Komodo-Secrets und Komodo-Runtime nur gemeinsam mit dem Betreiber aendern; `KOMODO_WEBHOOK_SECRET` ist bewusst getrennt von `KOMODO_SECRET_KEY`. Gitea-Webhooks nicht pauschal vereinheitlichen: einzelne Komodo-Stacks koennen eigene per-Stack-Webhook-Secrets haben.
|
||||
|
||||
### Apps
|
||||
|
||||
Wichtige Apps sind Paperless, Immich, Mealie, Mail Archiver, Nextcloud, ntfy, Vaultwarden und Gitea. Admin-/Ops-Tools sind u. a. Glance, Komodo, Borg UI, Filebrowser, code-server, Glances, Scrutiny, Speedtest, Monitoring Grafana und Hermes Agent.
|
||||
|
||||
### Hermes Agent — Architektur und Ops-Monitor
|
||||
|
||||
Hermes laeuft nach Model C (siehe `ops/hermes-agent/README.md`):
|
||||
|
||||
- `hermes-gateway` als Docker-Container auf dem Unraid-Host, intern auf `hermes_net:8642`
|
||||
- Terminal-Befehle werden via SSH auf eine dedizierte Linux-VM ausgefuehrt
|
||||
- VM-IP: `192.168.178.143`, SSH-User: `hermes`
|
||||
- Repo-Clone auf der VM: `/srv/hermes-workspace/homelab-infra/`
|
||||
|
||||
**Fuer KI-Agenten wichtig:** Das Hermes-Terminal laeuft auf der VM, nicht auf dem Unraid-Host.
|
||||
`/mnt/user/...`-Pfade sind von der VM aus nicht direkt erreichbar.
|
||||
Docker-CLI ist auf der VM nicht installiert — fuer Homelab-Checks wird `check_health.py` verwendet.
|
||||
|
||||
**Ops-Monitor (homelab-ops-monitor):**
|
||||
|
||||
- Skill: `ops/hermes-agent/skills/homelab-ops-monitor.md`
|
||||
- Script: `ops/hermes-agent/scripts/check_health.py` — prueft Services via HTTP, keine externen Deps
|
||||
- Wissensbasis: `ops/hermes-agent/services.json` — maschinenlesbare Ableitung aus `docs/SERVICE_CATALOG.md`
|
||||
- Check-Strategie: HTTP GET fuer URL-basierte Services, interne Services (DBs, Redis) als `"internal"` markiert
|
||||
- ntfy-Topic fuer Alerts: `homelab-alerts` auf `https://ntfy.kaleschke.info`
|
||||
|
||||
Nach Aenderungen an `services.json` oder `check_health.py`: `git pull` auf der VM ausfuehren.
|
||||
- Mail Archiver ist ein Hybrid-Dienst mit `frontend_net` fuer IMAP/Traefik und `backend_net` fuer PostgreSQL; die Web-UI liegt hinter Authelia und behaelt zusaetzlich App-eigene Auth.
|
||||
|
||||
### Monitoring / Metriken
|
||||
|
||||
- Zielzustand ist ein zentraler Stack `monitoring/` unter `https://monitoring.kaleschke.info`.
|
||||
- `monitoring-grafana` ist die zentrale UI fuer Prometheus, Loki und InfluxDB 3 Core.
|
||||
- `monitoring-prometheus` sammelt Infrastruktur-Metriken; `monitoring-loki` + `monitoring-promtail` sammeln Docker-Logs.
|
||||
- `monitoring-influxdb3-core` ist nicht public und nicht im `frontend_net`.
|
||||
- Home Assistant schreibt ueber LAN-only Port 8181 nach InfluxDB, gebunden ueber `INFLUXDB_BIND_IP`.
|
||||
- Ein `401 Unauthorized` von InfluxDB ohne Token ist beim Reachability-Test ein Erfolgssignal.
|
||||
- Die frueheren Altstaende `ops/loki` und `ops/grafana-influxdb` wurden aus dem aktiven Repo entfernt; fuer Monitoring immer `monitoring/` verwenden, Rollback nur ueber Git-Historie.
|
||||
- Uptime Kuma ist entfernt; HTTP-Verfuegbarkeit laeuft ueber Blackbox Exporter, Prometheus-Alerts und `Homelab / Availability` in Monitoring Grafana.
|
||||
|
||||
## Deployment-Logik
|
||||
|
||||
Normalfall:
|
||||
|
||||
1. lokaler Clone synchronisieren
|
||||
2. betroffene Dokumente und Compose-Datei lesen
|
||||
3. minimal aendern
|
||||
4. lokal validieren
|
||||
5. committen und pushen
|
||||
6. Komodo-Webhook / Deploy beobachten
|
||||
7. Runtime testen
|
||||
8. Doku aktualisieren
|
||||
|
||||
Wichtig: Komodo-Web-Editor ist nicht der Bearbeitungsort. Wenn Komodo und Git voneinander abweichen, zuerst Git und Komodo Workspace pruefen, nicht live herumprobieren.
|
||||
|
||||
Beim Anlegen neuer produktiver Stacks ist der Gitea->Komodo-Webhook Pflicht. Nach dem Anlegen muss ein Test-Push oder Test-Delivery zeigen, dass Gitea die aktuelle Komodo-Stack-ID erreicht.
|
||||
|
||||
## Netzwerkmodell
|
||||
|
||||
| Netzwerk | Bedeutung |
|
||||
|---|---|
|
||||
| `frontend_net` | Web-/Proxy-Netz fuer Traefik-geroutete Dienste und Dienste mit Internetbedarf |
|
||||
| `backend_net` | internes Netz fuer shared PostgreSQL, Redis und Backends |
|
||||
| `dns_net` | AdGuard + Unbound |
|
||||
| app-interne Netze | Isolation von App + DB/Cache, z. B. Immich, Mealie, Nextcloud, Monitoring |
|
||||
| `host` | nur dokumentierte Sonderfaelle wie Tailscale/Plex |
|
||||
|
||||
Regeln:
|
||||
|
||||
- Keine Secrets zitieren oder ins Repo schreiben.
|
||||
- Keine produktiven Host-Hotfixes ohne Repo-Abgleich.
|
||||
- Datenbanken nie ins `frontend_net`.
|
||||
- Direkte Host-Ports sind Ausnahme.
|
||||
- Traefik dynamic config und Authelia Host-Config sind manuelle Sync-Ausnahmen.
|
||||
- Bei Drift zuerst Git, Gitea, Komodo Workspace, Docker Runtime und Host getrennt pruefen.
|
||||
- Nach zwei fehlgeschlagenen Reparaturversuchen stoppen und `docs/GITOPS_DRIFT_RUNBOOK.md` nutzen.
|
||||
- Doku-Regel: ein Fakt hat genau ein Zuhause; verlinken statt kopieren (`docs/REPO_MAP.md`).
|
||||
- Admin-UIs nur mit Traefik + Middleware oder dokumentierter Ausnahme.
|
||||
- Direkte Host-Ports sind Ausnahme, nicht Default.
|
||||
- Runtime-Netznamen koennen Compose-Projektpraefixe bekommen, z. B. `monitoring_monitoring_influx_lan`.
|
||||
|
||||
## Bekannte Ausnahmen
|
||||
## Security-Modell
|
||||
|
||||
Autoritativ: `HOMELAB_ARCHITECTURE_MASTER_V2.md` §10. Kurzliste:
|
||||
- Secrets nie ins Git.
|
||||
- Werte niemals zitieren, auch nicht aus `.env`, Stack ENV, Logs oder Screenshots.
|
||||
- Secret-Dateien bevorzugt unter `/mnt/user/appdata/secrets/`.
|
||||
- `_FILE`-Varianten bevorzugen, falls Image sie unterstuetzt.
|
||||
- Wenn `_FILE` nicht unterstuetzt wird, Komodo Stack Environment Variables verwenden.
|
||||
- Docker-Socket, `privileged: true`, Host-Netz und breite Mounts sind nur mit dokumentierter Begruendung akzeptabel.
|
||||
|
||||
- Traefik: Host-Ports 80/443, WAN-Freigabe nur 443
|
||||
- Gitea: SSH auf Host-Port 222, keine WAN-Freigabe
|
||||
- AdGuard: DNS 53 direkt; Admin nur auf Tailscale-IP `100.80.98.33:8082`
|
||||
- Tailscale: natives Unraid-Plugin (nicht repo-verwaltet); Plex: Host-Netz
|
||||
- Scrutiny: privileged; Komodo/Periphery: Docker-Socket
|
||||
- InfluxDB 3 Core: `127.0.0.1:8181`, Root-User-Ausnahme dokumentiert
|
||||
Bekannte Ausnahmen:
|
||||
|
||||
## Arbeitsstand
|
||||
- Traefik: 80/443
|
||||
- Gitea: SSH 222
|
||||
- AdGuard: DNS 53 direkt; Admin 8082 ist bewusst ohne Traefik/2FA, aber auf Tailscale-IP `100.80.98.33` begrenzt
|
||||
- Tailscale: Host-Netz, `NET_ADMIN`, `NET_RAW`, `/dev/net/tun`
|
||||
- Scrutiny: privileged
|
||||
- Komodo: Docker-Socket, native Auth
|
||||
- InfluxDB: LAN-only 8181 fuer Home Assistant Writer
|
||||
- `monitoring-influxdb3-core`: `user: "0"` als dokumentierte Host-Appdata-Permissions-Ausnahme
|
||||
- Traefik dynamic config: manueller Host-Sync
|
||||
|
||||
- Offene Punkte: `docs/MASTER_TODO.md` (einzige Statusliste)
|
||||
- Entscheidungen und Begruendungen: `docs/DECISIONS.md`
|
||||
- Belege/Reports: `/mnt/user/backups/restore-reports/` auf dem Host
|
||||
## Backup- und Restore-Modell
|
||||
|
||||
Borg sichert kritische Appdaten, Secrets, Traefik-State und Dump-Artefakte. Datenbank-Restore soll bevorzugt ueber Dumps laufen, nicht ueber rohe Live-DB-Verzeichnisse.
|
||||
|
||||
Wichtige Pfade:
|
||||
|
||||
- `/mnt/user/appdata`
|
||||
- `/mnt/user/appdata/secrets`
|
||||
- `/mnt/user/services`
|
||||
- `/mnt/user/documents`
|
||||
- `/mnt/user/photos`
|
||||
- `/mnt/user/backups/borg/dumps/latest`
|
||||
|
||||
Dump-Skript:
|
||||
|
||||
- `ops/borg-ui/scripts/pre-backup-dumps.sh`
|
||||
- soll auf dem Unraid Host laufen
|
||||
- soll nicht als Borg-UI Inline-Hook behandelt werden, solange die Architektur nicht bewusst geaendert wird
|
||||
|
||||
Disaster Recovery folgt einer Bootstrap-Reihenfolge:
|
||||
|
||||
1. Traefik, AdGuard, Tailscale
|
||||
2. PostgreSQL, Authelia, Redis, Gitea
|
||||
3. Komodo
|
||||
4. kritische Apps
|
||||
5. restliche Apps/Ops inklusive Hermes Agent
|
||||
|
||||
## Typische Arbeitsweise im Repo
|
||||
|
||||
- Fuer Fragen zuerst `HOMELAB_ARCHITECTURE_MASTER_V2.md` lesen.
|
||||
- Fuer operative Aenderungen `docs/WORKFLOW.md` lesen.
|
||||
- Fuer Service-Details `docs/SERVICE_CATALOG.md` und die Compose-Datei lesen.
|
||||
- Fuer Drift `docs/GITOPS_DRIFT_RUNBOOK.md` nutzen.
|
||||
- Fuer Rollback `docs/ROLLBACK.md` nutzen.
|
||||
- Fuer Restore `docs/DISASTER_RECOVERY.md` und `docs/RESTORE_MATRIX.md` nutzen.
|
||||
|
||||
KI-Agenten sollen konservativ arbeiten: keine indirekten Live-Aenderungen, keine Deployments, keine Commits, keine Host-Schreibbefehle, wenn der Benutzer nur Analyse oder Doku verlangt.
|
||||
|
||||
## Bekannte Risiken und Altlasten
|
||||
|
||||
- Traefik dynamic config muss manuell auf den Host synchronisiert werden; Komodo deployed diese Dateien nicht automatisch.
|
||||
- `backend_net` und app-interne Netze muessen bei Runtime-Problemen live geprueft werden, weil Compose-Projektpraefixe Netznamen veraendern koennen.
|
||||
- Authelia `configuration.yml` ist Repo-Baseline fuer nicht geheime Einstellungen, wird aber nicht automatisch von Komodo auf den Host kopiert; die produktive Host-Datei kann OIDC-/Secret-Konfiguration enthalten. Bei Auth-Aenderungen Repo-Baseline, Host-Config und Compose-Middlewares pruefen und nicht blind ueberschreiben.
|
||||
- Authelia nutzt PostgreSQL, aber bewusst kein Redis-Session-Backend; Redis ist kein Authelia-Bootstrap-Blocker.
|
||||
- Authelia-Notifier ist SMTP; bei Auth-Aenderungen Host-Config backupen, `authelia validate-config` ausfuehren und erst danach neu starten.
|
||||
- `paperless-ngx` nutzt fuer DB/Redis bewusst Stack ENV statt `_FILE`.
|
||||
- `glance-docker-socket-proxy`, `glances` und `komodo-periphery` nutzen Docker-/Socket-Zugriff; Zugriff bewusst behandeln.
|
||||
- `borg-ui` und `filebrowser` haben breite Mounts; bei Hardening nicht ad hoc, sondern gezielt vorgehen.
|
||||
- `scrutiny` ist privilegiert und hat Device-Mounts.
|
||||
- `Plex-Media-Server` ist im Architekturziel als Host-Sonderfall dokumentiert, aber nicht als Repo-Compose-Stack enthalten.
|
||||
- Echte `stack.env`- und `.env`-Dateien gehoeren nicht ins Repo; fuer Hermes liegt nur `ops/hermes-agent/stack.env.example` im Git.
|
||||
- Einige Images nutzen mutable Tag plus Digest. Das friert den aktuellen Digest ein, ist aber kein automatisches Upgrade-Modell.
|
||||
- Stateful Images werden bevorzugt als Minor-/Patch-Tag plus Digest gepinnt; Redis-Caches bleiben bewusst ungedigestet.
|
||||
|
||||
## Arbeitsregel bei Unsicherheit
|
||||
|
||||
Nicht raten. Erst diese Reihenfolge:
|
||||
|
||||
1. Repo-Doku lesen
|
||||
2. Compose-Datei lesen
|
||||
3. Git-Stand pruefen
|
||||
4. Komodo Workspace pruefen
|
||||
5. Docker Runtime pruefen
|
||||
6. Host-Listener / echten Request pruefen
|
||||
7. genau eine abweichende Ebene benennen
|
||||
|
||||
Wenn zwei Reparaturversuche scheitern: keine weiteren Schreibbefehle, Pflichtmatrix aus `docs/GITOPS_DRIFT_RUNBOOK.md` ausfuellen.
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
# AI Handoff 2026-05-06
|
||||
|
||||
Kompakte Quelle fuer einen neuen Chat. Ziel: nicht das ganze Repo neu auditieren, sondern mit dem bekannten Stand weiterarbeiten.
|
||||
|
||||
## Aktueller Stand
|
||||
|
||||
- Repo: `G:\Gitea_Clone\homelab-infra`
|
||||
- Remote: `https://git.kaleschke.info/Micha/homelab-infra.git`
|
||||
- Branch: `master`
|
||||
- Letzter bekannter Commit: `e0e12f1 Document stale Komodo webhook cleanup`
|
||||
- Unraid-Host: `ssh root@192.168.178.58`
|
||||
- Push-Befehl, der zuverlaessig funktioniert: `git -C "G:\Gitea_Clone\homelab-infra" push origin master`
|
||||
- Nicht anfassen ohne explizite Freigabe: untracked `Homelab_Audit_2026-05-05.pdf` und untracked `ops/hermes-agent/services.yaml`.
|
||||
|
||||
## Audit-Arbeit Erledigt
|
||||
|
||||
- K1: ungueltige Digests fuer Authelia, ntfy und borg-ui korrigiert und smoke-getestet.
|
||||
- K2: Authelia nutzt bewusst kein Redis; Doku entsprechend korrigiert.
|
||||
- K3/M1/M2 alt: Authelia Repo-Baseline geklaert, Homepage/Komodo ACL-Drift bereinigt.
|
||||
- M3a/M3b: Digest-Pinning fuer stateful/Tier-1 und weitere versionierte Apps umgesetzt; Redis-Caches bewusst ohne Digest, Nextcloud bewusst offen.
|
||||
- M5/N5: `.gitignore` eingefuehrt, Hermes `stack.env` zu `stack.env.example`.
|
||||
- M6/M7/M8: Hermes-Domain, Grafana/Influx `user: "0"` und Tailscale-Capabilities dokumentiert.
|
||||
- M9: Backup Scope / Restore Matrix erledigt.
|
||||
- N-Aufraeumen: alte Compose-`version:` Felder, leere Env-Beispiele und `.keep`-Platzhalter bereinigt.
|
||||
- Mail Archiver: `mail.kaleschke.info` liegt hinter `authelia@file,secure-headers@file`; Smoke-Test war 302 zu Authelia.
|
||||
- Hermes: Restore/DR-Doku ergaenzt.
|
||||
- Authelia SMTP: GMX SMTP eingerichtet, validiert, deployed und smoke-getestet.
|
||||
- M10: `KOMODO_WEBHOOK_SECRET` ist von `KOMODO_SECRET_KEY` getrennt.
|
||||
|
||||
## Wichtige Runtime-Details
|
||||
|
||||
### Authelia SMTP
|
||||
|
||||
- Adresse: `submission://mail.gmx.net:587`
|
||||
- Mailkonto: `michideheld@gmx.de`
|
||||
- SMTP-Passwort liegt nur auf dem Host: `/mnt/user/appdata/secrets/authelia_smtp_password.txt`
|
||||
- Host-Config wurde vor Umstellung gesichert: `/mnt/user/appdata/authelia/config/configuration.yml.bak-20260506-smtp`
|
||||
- Authelia-Compose nutzt explizite DNS-Server, weil der SMTP-Startup-Check externe Namen aufloesen muss.
|
||||
- Nach Deploy war `authelia` healthy; `auth.kaleschke.info` antwortete 200, geschuetzte Routen 302 zu Authelia.
|
||||
|
||||
### Komodo / M10
|
||||
|
||||
- Komodo-Runtime nur gemeinsam mit dem Betreiber aendern.
|
||||
- `KOMODO_SECRET_KEY` wurde nicht geaendert.
|
||||
- `KOMODO_WEBHOOK_SECRET` wurde geaendert und ist jetzt eigener 64-Zeichen-Wert.
|
||||
- Neuer Wert liegt nur auf dem Host in `/mnt/user/services/stacks/komodo/.env`.
|
||||
- Komodo Compose auf Host: `/mnt/user/services/stacks/komodo/compose.yaml`.
|
||||
- Backups vom M10-Sprint:
|
||||
- `/mnt/user/appdata/komodo/_m10_backup_20260506-184838`
|
||||
- `/mnt/user/services/gitea/data/gitea/_m10_backup_20260506-184838/gitea.db.bak`
|
||||
- `komodo-core` wurde gezielt recreated.
|
||||
- `komodo-mongo` wurde nicht neu gestartet.
|
||||
- `komodo-periphery` lief durch und meldete sich wieder am Core-Websocket an.
|
||||
- Gitea-Komodo-Webhooks: 29 aktive Hooks, 29 zuletzt erfolgreich, 0 aktiv fehlgeschlagen.
|
||||
- Ein stale Gitea-Webhook auf eine nicht mehr existierende Komodo-Stack-ID wurde deaktiviert, nicht geloescht.
|
||||
- Eine Warnung `request branch does not match expected` ist ein Branch-Filter-Skip, kein Secret-/Auth-Fehler.
|
||||
- Fuer neue Gitea-Webhooks im Standardfall den globalen `KOMODO_WEBHOOK_SECRET` aus der Komodo-Host-`.env` nutzen, ausser Komodo zeigt fuer den Stack explizit ein eigenes per-Stack-Secret.
|
||||
|
||||
## Sicherheitsregeln Fuer Weitere Arbeit
|
||||
|
||||
- Keine Secret-Werte im Chat oder Git ausgeben.
|
||||
- Bei Host-Pruefungen nur SET/MISSING, Laengen und Pfade zeigen.
|
||||
- Komodo-Compose, Komodo-Secrets und Komodo-Runtime nur bewusst und kleinschrittig aendern.
|
||||
- Bei jedem Deploy pro Stack smoke-testen; nicht mehrere kritische Stacks parallel veraendern.
|
||||
- Untracked Dateien nicht automatisch committen.
|
||||
- Bei Authelia-Aenderungen: Host-Config sichern, `authelia validate-config` ausfuehren, dann erst neu starten.
|
||||
- Bei Komodo-Aenderungen: Gitea-Webhooks und Komodo-Core-Secret-Seite zusammen betrachten.
|
||||
|
||||
## Naechste Sinnvolle Next-Level-Themen
|
||||
|
||||
- Grafana/Influx rootless betreiben statt `user: "0"`; eigener Sprint wegen Volume-Rechten.
|
||||
- Restore-Test fuer Vaultwarden und Paperless dokumentiert durchfuehren.
|
||||
- Komodo Periphery von Legacy-Passkey auf Public-Key-Modell haerten.
|
||||
- Monitoring/Alerting reifer machen: externe Alarme, Restore-Test-Reminder, Backup-Erfolg sichtbar.
|
||||
- Gitea/Komodo Webhook-Landschaft weiter aufraeumen und per-Stack-Secret-Strategie dokumentieren.
|
||||
- DR-Test fuer `backend_net`/externe Docker-Netze explizit aufnehmen.
|
||||
|
||||
## Startprompt Fuer Neuen Chat
|
||||
|
||||
Bitte zuerst `docs/AI_HANDOFF_2026-05-06.md` lesen und als aktuelle Arbeitsquelle verwenden. Nicht das ganze Repo neu auditieren, ausser ich fordere es an. Beachte besonders: Komodo nur gemeinsam und kleinschrittig aendern, keine Secret-Werte ausgeben, untracked PDF und `ops/hermes-agent/services.yaml` nicht anfassen. Wir starten jetzt mit Next-Level-Hardening.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Alerting Map
|
||||
|
||||
Stand: 2026-05-23
|
||||
|
||||
Ziel: Alle problemrelevanten Homelab-Meldungen landen auf einem Handy-Topic.
|
||||
|
||||
## ntfy Topics
|
||||
|
||||
| Topic | Zweck |
|
||||
|---|---|
|
||||
| `homelab-alerts` | Alles, was Aufmerksamkeit braucht: Prometheus, Docker-Events, Posture, Zertifikate/Token, Compose-Drift, Borg-Pre-Hook-Fehler und Restore-Fehler |
|
||||
| `homelab-info` | Optionale Erfolgsmeldungen, z. B. erfolgreiche Restore-Testlaeufe |
|
||||
|
||||
## Sender
|
||||
|
||||
| Sender | Pfad | Problem-Topic | Hinweis |
|
||||
|---|---|---|---|
|
||||
| Prometheus / Alertmanager | `monitoring/alertmanager/alertmanager.yml`, `monitoring/alertmanager-ntfy-bridge/bridge.py` | `homelab-alerts` | Zentrale Monitoring-Alerts via Bridge |
|
||||
| Posture Check | `services/posture-check/posture-check.sh` | `homelab-alerts` | Warning und Critical gehen auf dasselbe Handy-Topic |
|
||||
| Cert / Token Check | `services/posture-check/cert-token-check.sh` | `homelab-alerts` | Prueft produktive HTTPS-Domains und Cloudflare Token |
|
||||
| Compose Runtime Drift | `services/posture-check/compose-runtime-drift.sh` | `homelab-alerts` | Meldet Abweichungen zwischen Repo-Compose und Runtime-Image |
|
||||
| Docker Critical Events | `services/posture-check/docker-critical-events.sh` | `homelab-alerts` | Meldet Docker `die`, `oom` und `kill` Events |
|
||||
| Borg Pre-Hook | `ops/borg-ui/scripts/pre-borg.sh` | `homelab-alerts` | Meldet Fehler vor Borg, z. B. Posture-, Dump- oder Restore-Freshness-Fehler |
|
||||
| Restore Jobs | `ops/restore-tests/run-restore-job-with-ntfy.sh` | `homelab-alerts` | Erfolg geht an `homelab-info`, Fehler immer an `homelab-alerts` |
|
||||
|
||||
## Konvention
|
||||
|
||||
- `NTFY_BASE_URL` zeigt standardmaessig auf `https://ntfy.kaleschke.info`.
|
||||
- Neue Problem-Alerts sollen `homelab-alerts` nutzen.
|
||||
- Erfolgsmeldungen sind optional und sollen nicht in `homelab-alerts` landen, ausser sie sind bewusst als Lebenszeichen gewuenscht.
|
||||
- Blackbox-Endpoint-Alerts sollen bekannte WAN-/Provider-Sammelausfaelle zusammenfassen, damit kurze DSL-Reconnects keine ntfy-Flut pro Domain erzeugen.
|
||||
@@ -1,54 +0,0 @@
|
||||
# Alert Rules
|
||||
|
||||
Stand: 2026-06-05
|
||||
|
||||
Diese Datei beschreibt die produktiven Alarmwege und wichtigsten Regeln. Die
|
||||
Konfiguration selbst liegt in `monitoring/prometheus/alerts.yml` und in den
|
||||
Skripten unter `services/posture-check/`.
|
||||
|
||||
## Alarmwege
|
||||
|
||||
| Weg | Quelle | Ziel |
|
||||
|---|---|---|
|
||||
| Prometheus / Alertmanager | `monitoring/prometheus/alerts.yml` | ntfy `homelab-alerts` |
|
||||
| Posture Check | `services/posture-check/posture-check.sh` | ntfy `homelab-alerts` |
|
||||
| Cert / Token Check | `services/posture-check/cert-token-check.sh` | ntfy `homelab-alerts` |
|
||||
| Compose Runtime Drift | `services/posture-check/compose-runtime-drift.sh` | ntfy `homelab-alerts` |
|
||||
| Docker Critical Events | `services/posture-check/docker-critical-events.sh` | ntfy `homelab-alerts` |
|
||||
| Borg Pre-Hook | `ops/borg-ui/scripts/pre-borg.sh` | ntfy `homelab-alerts` |
|
||||
| Restore Jobs | `ops/restore-tests/run-restore-job-with-ntfy.sh` | Fehler `homelab-alerts`, Erfolg `homelab-info` |
|
||||
|
||||
## Prometheus-Regeln
|
||||
|
||||
| Alarm | Ausloeser | Severity | Aktion |
|
||||
|---|---|---|---|
|
||||
| `HomelabExternalConnectivityDown` | mindestens 5 HTTP-Ziele down | warning | WAN/DNS/Provider pruefen, nicht jede Domain einzeln jagen |
|
||||
| `HomelabEndpointDown` | einzelnes HTTP-Ziel down | critical | Dienst, Traefik-Route und Backend pruefen |
|
||||
| `HomelabEndpointSlow` | Endpoint >5s | warning | Dienstlast oder Backend-Latenz pruefen |
|
||||
| `HomelabCertificateExpiresSoon` | Cert <21 Tage | warning | ACME/Traefik-Renewal beobachten |
|
||||
| `HomelabCertificateExpiresCritical` | Cert <=7 Tage | critical | Renewal sofort pruefen |
|
||||
| `HomelabDiskAlmostFull` | Filesystem >85% | warning | Platz schaffen oder Schwelle pruefen |
|
||||
| `HomelabDiskCritical` | Filesystem >95% | critical | Sofort Platz schaffen |
|
||||
| `HomelabHighMemoryUsage` | MemAvailable <10% | warning | Speicherfresser identifizieren |
|
||||
| `HomelabTraefik5xx` | >=5 5xx je Service in 5 Minuten | warning | betroffenes Backend pruefen |
|
||||
| `HomelabTextfileExporterStale` | Textfile-Exporter >2h alt | warning | Host-Cron pruefen |
|
||||
| `HomelabBorgMetricsMissing` | Borg-Metrik fehlt | critical | Textfile-Exporter oder Borg-UI pruefen |
|
||||
| `HomelabBorgBackupStale` | letztes Borg-Backup >30h | warning | Backup-Lauf nachholen/pruefen |
|
||||
| `HomelabBorgLastJobFailed` | letzter Borg-Job fehlgeschlagen | critical | Borg-UI-Job-Log pruefen |
|
||||
| `HomelabBorgLastJobCompletedWithWarnings` | letzter Borg-Job mit Warnungen | warning | Warnung im Borg-UI-Job lesen |
|
||||
| `HomelabCriticalContainerDown` | kritischer Container fehlt | critical | Komodo/Docker-Status pruefen |
|
||||
| `HomelabPrometheusTargetDown` | Scrape-Ziel down | critical | node-exporter/cadvisor/blackbox/traefik pruefen |
|
||||
|
||||
Die Liste der ueberwachten Critical-Container steht in
|
||||
`services/posture-check/export-prometheus-textfile.sh`.
|
||||
|
||||
## Bekannte Luecken
|
||||
|
||||
- Kein externer Dead-Man's-Switch fuer Prometheus/ntfy-Bridge. Optional spaeter
|
||||
ueber Uptime-Kuma Push-Monitor oder Healthchecks.io.
|
||||
- Kein Inode-Alarm. Bei Paperless/Immich spaeter sinnvoll, aber aktuell kein
|
||||
dokumentierter Vorfall.
|
||||
- Container-Memory-Limits werden erst nach realen Peak-Daten gesetzt; OOM/kill
|
||||
wird ueber `docker-critical-events.sh` gemeldet, sobald der Host-Watcher per
|
||||
Unraid User Script aktiviert ist. Start/Stop/Status/Smoke laufen ueber
|
||||
`services/posture-check/docker-critical-events-supervisor.sh`.
|
||||
@@ -0,0 +1,369 @@
|
||||
# Homelab Audit - 2026-05-23
|
||||
|
||||
Stand: 2026-05-23, repo-basiert. Erstellt nach `docs/WORKFLOW.md` und `docs/GITOPS_DRIFT_RUNBOOK.md`. Quellebasis: `origin/master` plus lokaler Clone, ohne Schreibbefehle, ohne Deploy.
|
||||
|
||||
Dieser Audit ist eine punktuelle Sollzustands-Bewertung, kein Live-Status. Die Live-Verifikations-Schritte stehen am Ende in Abschnitt 9; alle dortigen Outputs ersetzen Vermutungen durch Messwerte.
|
||||
|
||||
## 0. Executive Summary
|
||||
|
||||
Ampel-Bewertung pro Bereich:
|
||||
|
||||
| Bereich | Ampel | Kernaussage |
|
||||
|---|---|---|
|
||||
| GitOps-Konsistenz (lokal/Gitea) | 🟡 | Lokaler Clone ist **1 Commit voraus** auf `master` (`cd650b1`, Haertungs-Commit). Bis zum Push existiert dieser Stand nur lokal, nicht in Gitea — bei einem Clone-Verlust ist er weg. |
|
||||
| GitOps-Konsistenz (Working Tree) | 🟢* | Keine echten Inhaltsaenderungen offen. Die 47 "modified files" aus `git status` im Linux-Mount sind voraussichtlich CRLF/LF-Mount-Artefakte (durch `git diff -w --stat` auf Stichprobe bestaetigt leer). Bitte am Windows-Host gegenpruefen. |
|
||||
| Hardening-Sprint (Mai 2026) | 🟢 | Alle vier Post-Restore-Sprint-Items sind im Repo umgesetzt (Filebrowser-Mounts, Authelia Argon2id, Gitea Webhook-Allowlist, Backup-Dump-Konsistenz). |
|
||||
| Backup/Restore-Readiness | 🟢 | `pre-backup-dumps.sh` deckt alle relevanten SQLite/PostgreSQL/Mongo-Quellen ab. Borg-UI-Scope umfasst `/mnt/user/services`, `homelab-infra`, `stacks`, `posture-check`. Live-Frische ist offen (Abschnitt 9). |
|
||||
| Monitoring-Migration | 🟡 | `monitoring/` Stack im Repo komplett, aber Live-Deploy laut `docs/NEXT_SPRINT_TODO_2026-05-16.md` noch ausstehend. Alte Stacks `ops/grafana-influxdb` und `ops/loki` sollen erst nach Live-Smoke-Test gestoppt werden. |
|
||||
| Doku-Drift Repo vs. Master-Doku | 🟠 | `apps/jellyfin/`, `host-services/plex/` und einige andere existieren produktiv als Compose-Stacks, sind aber in `HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/SERVICE_CATALOG.md` und `docs/REPO_MAP.md` **nicht aufgefuehrt**. Authelia-ACL kennt `jellyfin.kaleschke.info` als bypass, im Masterdoku-Hostkatalog steht es nicht. |
|
||||
| Repo-Hygiene | 🟡 | 8 leere Verzeichnisse im Working Tree (siehe 4.3). `.serena/` ist untracked und nicht in `.gitignore`. Drei `ops/windows-reinstall/*.ps1` sind untracked. |
|
||||
| Bekannte Ausnahmen | 🟢 | Alle Ausnahmen aus `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 10 sind weiterhin dokumentiert und durch den Policy-Check abgedeckt (0 Critical, 4 Warnings, 9 Info – alles dokumentierte Ausnahmen). |
|
||||
|
||||
**Kernfazit:** Das Homelab ist sehr nah an der "Endstufe". Es gibt keine kritischen Befunde. Die einzige Pflichtaktion vor dem naechsten geplanten Schritt ist der **Push des lokalen Commits `cd650b1` nach Gitea**, damit `origin/master` wieder die Quelle der Wahrheit ist. Danach sind nur noch zwei priorisierte Pakete offen: Monitoring-Stack live finalisieren und Doku auf den Stand der neuen Stacks (Jellyfin/Plex/...) nachziehen.
|
||||
|
||||
---
|
||||
|
||||
## 1. Methodik und Quellen
|
||||
|
||||
Diese Audit-Quellen wurden gelesen (repo-seitig):
|
||||
|
||||
- `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
- `docs/WORKFLOW.md`
|
||||
- `docs/REPO_MAP.md`
|
||||
- `docs/SERVICE_CATALOG.md`
|
||||
- `docs/RESTORE_MATRIX.md`
|
||||
- `docs/GITOPS_DRIFT_RUNBOOK.md`
|
||||
- `docs/NEXT_SPRINT_TODO_2026-05-16.md`
|
||||
- `ops/borg-ui/scripts/pre-backup-dumps.sh`
|
||||
- `ops/borg-ui/docker-compose.yml`
|
||||
- `ops/borg-ui/all-important-sources.txt`
|
||||
- `ops/filebrowser/docker-compose.yml`
|
||||
- `security/authelia/configuration.yml`
|
||||
- `core/gitea/docker-compose.yml`
|
||||
- `apps/jellyfin/docker-compose.yml`
|
||||
- `host-services/plex/docker-compose.yml`
|
||||
- `ops/policy-checks/last-report.md`
|
||||
|
||||
Schreibbefehle: keine. Deploys: keine. Containerlaufzeit, Komodo-Webhook-Status, Borg-Lauf-Frische und Host-Listener wurden bewusst nicht angetastet — dafuer steht der Live-Daten-Block in Abschnitt 9.
|
||||
|
||||
---
|
||||
|
||||
## 2. Schicht A — GitOps und Konsistenz
|
||||
|
||||
### 2.1 Lokaler Clone vs. `origin/master`
|
||||
|
||||
```
|
||||
## master...origin/master [ahead 1]
|
||||
HEAD = cd650b19ac057a1b74ac63503e5dba50eaf5b8ea
|
||||
origin/master = af231dd4e835b19005cc0842509199d480af00d9
|
||||
```
|
||||
|
||||
- **Befund:** Lokaler Clone ist 1 Commit voraus.
|
||||
- **Commit:** `cd650b1 Close Gitea signup, dedup posture-check alerts, extend Borg scope` (Sat May 23 11:01:24 2026 +0200).
|
||||
- **Inhalt** (laut Commit-Message und betroffenen Dateien):
|
||||
- Gitea: `DISABLE_REGISTRATION=true`, `ENABLE_OPENID_SIGNIN=false`, `ENABLE_OPENID_SIGNUP=false`
|
||||
- Repo-Pflicht-Doku ergaenzt: Komodo-Stack-Webhook-Pflicht in `CLAUDE.md`, `AI_CONTEXT.md`, `WORKFLOW.md`
|
||||
- `posture-check.sh`: Disk1-NTFS-Funktion ausgelagert, Inode-Check auf NTFS uebersprungen, ntfy-Dedup via Fingerprint-State + `ALERT_REPEAT_SECONDS`
|
||||
- `docker-critical-events.sh`: JSON-Parsing, `die exit=0` gefiltert, strukturierte ntfy-Message
|
||||
- `borg-ui`: `/mnt/user/services` als `/local/services:ro` gemountet, `all-important-sources.txt` ergaenzt
|
||||
- Unraid User Scripts dokumentiert (daily report)
|
||||
- `MIGRATION_LOG.md`, `RESTORE_MATRIX.md`, `DISASTER_RECOVERY.md` aktualisiert
|
||||
- **Risiko:** Bei Verlust des Windows-Clones (Reinstall, Diskcrash) ist dieser Stand verloren, weil er nicht in Gitea liegt. Komodo deployt ausserdem aus Gitea und kennt diese Aenderungen noch nicht.
|
||||
- **Empfohlene Aktion (Pflicht vor weiterer Arbeit):** In GitHub Desktop `Push origin` ausfuehren. Danach Komodo-Reaktion fuer die betroffenen Stacks (`gitea`, `borg-ui`) pruefen und Smoke-Tests laufen lassen.
|
||||
|
||||
### 2.2 Working-Tree-Status
|
||||
|
||||
```
|
||||
$ git status --short
|
||||
M CLAUDE.md
|
||||
M HOMELAB_ARCHITECTURE_MASTER_V2.md
|
||||
M apps/homepage/docker-compose.yml
|
||||
...
|
||||
(47 Dateien als modified gemeldet, plus 4 Untracked)
|
||||
```
|
||||
|
||||
- **Bewertung:** Die 47 "modified files" sind mit hoher Wahrscheinlichkeit **Mount-Artefakte** durch CRLF/LF zwischen Windows-Clone und Linux-Mount. Stichprobe `git diff -w --stat CLAUDE.md HOMELAB_ARCHITECTURE_MASTER_V2.md` lieferte leer — d. h. keine inhaltlichen Diffs.
|
||||
- **Aktion:** Bitte am Windows-Host in GitHub Desktop `git status --short` ausfuehren. Wenn dort der Tree leer ist (nur die 4 Untracked), gibt es keinen echten Working-Tree-Drift. Wenn dort echte Diffs erscheinen, hier bitte zurueckmelden — dann ist das ein eigener Befund.
|
||||
- **Optional (nicht Pflicht):** `.gitattributes` mit `* text=auto eol=lf` haerten, damit dieser Mount-Effekt fuer KI-Audits aus dem Weg geht. Das ist ein eigener kleiner Commit, kein Audit-Output.
|
||||
|
||||
### 2.3 Untracked Files
|
||||
|
||||
```
|
||||
?? .serena/
|
||||
?? ops/windows-reinstall/backup-delta-after-2026-05-07.ps1
|
||||
?? ops/windows-reinstall/cleanup-dualboot-bcd.ps1
|
||||
?? ops/windows-reinstall/repair-disk0-boot-to-new-windows.ps1
|
||||
```
|
||||
|
||||
- `.serena/` ist das Working-Directory des Serena Code-Search-Tools. Hat eigene `.gitignore` intern, aber das `.serena/`-Verzeichnis selbst ist nicht in der Repo-`.gitignore`.
|
||||
- **Aktion (klein):** `.serena/` in `.gitignore` aufnehmen, damit es nicht versehentlich committet wird.
|
||||
- Die drei PowerShell-Scripts unter `ops/windows-reinstall/` sind Windows-Reinstall-Helfer. Entscheidung offen: ins Repo aufnehmen (mit Kontextkommentar warum sie dort liegen) oder lokal halten und in `.gitignore` aufnehmen. Vorschlag: aufnehmen, weil `ops/` der dokumentierte Ort fuer Ops-Skripte ist.
|
||||
|
||||
### 2.4 Letzte Commit-Historie (Top 10)
|
||||
|
||||
```
|
||||
cd650b1 Close Gitea signup, dedup posture-check alerts, extend Borg scope [LOKAL, NICHT GEPUSHT]
|
||||
af231dd Fix zero-count noise pattern handling
|
||||
428223d Mark posture report scripts executable
|
||||
b6d3ed4 Tune homelab availability alerts
|
||||
9e7bebb Add daily operations report with hardened log-noise filtering
|
||||
b7cbbe5 Fix Jellyfin external DNS
|
||||
71ac18b Fix Jellyfin native auth routing
|
||||
90f270b Fix Jellyfin config permissions
|
||||
e28f8da Add Jellyfin media server stack
|
||||
edfec5b Add Plex media server stack
|
||||
```
|
||||
|
||||
- Die letzten Tage waren sichtbar: Jellyfin/Plex hinzugefuegt, Availability-Alerts feinjustiert, Posture-Check-Skripte produktiv gemacht, dann der grosse Haertungs-Commit gestern (2026-05-23 11:01).
|
||||
|
||||
### 2.5 Compose-Inventar vs. Doku
|
||||
|
||||
Repo hat folgende Compose-Stacks, die in den Doku-Quellen (`HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md`) **nicht oder nur teilweise** aufgefuehrt sind:
|
||||
|
||||
| Stack | Status im Repo | Status in Master-Doku |
|
||||
|---|---|---|
|
||||
| `apps/jellyfin/docker-compose.yml` | produktiv vorhanden, gepinnt `jellyfin:10.11.8@sha256:...`, Traefik `jellyfin.kaleschke.info`, `secure-headers@file`, native Auth, `/mnt/user/media:ro` + `/mnt/user/photos:ro` | **fehlt** in 7.4 Apps; Authelia-ACL kennt aber bereits `jellyfin.kaleschke.info` als bypass — Doku hinkt hinterher |
|
||||
| `host-services/plex/docker-compose.yml` | produktiv vorhanden, gepinnt `plexinc/pms-docker:1.43.1.10611-1e34174b1@sha256:...`, `network_mode: host`, `/mnt/user/media:ro` + `/mnt/user/photos:ro` | Master-Doku sagt explizit "Plex-Media-Server ist historischer Host-Sonderfall, nicht als Repo-Compose-Stack enthalten" — **das stimmt nicht mehr**, Plex ist jetzt ein Repo-Compose-Stack |
|
||||
| `host-services/docker/` | leeres Verzeichnis | nicht erwaehnt |
|
||||
| `infra/dns/` | leeres Verzeichnis | nicht erwaehnt |
|
||||
| `ops/Semaphore/` | Skripten/Playbooks aber kein Compose | nicht erwaehnt |
|
||||
| `ops/backrest/` | leeres Verzeichnis (Stack laut Master-Doku am 2026-05-15 entfernt) | korrekt als entfernt dokumentiert; Verzeichnis sollte leer bleiben oder weg |
|
||||
| `apps/firefly/`, `apps/firefly-fints/` | leere Verzeichnisse | nicht erwaehnt |
|
||||
| `apps/stirling-pdf/` | leeres Verzeichnis (durch `bentopdf` abgeloest) | korrekt als abgeloest dokumentiert |
|
||||
|
||||
- **Aktion (Doku-Synchronisierung):** `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 7 (Container-Zielbild), `docs/SERVICE_CATALOG.md` und `docs/REPO_MAP.md` um Jellyfin und Plex erweitern. Plex-Doku im Master umschreiben: nicht mehr "historisch ausserhalb Repo", sondern "Compose-Stack mit `network_mode: host` als VPN-Discovery-Ausnahme".
|
||||
- **Aktion (Repo-Hygiene):** Die leeren Verzeichnisse `apps/firefly`, `apps/firefly-fints`, `apps/stirling-pdf`, `host-services/docker`, `infra/dns`, `ops/backrest`, `ops/grafana-influxdb/scripts`, `ops/Semaphore/playbooks`, `ops/Semaphore/Scripts` aufraeumen — Master-Doku sagt: "Leere `.keep`-Platzhalter wurden entfernt; neue Verzeichnisse sollen erst mit konkretem Inhalt ins Repo." Diese Verzeichnisse verletzen diese Regel passiv.
|
||||
|
||||
### 2.6 Image-Pinning
|
||||
|
||||
Lt. `docs/NEXT_SPRINT_TODO_2026-05-16.md` sind diese Stacks noch nicht voll versioniert gepinnt:
|
||||
- `ddns-updater` — `latest...@sha256`
|
||||
- `glances` — `latest-full@sha256`
|
||||
- `scrutiny` — `latest-omnibus@sha256`
|
||||
|
||||
Das ist bewusst dokumentiert und kein Audit-Befund.
|
||||
|
||||
---
|
||||
|
||||
## 3. Schicht B — Hardening-Sprint 2026-05 (Sitrep)
|
||||
|
||||
Dies war der Sprint, der nach dem 2026-05 Restore explizit gesetzt wurde. Stand im Repo:
|
||||
|
||||
| Sprint-Item | Stand 2026-05-16 (Plan) | Stand 2026-05-23 (Repo) | Beleg |
|
||||
|---|---|---|---|
|
||||
| **(1) Backup-Konsistenz** — `dump_sqlite_container` fuer Gitea/Vaultwarden/Uptime-Kuma/Speedtest/Filebrowser + `pg_dump` Nextcloud | offen | ✅ erledigt | `ops/borg-ui/scripts/pre-backup-dumps.sh` Z. 97–139 (`dump_sqlite_container`), Z. 253–258 (Nextcloud `pg_dump`), Z. 261–264 (alle SQLite-Container mit Host-Fallback), Z. 267 (Filebrowser BoltDB). Borg-Scope erweitert um `/mnt/user/services` (Borg-UI Compose Z. 26 + `all-important-sources.txt` Z. 23–25). |
|
||||
| **(2) Filebrowser entschaerfen** — `/mnt/user/appdata:/srv/appdata` weg, gezielte RW-Subpfade | offen | ✅ erledigt | `ops/filebrowser/docker-compose.yml` Z. 11–16. Keine Appdata-Mounts mehr. Nur noch `/mnt/user/documents`, `/mnt/user/photos`, `/mnt/user/projekte` als Datenmounts plus eigener `/database` und `/config`. |
|
||||
| **(3) Authelia Argon2id haerten** — iterations 3, memory 65536, parallelism 4 | offen | ✅ erledigt | `security/authelia/configuration.yml` Z. 17–25. Exakt die geplanten Parameter sind aktiv. |
|
||||
| **(4) Gitea Webhook-Allowlist** — `ALLOWED_HOST_LIST=*` einschraenken | offen | ✅ erledigt | `core/gitea/docker-compose.yml` Z. 18: `GITEA__webhook__ALLOWED_HOST_LIST=komodo-core,localhost,127.0.0.1,192.168.178.0/24`. Zusatz aus heutigem Commit: Public Registration und OpenID-Signup/Signin sind deaktiviert. |
|
||||
|
||||
Alle vier Items sind **im Repo abgeschlossen**. Live-Wirksamkeit haengt am Komodo-Deploy aus Gitea — und genau da haengt aktuell der ungepushte Commit `cd650b1` davor (siehe 2.1). Solange er nicht in Gitea ist, ist insbesondere die Gitea-Signup-Schliessung im Live-Stand nicht garantiert.
|
||||
|
||||
**Bewusst nicht angefasste Liste (Operator-Entscheidung 2026-05-16) ist weiterhin gueltig:**
|
||||
- Hermes — bleibt VM-seitig offen, NAS-Stack bewusst nicht starten
|
||||
- Disk1 NTFS — Phase-2-Migration nach Plan
|
||||
- Komodo native Auth ohne ForwardAuth
|
||||
- Grafana/Influxdb3-core `user: "0"`
|
||||
- Image-Pinning-Vereinheitlichung (`:latest@sha256:`) fuer ddns-updater/glances/scrutiny
|
||||
|
||||
---
|
||||
|
||||
## 4. Schicht C — "Endstufe?"-Bewertung
|
||||
|
||||
### 4.1 Backup/Restore-Readiness
|
||||
|
||||
- **Dump-Coverage:** `pre-backup-dumps.sh` deckt 14 Quellen ab: PostgreSQL-Globals + 3 Shared-DBs + 3 dedizierte Postgres (mealie, immich, nextcloud) + 4 SQLite (gitea, vaultwarden, uptime-kuma, speedtest-tracker) + Filebrowser-BoltDB + Borg-UI + Grafana + Komodo-Mongo. Deckt 1:1 die Restore-Matrix-Eintraege ab.
|
||||
- **Borg-Scope:** `all-important-sources.txt` enthaelt 27 Eintraege inkl. neuer `services/homelab-infra`, `services/stacks`, `services/posture-check` und `secrets`.
|
||||
- **Restore-Validierungen:** Laut `docs/RESTORE_MATRIX.md` sind am 2026-05-07 Mini-Restores fuer `gitea`, `vaultwarden` und `paperless` validiert worden — dokumentierter Stand.
|
||||
- **Live offen:** Wann lief der letzte Borg-Lauf? Sind alle Dumps unter `/mnt/user/backups/borg/dumps/latest` frischer als 24h? Siehe Live-Checkliste 9.4.
|
||||
|
||||
### 4.2 Monitoring-Migration
|
||||
|
||||
- Repo-Zielzustand `monitoring/docker-compose.yml` (337 Zeilen Compose) existiert mit Prometheus, Alertmanager, ntfy-Bridge, Blackbox-Exporter, Loki, Promtail, Grafana, node-exporter, cAdvisor, InfluxDB3 Core.
|
||||
- Provisioning unter `monitoring/grafana/provisioning/` und `monitoring/prometheus/`, `monitoring/loki/`, `monitoring/promtail/`, `monitoring/alertmanager/`, `monitoring/blackbox/` vollstaendig vorhanden.
|
||||
- Alte Stacks `ops/grafana-influxdb/` und `ops/loki/` bewusst noch im Repo (dokumentierter Altstand, Rollback-Referenz).
|
||||
- **Live offen:** Ist `monitoring` schon als Komodo-Stack deployed? Laufen die Container? Sind die Secret-Dateien `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json` auf dem Host? Siehe Live-Checkliste 9.5.
|
||||
|
||||
### 4.3 Repo-Hygiene
|
||||
|
||||
| Befund | Schwere | Aktion |
|
||||
|---|---|---|
|
||||
| 8 leere Verzeichnisse (`apps/firefly`, `apps/firefly-fints`, `apps/stirling-pdf`, `host-services/docker`, `infra/dns`, `ops/backrest`, `ops/grafana-influxdb/scripts`, `ops/Semaphore/playbooks`, `ops/Semaphore/Scripts`) | klein | Aufraeumen, danach committen |
|
||||
| `.serena/` untracked, nicht in `.gitignore` | klein | `.serena/` zu `.gitignore` hinzufuegen |
|
||||
| 3 `ops/windows-reinstall/*.ps1` untracked | klein | Entscheidung treffen: ins Repo oder ignorieren |
|
||||
|
||||
### 4.4 Bekannte dokumentierte Ausnahmen
|
||||
|
||||
Aus `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 10 — alle weiterhin gueltig und durch den Policy-Check abgedeckt (`ops/policy-checks/last-report.md` 0 Critical):
|
||||
|
||||
- Traefik 80/443
|
||||
- Tailscale Host-Netz + Capabilities
|
||||
- AdGuard Port 53 + 8082 (Admin-Port LAN-only, dokumentiert; **offener Punkt im Master:** "Traefik-Absicherung ausstehend (Block F)" — bewusst spaeter)
|
||||
- Plex Host-Netz (aber Master-Doku-Eintrag jetzt falsch, siehe 2.5)
|
||||
- Scrutiny `privileged: true`
|
||||
- Komodo Docker-Socket + keine pauschale Middleware
|
||||
- glance-docker-socket-proxy Read-only Socket
|
||||
- Gitea SSH 222
|
||||
- ddns-updater `frontend_net`
|
||||
- mail-archiver Hybrid-Netze
|
||||
- `traefik/dynamic/*` manueller Host-Sync
|
||||
- nextcloud native Auth
|
||||
- monitoring-influxdb3-core LAN 8181 + `user: "0"`
|
||||
- monitoring-promtail Docker-Socket read-only
|
||||
|
||||
Keine ungeplanten neuen Ausnahmen.
|
||||
|
||||
### 4.5 Endstufen-Definition
|
||||
|
||||
"Endstufe" ist erreicht, wenn alle folgenden Punkte gruen sind:
|
||||
|
||||
1. **Gitea = Quelle der Wahrheit** — kein lokaler Commit ohne Push 🟡 (heute: `cd650b1` ungepusht)
|
||||
2. **Hardening-Sprint im Repo abgeschlossen** 🟢
|
||||
3. **Backup-Konsistenz live verifiziert (Borg laeuft, Dumps frisch)** ❓ Live
|
||||
4. **Monitoring-Stack live, alte Altstaende gestoppt** 🟡
|
||||
5. **Doku synchron mit Repo (Jellyfin/Plex, leere Verzeichnisse, ...)** 🟠
|
||||
6. **Policy-Check 0 Critical** 🟢 (4 Warnings sind dokumentierte Ausnahmen)
|
||||
7. **Restore-Lab gepflegt (`mail-archiver` als naechste Uebung empfohlen)** 🟡 dokumentiert offen
|
||||
|
||||
Sechs der sieben Punkte sind in Reichweite ohne neue Architekturentscheidungen. Punkt 3 und 4 brauchen Live-Daten (Abschnitt 9). Punkt 1 ist 1 Push entfernt.
|
||||
|
||||
---
|
||||
|
||||
## 5. Priorisierte Restliste
|
||||
|
||||
| Prio | Aktion | Begruendung | Aufwand |
|
||||
|---|---|---|---|
|
||||
| **P0** | `cd650b1` nach Gitea pushen | GitOps-Quelle-der-Wahrheit, Voraussetzung fuer alles weitere | 30 Sekunden |
|
||||
| **P0** | Live-Daten aus Abschnitt 9 einholen | Ohne Live-Frische ist Endstufen-Bewertung unvollstaendig | 5 Minuten |
|
||||
| **P1** | Monitoring-Stack live finalisieren (Secrets pruefen, deployen, Smoke-Test, alte Altstaende stoppen) | Aus `docs/NEXT_SPRINT_TODO_2026-05-16.md` der naechste produktive Schritt | 1–2 Stunden mit Tests |
|
||||
| **P2** | Doku-Drift schliessen: Jellyfin und Plex in `HOMELAB_ARCHITECTURE_MASTER_V2.md` 7.4 + 7.1, `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md` ergaenzen; Plex-Eintrag in Abschnitt 7.7 "noch offene Sonderfaelle" entfernen (ist umgesetzt) | Doku ist Source of Truth fuer KI-Audits und Nachfolge | 30 Minuten |
|
||||
| **P2** | Home Assistant -> InfluxDB final testen, HA-Dashboard in `monitoring-grafana` anlegen | aus NEXT_SPRINT_TODO | 1–2 Stunden |
|
||||
| **P3** | Repo-Hygiene: 8 leere Verzeichnisse loeschen, `.serena/` in `.gitignore`, Entscheidung zu `ops/windows-reinstall/*.ps1` | minor, aber dokumentiert | 15 Minuten |
|
||||
| **P3** | Naechster Restore-Lab-Lauf: `mail-archiver` (empfohlen in `RESTORE_MATRIX.md`) | Restore-Routine ueben, bevor sie gebraucht wird | 1 Stunde |
|
||||
| **P4** | `.gitattributes` mit `* text=auto eol=lf` hinzufuegen, um CRLF/LF-Mount-Effekte bei KI-Audits zu vermeiden | klein, kosmetisch fuer kuenftige Audits | 5 Minuten |
|
||||
| **bleibt** | Hermes VM-Seite, Disk1-NTFS Phase 2, AdGuard Admin-Port hinter Traefik (Block F), Image-Pinning ddns/glances/scrutiny | bewusste Operator-Entscheidung, kein Audit-Beduerfnis | nicht jetzt |
|
||||
|
||||
---
|
||||
|
||||
## 6. Was bewusst NICHT angetastet wurde (Audit-Verzicht)
|
||||
|
||||
Konsistent mit der bekannten Nicht-Anfassen-Liste:
|
||||
|
||||
- Hermes (VM-seitig offen)
|
||||
- Disk1 NTFS (Phase-2-Migration nach Plan)
|
||||
- Komodo native Auth ohne ForwardAuth
|
||||
- Grafana / influxdb3-core `user: "0"` Uebergangsausnahme
|
||||
- Image-Pinning-Vereinheitlichung fuer ddns-updater/glances/scrutiny
|
||||
|
||||
---
|
||||
|
||||
## 7. Risiken und Drift-Indikatoren
|
||||
|
||||
| Risiko | Wahrscheinlichkeit | Wirkung | Migitation |
|
||||
|---|---|---|---|
|
||||
| Lokaler Clone-Verlust (Disk, Reinstall) bevor `cd650b1` gepusht wurde | gering, aber real (Du bist im Reinstall-Kontext, siehe `ops/windows-reinstall/`!) | Verlust von Gitea-Signup-Closure und Posture-Check-Verbesserungen | **Sofort pushen** |
|
||||
| Komodo deployt aus Gitea, `gitea` und `borg-ui` laufen aktuell ohne die heutigen Verbesserungen | mittel | Gitea Signup steht noch offen, Borg-Scope umfasst `/mnt/user/services` noch nicht | Push + Komodo-Reaktion pruefen |
|
||||
| 47 vermeintlich modified files koennten doch echte Diffs sein, wenn der Windows-Host etwas anderes zeigt | gering | falsche Audit-Aussage | Punkt 9.1 auf dem Windows-Host pruefen |
|
||||
| Doku-Drift wird groesser, wenn weitere Stacks ohne Doku-Update hinzukommen | mittel | KI-Audits und Onboarding leiden | P2-Doku-Sync nicht aufschieben |
|
||||
| Monitoring-Stack-Migration unfertig, alter und neuer Stack koennten parallel werden | mittel | Doppelte Metric-/Log-Pipeline, Verwirrung bei Diagnose | Live-Status klaeren bevor Deploy |
|
||||
|
||||
---
|
||||
|
||||
## 8. Sources of Truth — Schnellzugriff
|
||||
|
||||
- Operative Quelle der Wahrheit: Gitea `origin/master` (https://git.kaleschke.info/Micha/homelab-infra)
|
||||
- Architektur-Master: `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
- Workflow / GitOps-Regeln: `docs/WORKFLOW.md`
|
||||
- Drift-Runbook: `docs/GITOPS_DRIFT_RUNBOOK.md`
|
||||
- Restore-Quellen: `docs/RESTORE_MATRIX.md`, `docs/DISASTER_RECOVERY.md`
|
||||
- Letzter Policy-Check: `ops/policy-checks/last-report.md` (0 Critical)
|
||||
- Letzte Sprint-Restliste: `docs/NEXT_SPRINT_TODO_2026-05-16.md`
|
||||
|
||||
---
|
||||
|
||||
## 9. Live-Daten-Checkliste — bitte ausfuehren und zurueckspielen
|
||||
|
||||
Fuehre die folgenden Bloecke am Unraid-Host (per SSH oder Web-Terminal) und am Windows-Host (Git Bash / PowerShell in `G:\Gitea_Clone\homelab-infra`) aus und pastiere die Outputs zurueck. Ich integriere sie dann in diesen Report.
|
||||
|
||||
### 9.1 Windows-Host: Echter Working-Tree-Status
|
||||
|
||||
```powershell
|
||||
cd G:\Gitea_Clone\homelab-infra
|
||||
git status --short
|
||||
git log origin/master..HEAD --oneline
|
||||
```
|
||||
|
||||
Erwartet: Working tree leer (oder nur die 4 Untracked). `cd650b1` als einziger lokaler Commit.
|
||||
|
||||
### 9.2 Unraid-Host: Gitea online
|
||||
|
||||
```bash
|
||||
curl -sI --max-time 5 https://git.kaleschke.info/ | head -5
|
||||
docker exec gitea sh -lc 'gitea --version'
|
||||
```
|
||||
|
||||
Erwartet: `HTTP/2 200` (oder ein Auth-Code, der den Erreichbarkeitstest erfuellt). Gitea-Version stimmt mit Image-Tag `1.25.4` ueberein.
|
||||
|
||||
### 9.3 Unraid-Host: Komodo-Webhook-Status
|
||||
|
||||
In Komodo UI fuer jeden produktiven Stack aus `Micha/homelab-infra` pruefen:
|
||||
- `webhook_enabled: true`
|
||||
- Gitea-Hook auf `http://komodo-core:9120/listener/github/stack/<stack-id>/deploy` aktiv
|
||||
- `last_status` der letzten Webhook-Delivery in Gitea (Repository -> Settings -> Webhooks)
|
||||
|
||||
Pflicht-Stacks zum Pruefen: `traefik`, `gitea`, `authelia`, `vaultwarden`, `postgresql17`, `redis`, `paperless-ngx`, `immich`, `nextcloud`, `mealie`, `mail-archiver`, `ntfy`, `homepage`, `paperless-gpt`, `borg-ui`, `filebrowser`, `code-server`, `uptime-kuma`, `glance`, `glances`, `scrutiny`, `speedtest-tracker`, `bentopdf`, `ddns-updater`, `komodo`, `jellyfin`, `plex`, `adguard`, `tailscale`, `monitoring`, `hermes-agent` (sofern produktiv).
|
||||
|
||||
Bei Stacks **ohne** aktiven Webhook bitte den Grund vermerken (dokumentierte Ausnahme oder Nachholbedarf).
|
||||
|
||||
### 9.4 Unraid-Host: Borg-Lauf-Frische und Dump-Coverage
|
||||
|
||||
```bash
|
||||
ls -lah /mnt/user/backups/borg/dumps/latest/
|
||||
stat -c '%y %n' /mnt/user/backups/borg/dumps/latest/*.dump /mnt/user/backups/borg/dumps/latest/*.sql /mnt/user/backups/borg/dumps/latest/*.archive.gz /mnt/user/backups/borg/dumps/latest/*.sqlite 2>/dev/null | sort
|
||||
docker exec borg-ui borg list --short 2>&1 | tail -10
|
||||
```
|
||||
|
||||
Erwartet: Alle 14 Artefakte aus 4.1 sind vorhanden, mtime juenger als 24h. Borg-Archive-Liste zeigt regelmaessige Laeufe.
|
||||
|
||||
### 9.5 Unraid-Host: Monitoring-Stack live?
|
||||
|
||||
```bash
|
||||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | grep monitoring
|
||||
ls -la /mnt/user/appdata/secrets/ | grep -E 'monitoring|influxdb3'
|
||||
curl -sI --max-time 5 https://monitoring.kaleschke.info/ | head -5
|
||||
ss -ltnp 2>/dev/null | grep -E ':8181|:9090|:3100' | head -10
|
||||
```
|
||||
|
||||
Erwartet: Entweder alle `monitoring-*` Container laufen (dann ist 4.2 🟢) oder gar nicht (dann ist 4.2 🟡 wie aktuell bewertet). Halb-Zustand ist ein Audit-Befund.
|
||||
|
||||
### 9.6 Unraid-Host: GitOps-Pflichtmatrix Spot-Check fuer einen Stack
|
||||
|
||||
Beispiel `gitea` (weil der heutige Commit ihn betrifft):
|
||||
|
||||
```bash
|
||||
cd /mnt/user/services/stacks/gitea
|
||||
git rev-parse --short HEAD
|
||||
git status -sb
|
||||
docker inspect gitea --format '{{.Image}}'
|
||||
docker exec gitea sh -lc 'env | grep -E "ALLOWED_HOST_LIST|DISABLE_REGISTRATION|ENABLE_OPENID"'
|
||||
```
|
||||
|
||||
Erwartet: Komodo-Workspace `HEAD` zeigt entweder auf `cd650b1` (wenn Push schon erfolgt + Komodo deployed) oder auf `af231dd` (vor dem Push). ENV-Vars in der Live-Runtime spiegeln den Commit, der Komodo zuletzt deployed hat.
|
||||
|
||||
### 9.7 Unraid-Host: Host-Listener-Spot-Check
|
||||
|
||||
```bash
|
||||
ss -ltnp 2>/dev/null | grep -E ':80|:443|:53|:222|:8082|:8181' | sort
|
||||
```
|
||||
|
||||
Erwartet exakt die dokumentierten Ausnahmen aus `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 10. Andere Listener = Befund.
|
||||
|
||||
---
|
||||
|
||||
## 10. Nachhalte-Vorschlag
|
||||
|
||||
Wenn Du moechtest, halte ich diesen Audit in zwei Schritten zu Ende:
|
||||
|
||||
1. Du fuehrst Abschnitt 9 aus und pastierst die Outputs zurueck.
|
||||
2. Ich aktualisiere diesen Report mit den Live-Ergebnissen, ergaenze die Ampel und schliesse die offenen 🟡/🟠 Punkte oder benenne sie als echte Restliste.
|
||||
|
||||
Bis dahin gilt der Stand dieses Reports als Repo-Audit, nicht als Endstufen-Zertifikat.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Homelab Audit Final - 2026-05-23
|
||||
|
||||
Stand: 2026-05-25 07:33 CEST. Ergebnis nach Push, Live-Messung, Doku-Sync, Repo-Hygiene und erneuter Live-Nachmessung.
|
||||
|
||||
| Punkt | Ampel | Beleg |
|
||||
|---|---|---|
|
||||
| P0 `cd650b1` nach Gitea pushen | gruen | Push `af231dd..cd650b1 master -> master`; produktiver Runtime-Stand `66ee10c` enthaelt `cd650b1`. Die abschliessenden Audit-Doku-Commits liegen in Gitea; der runtime-relevante Stack-Inhalt fuer `gitea`, `borg-ui` und `monitoring` ist seit `66ee10c` unveraendert. |
|
||||
| P0 Live-Daten ablegen | gruen | `docs/AUDIT_2026-05-23_LIVE.md` angelegt, keine Secret-Werte dokumentiert. |
|
||||
| P1 Monitoring live / Altstaende down | gruen | 10 `monitoring-*` Container laufen, `0` unhealthy, `0` starting, `0` stopped; alte `grafana`/`influxdb3-core`/`loki`/`alloy` Container sind nicht vorhanden. `monitoring.kaleschke.info` liefert 302 zu Authelia, Prometheus ist bereit, Loki `/ready` liefert `ready`. |
|
||||
| P1 Jellyfin/Plex Doku | gruen | `HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/SERVICE_CATALOG.md` und `docs/REPO_MAP.md` ergaenzt; Plex ist als Repo-Compose-Stack dokumentiert, nicht mehr als nicht migrierter Dockerman-Sonderfall. |
|
||||
| P2 Borg-Frische | gruen | Borg-UI DB: letzter Backup-Job `completed`, Archiv `Taegliche-Sicherung-2026-05-25T05:52:44.157`, `nfiles=100221`; 15 kanonische Dump-/Archive-Artefakte von 2026-05-25 06:09/06:10 CEST und damit juenger als 24 h. |
|
||||
| P3 Repo-Hygiene | gruen | `.serena/` in `.gitignore`; leere Verzeichnisse entfernt; `ops/windows-reinstall/*.ps1` bewusst ins Repo aufgenommen. |
|
||||
| Policy-Check | gruen | `ops/policy-checks/check_repo.ps1`: 0 Critical, dokumentierte Warnings zu Plex Host-Netz, InfluxDB/Grafana `user: "0"` und bekannten mutable-tag-Ausnahmen. |
|
||||
|
||||
## Bewusst offen
|
||||
|
||||
- Keine offenen Punkte aus der Audit-Restliste.
|
||||
- Nicht Teil des Audits: Nach Disk1 Phase 2 laeuft seit 2026-05-25 eine nicht korrigierende Parity-Pruefung (`NOCORRECT`) im Hintergrund; Zwischenstand der Nachmessung: `mdResyncAction=check P`, `mdResyncCorr=0`.
|
||||
|
||||
## Schlussbewertung
|
||||
|
||||
Das Homelab ist fuer die Audit-Restliste in der Endstufe. Es gibt keine kritischen Repo-, GitOps- oder Live-Befunde aus diesem Audit. Monitoring ist produktiv und ready, alte Altstaende sind down, Backups und Dumps sind frisch.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Homelab Audit Live-Daten - 2026-05-23
|
||||
|
||||
Stand: 2026-05-23 11:27 CEST. Quelle: lokaler Windows-Clone und SSH auf `Kallilabcore`. Secret-Werte wurden nicht ausgelesen oder redaktiert; dokumentiert sind nur Status, Dateinamen, Modi, Env-Key-Namen und nicht geheime Bool-/Host-Werte.
|
||||
|
||||
## 9.1 Windows-Host / Git
|
||||
|
||||
- `git status --short` nach dem initialen Push: keine tracked Modifikationen, untracked waren `.serena/`, `docs/AUDIT_2026-05-23.md`, `docs/CODEX_ENDSTUFE_PROMPT_2026-05-23.md` und drei `ops/windows-reinstall/*.ps1`.
|
||||
- `cd650b1` wurde nach `origin/master` gepusht: `af231dd..cd650b1 master -> master`.
|
||||
|
||||
## 9.2 Gitea online
|
||||
|
||||
- `curl -sI https://git.kaleschke.info/`: `HTTP/2 200`.
|
||||
- `docker exec gitea gitea --version`: `1.25.4`.
|
||||
- Signup-Smoke: `/user/sign_up` meldet Registration disabled.
|
||||
|
||||
## 9.3 Komodo / Workspace-Reaktion
|
||||
|
||||
| Stack | Workspace HEAD | Status | Live-Beleg |
|
||||
|---|---:|---|---|
|
||||
| `gitea` | `cd650b1` | `## master...origin/master` | Container neu gestartet, Env-Keys aktiv |
|
||||
| `borg-ui` | `cd650b1` | `## master...origin/master` | Container healthy, `/mnt/user/services -> /local/services` gemountet |
|
||||
| `monitoring` | `cd650b1` | `## master...origin/master`, untracked Host-Backup `monitoring/prometheus/alerts.yml.bak-20260520-incident` | Stack laeuft seit 4 Tagen |
|
||||
|
||||
Gitea Live-Env ohne Secrets:
|
||||
|
||||
```text
|
||||
GITEA__service__DISABLE_REGISTRATION=true
|
||||
GITEA__openid__ENABLE_OPENID_SIGNIN=false
|
||||
GITEA__openid__ENABLE_OPENID_SIGNUP=false
|
||||
GITEA__webhook__ALLOWED_HOST_LIST=komodo-core,localhost,127.0.0.1,192.168.178.0/24
|
||||
```
|
||||
|
||||
## 9.4 Borg-Lauf-Frische und Dump-Coverage
|
||||
|
||||
- Borg UI DB: Repository `appdata-critical`, `last_backup=2026-05-23 02:30:12 UTC`, `archive_count=30`, letzter Job `completed`, `nfiles=100056`.
|
||||
- Schedule: `Taegliche Sicherung` enabled, letzter Lauf `2026-05-23 02:30:11 UTC`, naechster Lauf `2026-05-24 02:30:00 UTC`.
|
||||
- Hinweis: `docker exec borg-ui borg list --short` funktioniert ohne Repository-Parameter/Env nicht (`Invalid location format: ""`). Der Borg-UI-Status wurde deshalb ueber die lokale Borg-UI-Datenbank ohne Secret-Spalten ausgewertet.
|
||||
|
||||
Frische Artefakte in `/mnt/user/backups/borg/dumps/latest`:
|
||||
|
||||
```text
|
||||
2026-05-23 04:00 postgresql17-globals.sql
|
||||
2026-05-23 04:00 postgresql17-mailarchiver.dump
|
||||
2026-05-23 04:00 postgresql17-paperless.dump
|
||||
2026-05-23 04:01 postgresql17-authelia.dump
|
||||
2026-05-23 04:01 mealie.dump
|
||||
2026-05-23 04:01 gitea.sqlite.dump
|
||||
2026-05-23 04:01 immich.dump
|
||||
2026-05-23 04:01 nextcloud.dump
|
||||
2026-05-23 04:01 uptime-kuma.sqlite.dump
|
||||
2026-05-23 04:01 vaultwarden.sqlite.dump
|
||||
2026-05-23 04:01 speedtest-tracker.sqlite.dump
|
||||
2026-05-23 04:01 filebrowser.bolt.dump
|
||||
2026-05-23 04:01 borg-ui.sqlite
|
||||
2026-05-23 04:01 grafana.sqlite
|
||||
2026-05-23 04:01 komodo-mongo.archive.gz
|
||||
```
|
||||
|
||||
Bewertung: 15 aktuelle Dump-/Archive-Artefakte sind juenger als 24 h. Aeltere nackte `.sqlite`-Dateien vom 2026-05-16 liegen noch im Verzeichnis, sind aber Legacy-Kopien ohne `.dump`-Suffix und nicht Teil der aktuellen Dump-Serie.
|
||||
|
||||
## 9.5 Monitoring-Stack
|
||||
|
||||
- Aktive Container: `monitoring-grafana`, `monitoring-promtail`, `monitoring-prometheus`, `monitoring-cadvisor`, `monitoring-influxdb3-core`, `monitoring-loki`, `monitoring-blackbox-exporter`, `monitoring-alertmanager-ntfy-bridge`, `monitoring-alertmanager`, `monitoring-node-exporter`.
|
||||
- Alte Altcontainer `grafana`, `influxdb3-core`, `loki`, `alloy`: nicht vorhanden in `docker ps -a`.
|
||||
- Secret-Dateien vorhanden und mode `600`: `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json`.
|
||||
- `https://monitoring.kaleschke.info/`: `HTTP/2 302` zu Authelia, wie erwartet.
|
||||
- Host-Listener fuer Monitoring: nur `127.0.0.1:8181`; keine Host-Listener fuer `:9090` oder `:3100`.
|
||||
- Prometheus readiness: `Prometheus Server is Ready.`
|
||||
- Grafana health: `database=ok`, Version `12.4.3`.
|
||||
- Loki: Container laeuft und API/metrics liefert `loki_build_info`; `/ready` liefert aktuell `503 Service Unavailable`, waehrend Query-/Metrics-Endpunkte 200-Zaehler zeigen. Kein Reparaturversuch gestartet, weil der produktive Logpfad nachweislich Daten annimmt und die Stop-Regel keine blinden Eingriffe erlaubt.
|
||||
|
||||
## 9.6 GitOps Spot-Check Gitea
|
||||
|
||||
- `/mnt/user/services/stacks/gitea`: `cd650b1`, `## master...origin/master`.
|
||||
- Docker-Image: `docker.gitea.com/gitea:1.25.4`.
|
||||
- Live-ENV spiegelt `cd650b1` fuer Registrierung, OpenID und Webhook-Allowlist.
|
||||
|
||||
## 9.7 Host-Listener
|
||||
|
||||
Dokumentierte Listener gefunden:
|
||||
|
||||
- `:80`, `:443` Traefik
|
||||
- `:53` AdGuard DNS
|
||||
- `:222` Gitea SSH
|
||||
- `:8082` AdGuard Admin
|
||||
- `127.0.0.1:8181` Monitoring InfluxDB
|
||||
|
||||
Zusaetzlich sichtbar: mehrere `wsdd2` Listener auf `:5355` je Interface. Das ist Host-/Unraid-Service-Discovery, kein Compose-Webdienst und kein GitOps-Stack-Port.
|
||||
@@ -0,0 +1,895 @@
|
||||
# Homelab-Audit KalliLab CORE
|
||||
|
||||
Stand: 2026-05-25
|
||||
Methode: Repo-basierter Audit auf `master` (lokaler Clone). Keine Live-Messung gegen den Host. Querverweise auf Audit-Live-Daten aus `docs/AUDIT_2026-05-23_LIVE.md`, wo verfuegbar.
|
||||
Auftrag: externer, kritischer Audit-Blick zusaetzlich zur internen `docs/STRATEGISCHE_BEWERTUNG_2026-05-23.md`.
|
||||
|
||||
## Wichtige Vorbemerkung
|
||||
|
||||
Es gibt seit dem 23.05. eine fundierte interne Bewertung (`docs/STRATEGISCHE_BEWERTUNG_2026-05-23.md`) und eine konsolidierte Hausaufgabenliste (`docs/CODEX_KONSOLIDIERUNG_2026-05-23.md`). Davon wurden seit dem 25.05. bereits umgesetzt:
|
||||
|
||||
- Jellyfin entfernt (MASTER 7.8)
|
||||
- Homepage entfernt (MASTER 7.8)
|
||||
- Uptime-Kuma entfernt (MASTER 7.8, SECRETS_MAP 29)
|
||||
- Monitoring-Stack produktiv (AUDIT_FINAL 9), Altstaende-Container down
|
||||
- Disk1 NTFS -> XFS Phase 2 abgeschlossen am 2026-05-25 (STORAGE_LAYOUT 3)
|
||||
- Unraid-Flash-Backup live (`unraid-flash-config.tar.gz` im Borg-Lauf)
|
||||
- GitHub-Push-Mirror `michaelkaleschke-spec/homelab-infra` aktiv (DR 10, MASTER 7.1)
|
||||
|
||||
Diese geloesten Punkte werden hier nicht wiederholt. Dieser Audit konzentriert sich auf das, was nach dem 23.05.-Sprint **noch offen ist** und auf das, was die strategische Bewertung **nicht oder nur kurz angerissen** hat.
|
||||
|
||||
---
|
||||
|
||||
# Phase 1: Repo-Inventar
|
||||
|
||||
## Ordnerstruktur (Ist-Zustand)
|
||||
|
||||
```
|
||||
homelab-infra/
|
||||
├── apps/ 9 Stacks (bentopdf, immich, mail-archiver, mealie, nextcloud, ntfy, paperless, paperless-gpt, unbound)
|
||||
├── core/ 1 Stack (gitea)
|
||||
├── docs/ 28 Markdown-Dokumente
|
||||
├── env/ 2 *.example
|
||||
├── host-services/ 3 Stacks (Adguard, plex, tailscale)
|
||||
├── infra/ 3 Stacks (ddns-updater, postgresql17, redis)
|
||||
├── monitoring/ 1 Compose mit 10 Services + Provisioning
|
||||
├── ops/ 17 Verzeichnisse (Semaphore, borg-ui, code-server, filebrowser, glance, glances, grafana-influxdb [Altstand], hermes-agent, komodo, loki [Altstand], policy-checks, restore-tests, scrutiny, speedtest, uptime-kuma [Altrest], windows-reinstall)
|
||||
├── security/ 2 Stacks (authelia, vaultwarden)
|
||||
├── services/ 1 posture-check (Host-Skripte)
|
||||
└── traefik/ 1 Compose + dynamic/ (3 Files)
|
||||
```
|
||||
|
||||
**Inventar-Befund:**
|
||||
|
||||
- ~30 Compose-Dateien, 1 zentraler Compose-Multi-Service (`monitoring/`).
|
||||
- 29 Composes wurden vom Policy-Checker validiert (`ops/policy-checks/last-report.md`): **0 Critical, 4 Warnings, 9 Info**.
|
||||
- Doku-Dichte ist hoch (REPO_MAP, SERVICE_CATALOG, RESTORE_MATRIX, DISASTER_RECOVERY, SECRETS_MAP, WORKFLOW, STORAGE_LAYOUT, GITOPS_DRIFT_RUNBOOK, ALERTING_MAP).
|
||||
- Restore-Tests sind als echte Scripts versioniert (`ops/restore-tests/`). Ueberdurchschnittlich.
|
||||
|
||||
## Gut dokumentierte Bereiche (Belegt)
|
||||
|
||||
| Bereich | Quelle |
|
||||
|---|---|
|
||||
| Architektur, Netze, Ausnahmen | `HOMELAB_ARCHITECTURE_MASTER_V2.md` |
|
||||
| GitOps-Workflow, Drift | `docs/WORKFLOW.md`, `docs/GITOPS_DRIFT_RUNBOOK.md` |
|
||||
| Backup-Scope, Restore-Wege, Tier-Modell | `docs/RESTORE_MATRIX.md`, `docs/DISASTER_RECOVERY.md`, `ops/borg-ui/BACKUP_SCOPE.md` |
|
||||
| Storage / Cache-Policy / FS / Posture | `docs/STORAGE_LAYOUT.md` (zum Audit-Zeitpunkt noch `docs/STORAGE_LAYOUT.draft.md`) |
|
||||
| Secret-Inventur | `docs/SECRETS_MAP.md` |
|
||||
| Alert-Pfade | `docs/ALERTING_MAP.md` |
|
||||
|
||||
## Luecken / Unklar (vermutet bzw. Rueckfrage noetig)
|
||||
|
||||
| Luecke | Warum es ein Audit-Loch ist |
|
||||
|---|---|
|
||||
| `docs/STORAGE_LAYOUT.draft.md` ist `Draft 1.3`, nicht `Active` | Stand zum Audit-Zeitpunkt 2026-05-25: mehrere Hard Rules (12 Constitution) galten formal noch nicht. Hard Rule 11 (kein Stack ohne Restore-Pfad in RESTORE_MATRIX) wurde schon eingehalten — also nur Formal-Luecke. Folgearbeit: als `docs/STORAGE_LAYOUT.md` Active heben. |
|
||||
| `docs/SERVICES_RECOVERY.md` ist als verbindlich angekuendigt (STORAGE_LAYOUT 4), aber nicht im Repo | Konkrete Mirror-Mechanik fuer `services/gitea/git/repositories/` ≤ 6 h ist nirgends spezifiziert. |
|
||||
| Hardware-Inventar: kein zentrales Dokument | Keine Stelle im Repo nennt CPU-Modell, RAM-Groesse, NIC-Speed, Mainboard, Parity-Disk-Groessen — nur "Samsung 970 EVO Plus 2 TB" steht in STORAGE_LAYOUT 3. |
|
||||
| USV: keine Erwaehnung | Keine Datei nennt eine USV. Unklar, ob vorhanden. |
|
||||
| Familien-/User-Onboarding-Doku | Keine Doku, die deine Frau/Kinder lesen muessten ("So loggst du dich in Nextcloud ein"). Aktuell ist alles Operator-Doku. |
|
||||
|
||||
## Fuer den Audit besonders wichtige Dateien (verwendet)
|
||||
|
||||
- `HOMELAB_ARCHITECTURE_MASTER_V2.md` — komplett
|
||||
- `docs/WORKFLOW.md`, `docs/REPO_MAP.md`, `docs/SERVICE_CATALOG.md` — komplett
|
||||
- `docs/DISASTER_RECOVERY.md`, `docs/RESTORE_MATRIX.md`, `docs/SECRETS_MAP.md` — komplett
|
||||
- `docs/STORAGE_LAYOUT.md` (zum Audit-Zeitpunkt `docs/STORAGE_LAYOUT.draft.md`), `docs/STRATEGISCHE_BEWERTUNG_2026-05-23.md` — komplett
|
||||
- `docs/AUDIT_2026-05-23_LIVE.md`, `docs/AUDIT_2026-05-23_FINAL.md`
|
||||
- `ops/policy-checks/last-report.md`
|
||||
- `monitoring/docker-compose.yml`, `monitoring/prometheus/alerts.yml`
|
||||
- `traefik/docker-compose.yml`, `traefik/dynamic/middlewares.yml`
|
||||
- `security/authelia/configuration.yml`, `security/authelia/docker-compose.yml`
|
||||
- `apps/paperless/docker-compose.yml`, `apps/immich/docker-compose.yml`, `apps/nextcloud/docker-compose.yml`
|
||||
- `host-services/Adguard/docker-compose.yml`
|
||||
|
||||
---
|
||||
|
||||
# A. Executive Summary
|
||||
|
||||
**Was schon stark ist:**
|
||||
|
||||
- GitOps-Disziplin: Gitea als Sollzustand, Komodo als Consumer, dokumentierter Drift-Runbook, Stop-Regel ("zwei Fehlversuche -> Pflichtmatrix"). Seltene Reife.
|
||||
- Backup-Architektur: Pre-Backup-Dumps + Borg + Restore-Tests mit echtem Smoke-Test-Kriterium ("Container startet ≠ Erfolg"). 15 frische Dumps < 24 h alt (`AUDIT_LIVE 9.4`).
|
||||
- Architektur-Klarheit: `frontend_net` / `backend_net` / app-interne Netze, keine Sammelnetze, dokumentierte Ausnahmen.
|
||||
- Image-Pinning: Tier-1-Stateful mit `<minor>@sha256:...`. Konsequent durchgezogen.
|
||||
- Secrets-Hygiene: Keine Secret-Werte im Repo, `_FILE`-Mounts + Komodo Stack ENV, explizit dokumentierte Ausnahmen.
|
||||
- Policy-as-Code: `check_repo.ps1` mit 0 Critical und sauber dokumentierten Exceptions.
|
||||
|
||||
**Was kritisch ist:**
|
||||
|
||||
- **AdGuard Admin-Port 8082 ohne Authelia/2FA am LAN gebunden** (`host-services/Adguard/docker-compose.yml:16`) — dokumentierte "Operator-Entscheidung" 2026-05-25. Im Heim-LAN tolerierbar, mit IoT/Gaeste-WLAN potenziell ein Pfad zur DNS-Manipulation. Niedrigster Aufwand: Bind nur auf Tailscale-Interface.
|
||||
- **Authelia ACL: 2FA nur fuer `files.kaleschke.info` und `scrutiny.kaleschke.info`** (`security/authelia/configuration.yml:44-48`). Borg-UI, Code-Server, Filebrowser, Glance — alles nur `one_factor`. Bei Pwd-Kompromittierung des Operator-Accounts ist Borg-UI + Code-Server der direkteste Pfad zur Datenexfiltration.
|
||||
- **Authelia-Repo-Baseline ↔ Host-Config-Drift "by design"** (`docs/REPO_MAP.md:48`, `SERVICE_CATALOG 23`). User-DB, OIDC-Clients und Secrets sind hostseitig, Manual-Merge-Pflicht. Stelle, an der Drift mit Anlauf passiert.
|
||||
- **Komodo Self-Bootstrap-Problem ist nur dokumentiert, nicht geloest** (MASTER 13: Self-Stack Drift-Recovery 2026-05-04). Bei Recovery vom kalten Host musst du Komodo aus `compose.yaml` neu erzeugen — dafuer brauchst du die `.env` mit `KOMODO_*`-Secrets, die nur auf Host und ggf. Vaultwarden liegen.
|
||||
- **Backup-Off-Site-Diversitaet:** BorgBase Hetzner ist Single-Provider; Borg-Passphrase analog gesichert ist als TODO markiert (`docs/DISASTER_RECOVERY.md:64,401`). Wenn Hetzner-Account verloren geht, ist das halbe DR-Versprechen weg.
|
||||
|
||||
**Was unnoetig komplex ist:**
|
||||
|
||||
- Drei dokumentierte Monitoring-/Logging-Pfade gleichzeitig im Repo: `ops/grafana-influxdb` (Altstand), `ops/loki` (Altstand), `monitoring/` (Ziel). Die Altstaende sind als Container down, aber **Verzeichnisse noch im Repo** — Doppelpflege-Risiko. Der versprochene Repo-Cleanup (`git rm`) fehlt.
|
||||
- Hermes-Agent: NAS-Stack bewusst deaktiviert ("VM-seitig offen"), aber Stack-Verzeichnis und Compose mit Dashboard-Domain bleiben im Repo. Mehr "Schwebezustand" als operativer Wert.
|
||||
- BentoPDF: "vorbereitet", noch nie produktiv abgenommen (`SERVICE_CATALOG 52`, `MASTER 7.5`).
|
||||
- `infra/redis` ist als shared Cache deklariert, wird de facto nur von Paperless genutzt (Authelia nicht, Immich/Nextcloud/Mealie haben eigene Redis). Das "shared" stimmt im Repo nicht mit der Realitaet ueberein.
|
||||
|
||||
**Groesster Hebel:**
|
||||
|
||||
**Authelia OIDC-Provider aktivieren** — wenn Nextcloud, Immich, Grafana (und perspektivisch Mealie via OIDC-Bridge) per SSO laufen, gewinnst du gleichzeitig:
|
||||
|
||||
- (a) Familien-Onboarding-Komfort (ein Login),
|
||||
- (b) zentrale Brute-Force-Regulation und Audit,
|
||||
- (c) Voraussetzung fuer sinnvolles CrowdSec/Fail2Ban,
|
||||
- (d) zentrale 2FA-Pflicht statt App-by-App.
|
||||
|
||||
Das ist ein Sprint, nicht ein Quartal, und macht aus deinem "Admin-Authelia" ein echtes Identity-System.
|
||||
|
||||
**Was ein erfahrener Homelabber sofort aendern wuerde:**
|
||||
|
||||
1. AdGuard-Admin-Port nur auf Tailscale-Interface binden (5 Min, Compose-Edit).
|
||||
2. Borg-Passphrase auf Papier in Bankschliessfach (15 Min, off-system).
|
||||
3. `scrutiny` und `ddns-updater` `no-new-privileges` Warning aufraeumen (10 Min) — kosmetisch, aber Policy-Check sollte clean sein.
|
||||
4. Altstaende `ops/grafana-influxdb/` und `ops/loki/` aus Repo entfernen (Backup-Branch dann `git rm`).
|
||||
5. Renovate-Bot gegen Gitea einrichten — beendet manuelle Digest-Pflicht.
|
||||
|
||||
---
|
||||
|
||||
# B. Scorecard (1 = exzellent, 10 = ungenuegend)
|
||||
|
||||
| Bereich | Note | Begruendung |
|
||||
|---|---:|---|
|
||||
| Hardware | **nicht bewertbar** | Keine Inventar-Doku im Repo. Nur Cache-NVMe genannt. Siehe Phase H. |
|
||||
| Ordnerstruktur | **2** | Klare Trennung apps/infra/ops/security/core; konsistente Namenskonvention (mit Migrationsplan in STORAGE_LAYOUT 6). Kleinerer Haenger: `host-services/Adguard/` mit Grossbuchstabe. |
|
||||
| Storage | **3** (Repo-Stand) / **2** (mit STORAGE_LAYOUT Active) | Cache-XFS, Disk1-XFS jetzt erreicht. Pfad-Disziplin via `/mnt/user/...`. Posture-Check etabliert. Note durch Draft-Status und fehlendes `SERVICES_RECOVERY.md` gedrueckt. |
|
||||
| Docker-Architektur | **2** | Netzmodell klar, Healthchecks fehlen grossflaechig, `latest@sha256` als bewusster Kompromiss bei einigen Images dokumentiert. Keine Memory-Limits. |
|
||||
| Reverse Proxy / Zugriff | **2** | DNS-Challenge, Wildcard-faehig, Authelia ForwardAuth, dynamic config sauber getrennt. Manuelle Host-Sync-Ausnahme ist pragmatisch. |
|
||||
| Security | **3** | Solides Fundament (Authelia Argon2id, no-new-privileges-Standard, Webhook-Allowlist, `cloudflare_dns_api_token` als Docker Secret), aber: nur 2 Domains mit 2FA, AdGuard-Admin direkt am LAN, kein WAF/Bouncer, Authelia Regulation 5-Min-Ban ist gentil. |
|
||||
| Netzwerk / DNS | **2** | AdGuard + Unbound + Tailscale-Trias ist Best-of-Class-Homelab. FritzBox als Router nicht im Repo dokumentiert, daher Note nicht 1. |
|
||||
| Backup | **2** | Borg, Pre-Dumps, Tier-Modell, dokumentierter Scope. Punkt-Abzug: Single-Provider Off-Site, Passphrase nicht analog, Komodo-Mongo-Dump-Verifikation nicht im Auto-Cron. |
|
||||
| Restore-Faehigkeit | **2** | RESTORE_MATRIX mit Smoke-Test je Dienst, Restore-Test-Schedule + Validierungen fuer Vaultwarden/Gitea/Paperless dokumentiert. Punkt-Abzug: Immich-Restore noch nie geuebt — groesster Datentopf. |
|
||||
| GitOps | **1-2** | Webhook-Pflicht fuer neue Stacks, Source-of-Truth-Hierarchie, Drift-Runbook. Self-Bootstrap-Problem von Komodo zieht von 1 auf 2. |
|
||||
| Monitoring | **3** | Stack produktiv, aber Altstaende noch im Repo, Family-View-Dashboard fehlt, Alerts (`alerts.yml`) sehr knapp (5 Regeln), keine Cert-Expiry-Alert auf Prometheus-Ebene (Cert-Token-Check laeuft separat). |
|
||||
| Dokumentation | **1** | Aussergewoehnlich. SERVICE_CATALOG ist Gold. Einziger Punkt: kein End-User-/Familien-Onboarding. |
|
||||
| Automatisierung | **3** | Borg-Dumps automatisiert, posture-check Host-Cron, Alert->ntfy-Pipe. Aber: keine CI gegen Repo, kein Renovate, kein automatisches Image-Update-Tracking. |
|
||||
| Wartbarkeit | **2** | Doku traegt; Sprintpflege-Disziplin sichtbar (MIGRATION_LOG, AUDIT_FINAL). Risiko: Authelia-Drift, Hermes-Schwebezustand. |
|
||||
| Nerd-Faktor | **2-** | Komodo + Borg-UI + ntfy-Bridge + Posture-Check + Restore-Lab + Hermes-Experiment + Push-Mirror + Digest-Pinning. Liegt zwischen "Solider Senior" und "Spielwiese halten lernen". |
|
||||
|
||||
**Gesamteindruck: 2 (gut).** Strukturell weit ueber durchschnittlichem Homelab; konkrete Luecken sind klar benennbar und nicht systemisch.
|
||||
|
||||
---
|
||||
|
||||
# C. Top-20 Findings
|
||||
|
||||
> Format: priorisiert nach Risiko-zu-Aufwand-Hebel. Jeder Eintrag hat Fundstelle, Empfehlung und Prio.
|
||||
|
||||
### F-01 · AdGuard-Admin am LAN ohne Auth
|
||||
|
||||
- **Kategorie:** Security / Zugriff
|
||||
- **Fundstelle:** `host-services/Adguard/docker-compose.yml:16`, `MASTER 10`, `docs/SERVICE_CATALOG.md:14`
|
||||
- **Beobachtung:** Port `8082:80` direkt auf alle Interfaces. Bewusste Operator-Entscheidung 2026-05-25.
|
||||
- **Risiko:** Jedes Geraet im LAN kann DNS-Filterregeln, Upstream und Logging manipulieren. IoT-Kompromittierung oder Gast-WLAN -> DNS-Hijack moeglich.
|
||||
- **Best Practice:** Admin-UIs nicht im LAN ohne Auth. Entweder hinter Traefik+Authelia mit `two_factor` oder Bind auf Tailscale-Interface (z. B. `100.x.y.z:8082:80`).
|
||||
- **Empfehlung:** Schritt 1 — Bind auf Tailscale-IP (S, 5 Min). Schritt 2 — optional spaeter Traefik-Route hinter Authelia.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** `ss -ltnp | grep :8082` zeigt nur Tailscale-IP; LAN-Browser-Zugriff schlaegt fehl.
|
||||
- **Rollback:** Compose-Diff zurueck, Komodo redeploy.
|
||||
|
||||
### F-02 · Borg-Passphrase nicht analog gesichert
|
||||
|
||||
- **Kategorie:** Backup / DR
|
||||
- **Fundstelle:** `docs/DISASTER_RECOVERY.md:64,401`, `docs/SECRETS_MAP.md:48`
|
||||
- **Beobachtung:** `borg_repo_passphrase.txt` liegt im Host-Filesystem unter `/mnt/user/appdata/secrets/`. Doku weist explizit darauf hin, dass eine externe analoge Sicherung Operator-Aufgabe ist.
|
||||
- **Risiko:** Wenn Unraid-Host und ggf. Vaultwarden gleichzeitig defekt sind, ist das verschluesselte Borg-Repo bei Hetzner nutzlos.
|
||||
- **Empfehlung:** Auf Papier ausdrucken, in Bankschliessfach oder bei vertrauter Person versiegelt. Zusaetzlich in Vaultwarden hinterlegen (aber Vaultwarden hilft nicht, wenn es selbst restauriert werden muss).
|
||||
- **Prioritaet:** Muss sofort
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** Du kannst den Wert ohne Host wiederherstellen.
|
||||
|
||||
### F-03 · Single-Provider Off-Site Backup
|
||||
|
||||
- **Kategorie:** Backup
|
||||
- **Fundstelle:** `ops/borg-ui/BACKUP_SCOPE.md`, `docs/RESTORE_MATRIX.md:77-96`, `STORAGE_LAYOUT 8.1`
|
||||
- **Beobachtung:** Hetzner Storage Box als alleiniges Off-Site-Borg-Ziel. STORAGE_LAYOUT 8.1 sieht zusaetzlich lokales Borg-Repo auf `/mnt/user/backups/borg/` vor (gleicher Host) und eine externe Wechselplatte (manuell rotiert).
|
||||
- **Risiko:** Hetzner-Account-Verlust (Payment-Issue, Account-Hack, Provider-Outage) = halbes 3-2-1.
|
||||
- **Best Practice:** Zweites Off-Site-Ziel mit unterschiedlichem Provider oder Cold-Wechselplatte mit fester Rotationskadenz.
|
||||
- **Empfehlung:** (a) Wechselplatten-Rotation in fester Kadenz dokumentieren (zwei Platten, monatlicher Tausch). Oder (b) zweites Borg-Repo bei rsync.net / BorgBase EU2 / privatem 2. Standort.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** M
|
||||
- **Validierung:** `borg list` gegen beide Repos, beide < 7 Tage alt.
|
||||
|
||||
### F-04 · Authelia 2FA-Pflicht zu schmal
|
||||
|
||||
- **Kategorie:** Security
|
||||
- **Fundstelle:** `security/authelia/configuration.yml:44-53`
|
||||
- **Beobachtung:** Nur `files.kaleschke.info` und `scrutiny.kaleschke.info` sind `two_factor`. Tier-1-Operator-UIs wie Borg-UI, Code-Server, Filebrowser (zweite Route?), Komodo (eigene Auth), Glance, Grafana laufen mit `one_factor`.
|
||||
- **Risiko:** Operator-Passwort-Kompromittierung (Phishing, Keylogger, Browser-Save-Leak) gibt ohne 2FA Vollzugriff auf Code-Server (Repo + Workspace), Borg-UI (Restore-Pfade), Filebrowser (Documents/Photos).
|
||||
- **Empfehlung:** ACL erweitern: `two_factor` fuer `borg.kaleschke.info`, `code.kaleschke.info`, `files.kaleschke.info` (schon), `glance.kaleschke.info` (debattierbar), `traefik.kaleschke.info`. Komodo bleibt Ausnahme.
|
||||
- **Prioritaet:** Muss sofort
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** Nach Login auf `borg.kaleschke.info` wird 2FA-Prompt erzwungen.
|
||||
- **Rollback:** ACL-Block zurueck.
|
||||
|
||||
### F-05 · Repo-Altstaende `ops/grafana-influxdb/` und `ops/loki/` nicht entfernt
|
||||
|
||||
- **Kategorie:** Wartbarkeit / GitOps
|
||||
- **Fundstelle:** Repo-Wurzeln `ops/grafana-influxdb/`, `ops/loki/`; `MASTER 7.6`, `SERVICE_CATALOG 68-70,80-81`, `AUDIT_FINAL 9`
|
||||
- **Beobachtung:** Container down, aber Compose-Dateien + Provisioning bleiben im Repo. Doku referenziert beide gleichzeitig. Risiko: jemand (zukuenftiges Ich, KI) deployt versehentlich den Altstand.
|
||||
- **Empfehlung:** `git rm` der beiden Verzeichnisse, Tag `pre-monitoring-cleanup` fuer Rollback, MIGRATION_LOG-Eintrag.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** `policy-checks` laeuft clean, Repo enthaelt nur noch `monitoring/`.
|
||||
|
||||
### F-06 · Hermes-Agent im Schwebezustand
|
||||
|
||||
- **Kategorie:** App-Landschaft / Wartbarkeit
|
||||
- **Fundstelle:** `ops/hermes-agent/docker-compose.yml`, `MASTER 7.5`, `SERVICE_CATALOG 82-83`
|
||||
- **Beobachtung:** "NAS-Stack bewusst deaktiviert" wegen offener VM-Seite. Dashboard-Domain (`hermes.kaleschke.info`) + Authelia-ACL + Secret-Pfade dokumentiert.
|
||||
- **Risiko:** Schleichender Verfall — in 6 Monaten verstehst du Model-C nicht mehr ohne `ops/hermes-agent/README.md`. Bei jeder Authelia-/Compose-Aenderung musst du Hermes mitpruefen, obwohl es nichts tut.
|
||||
- **Empfehlung:** Operator-Entscheidung mit 60-Tage-Deadline ehrlich treffen. Wenn nicht produktiv bis 2026-07-25: `git rm ops/hermes-agent/`, Domain aus DNS, ACL-Eintrag raus.
|
||||
- **Prioritaet:** Sollte zeitnah (Entscheidung)
|
||||
- **Aufwand:** S (Entfernen) / L (echte Produktiv-Aktivierung)
|
||||
- **Validierung:** Entweder Smoke-Test auf `hermes.kaleschke.info` mit funktionalem Use-Case-Beleg, oder Repo-clean.
|
||||
|
||||
### F-07 · Monitoring-Stack ohne Digest-Pin
|
||||
|
||||
- **Kategorie:** Reproduzierbarkeit / GitOps
|
||||
- **Fundstelle:** `monitoring/docker-compose.yml:3,28,66,84,100,118,276,296`
|
||||
- **Beobachtung:** Prometheus, Alertmanager, Blackbox, Loki, Promtail, Grafana, node-exporter, cAdvisor sind alle nur per Tag gepinnt (`prom/prometheus:v3.7.3`, `grafana/grafana:12.4.3`, ...). Nur `influxdb3-core` hat `@sha256:`. Das widerspricht der Image-Versionierungs-Disziplin der Tier-1-Stateful-Dienste.
|
||||
- **Risiko:** Wenn upstream einen Tag erneut pushed (Versionsdrift, Supply Chain), wird beim Rebuild ein anderer Container deployed — gerade Monitoring sollte stabil sein.
|
||||
- **Empfehlung:** Beim naechsten Komodo-Redeploy aktuellen Digest auslesen und einpinnen. Vorbereitung fuer Renovate (F-12).
|
||||
- **Prioritaet:** Nice to have
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** `grep '@sha256' monitoring/docker-compose.yml` listet alle 10 Services.
|
||||
|
||||
### F-08 · Alert-Regeln zu duenn
|
||||
|
||||
- **Kategorie:** Monitoring
|
||||
- **Fundstelle:** `monitoring/prometheus/alerts.yml`
|
||||
- **Beobachtung:** Exakt 5 Regeln: ExternalConnectivityDown, EndpointDown, EndpointSlow, DiskAlmostFull, MemoryHighUsage, Traefik5xx. Es fehlen:
|
||||
- Borg-Lauf-Frische (ueber `node_exporter` textfile collector oder Pushgateway).
|
||||
- Zertifikatslaufzeit (Blackbox kann `probe_ssl_earliest_cert_expiry`, aber keine Alert-Regel dafuer).
|
||||
- Container-down-Alert (cAdvisor liefert `container_last_seen`).
|
||||
- PostgreSQL-Connection-Saturation.
|
||||
- Loki ingestion-rate / log-volume spike.
|
||||
- InfluxDB-Disk-Pressure.
|
||||
- Backup-Job-Failure.
|
||||
- **Risiko:** Du siehst Probleme nicht, bevor sie weh tun. Cert-Expiry und Borg-Stale sind die schmerzhaftesten Blind-Spots.
|
||||
- **Empfehlung:** Mindestens zwei Regeln nachziehen: `BorgArchiveStale` (>30 h, Pushgateway oder textfile) und `TLSCertExpiryNear` (<14 Tage). Rest als Folge-Sprint.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** M
|
||||
- **Validierung:** Alerts feuern in Test-Bedingung (Borg-Dump-File touch -d backwards).
|
||||
|
||||
### F-09 · Komodo-Self-Bootstrap-Problem
|
||||
|
||||
- **Kategorie:** GitOps / DR
|
||||
- **Fundstelle:** `MASTER 13: Komodo Self-Stack Drift-Recovery 2026-05-04`
|
||||
- **Beobachtung:** Du hattest schon einen Drift-Vorfall (Komodo-Core ran aus `/tmp/*repair.yml`, Mongo-Pfad fehlte). Recovery-ENV liegt als "temporaeres Tier-1-Secret-Material" unter `/mnt/user/appdata/secrets/_komodo_stack_env_recovery_2026-05-04.env` (Doku-Stand).
|
||||
- **Risiko:** Bei Totalausfall musst du Komodo aus Compose-Datei wiederbeleben, dafuer brauchst du die Stack-ENV mit `KOMODO_SECRET_KEY`, `KOMODO_MONGO_PASSWORD`, `KOMODO_PERIPHERY_PASSKEY` etc., die nur als Komodo Stack ENV existieren. Klassisches Henne-Ei.
|
||||
- **Empfehlung:** Komodo-Self-Stack aus Komodos eigener Verwaltung herausnehmen und als handgepflegten `docker compose`-Service in `services/komodo-bootstrap/` halten. Stack-ENV als versiegelte Datei unter `/mnt/user/appdata/secrets/` mit deterministischem Restore-Pfad in RESTORE_MATRIX.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** M
|
||||
- **Validierung:** Komodo-Stack-Datei lebt im Repo unter `services/`, nicht in Komodos eigener Workspace-Sicht.
|
||||
|
||||
### F-10 · Authelia Repo↔Host Drift "by design"
|
||||
|
||||
- **Kategorie:** GitOps / Security
|
||||
- **Fundstelle:** `docs/REPO_MAP.md:48`, `security/authelia/configuration.yml`, `SERVICE_CATALOG 23`
|
||||
- **Beobachtung:** Repo enthaelt Baseline ohne Secrets, OIDC, Users-DB. Manuelles Merge auf den Host noetig. Es gibt keine automatische Konsistenz-Pruefung.
|
||||
- **Risiko:** Repo-Aenderung (z. B. neue ACL-Regel) wird gepusht, aber nie auf den Host gemerged -> Drift, Authelia hinkt der Wahrheit hinterher.
|
||||
- **Empfehlung:** Symmetrisch zum Traefik-Dynamic-Workflow (manueller Sync explizit als Pflicht in WORKFLOW.md). Zusaetzlich ein einfaches Diff-Script `services/authelia-diff.sh`, das `diff` zwischen Repo-Baseline und Host-Datei zeigt, und das im posture-check als Warning auftaucht, wenn die ACL-Sektion differiert.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** Script laeuft, posture-check kennt einen neuen Check `authelia_config_drift`.
|
||||
|
||||
### F-11 · Immich-Restore noch nie geuebt
|
||||
|
||||
- **Kategorie:** Backup / Restore
|
||||
- **Fundstelle:** `docs/RESTORE_MATRIX.md:49`, Restore-Test-Schedule
|
||||
- **Beobachtung:** Vaultwarden / Gitea / Paperless haben Mini-Restore-Tests (2026-05-07). Immich nicht. Immich ist der groesste Datentopf (Familien-Fotos).
|
||||
- **Risiko:** Silent Corruption in Postgres-pgvecto-rs-Daten bemerkst du erst beim Restore-Versuch.
|
||||
- **Empfehlung:** Eigener Sprint: Immich-Restore-Test gegen `/mnt/user/backups/restore-lab/immich/` mit Sub-Set der `immich.dump` und einem Foto-Sample. Smoke-Test = "10 Fotos im Browser sichtbar nach Restore".
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** M
|
||||
- **Validierung:** Report unter `/mnt/user/backups/restore-reports/immich-<datum>.json`.
|
||||
|
||||
### F-12 · Keine Image-Update-Automatik (Renovate o. ae.)
|
||||
|
||||
- **Kategorie:** Wartbarkeit
|
||||
- **Fundstelle:** Repo-weit; `docs/WORKFLOW.md:282-288` (Image-Versionierung)
|
||||
- **Beobachtung:** Digest-Pinning ist konsequent, aber rein manuell. Bei ~30 Images bedeutet das, du musst monatlich fuer Patch-Updates manuell Digests auslesen — oder es bleibt liegen.
|
||||
- **Risiko:** CVE-Patches werden nicht eingespielt, weil "der laufende Stand ist stabil".
|
||||
- **Empfehlung:** Renovate Bot (self-hosted, gegen Gitea), Gitea-Actions-Runner. Renovate oeffnet PRs fuer Patch-/Minor-Updates; Major-Updates werden mit Labels separiert.
|
||||
- **Prioritaet:** Sollte zeitnah (oder Nice to have, je nach Schmerz)
|
||||
- **Aufwand:** M (Initial-Setup ist substantiell)
|
||||
- **Validierung:** Renovate hat erste PRs in Gitea geoeffnet, du mergst eines davon kontrolliert.
|
||||
|
||||
### F-13 · Keine OIDC-SSO fuer User-Apps
|
||||
|
||||
- **Kategorie:** Security / UX
|
||||
- **Fundstelle:** `security/authelia/configuration.yml`, `docs/SECRETS_MAP.md`
|
||||
- **Beobachtung:** Authelia kann OIDC, ist aber nur als ForwardAuth konfiguriert. Nextcloud, Immich, Grafana, Mealie laufen mit eigenen User-DBs.
|
||||
- **Risiko:** N getrennte Passwortspeicher, N getrennte 2FA-Setups, keine zentrale Sperrung bei Account-Kompromittierung. Familie hat keinen einfachen Onboarding-Pfad.
|
||||
- **Empfehlung:** OIDC-Provider in Authelia aktivieren, Nextcloud (via Plugin), Immich (nativer OIDC-Support), Grafana (nativer OIDC-Support) als Clients konfigurieren. Vaultwarden via OIDC-Bridge nur, wenn der Aufwand klar mehrwertig ist — sonst bewusst auslassen.
|
||||
- **Prioritaet:** Sollte zeitnah (groesster Hebel laut Executive)
|
||||
- **Aufwand:** L
|
||||
- **Validierung:** Familienkonto kann sich mit einem Login bei Nextcloud + Immich + Grafana anmelden.
|
||||
|
||||
### F-14 · Kein WAF / Bouncer vor oeffentlichen Apps
|
||||
|
||||
- **Kategorie:** Security
|
||||
- **Fundstelle:** `traefik/docker-compose.yml`, oeffentliche Hosts in `docs/REPO_MAP.md:127-152`
|
||||
- **Beobachtung:** Sechs oeffentliche Apps mit nativer Auth (vault, paperless, mealie, ntfy, git, immich, cloud) ohne IP-Bouncer. Authelia-Regulation greift nur fuer die ForwardAuth-Pfade; Apps mit eigener Auth bekommen den vollen Traffic.
|
||||
- **Risiko:** Credential-Stuffing-Bot-Wellen treffen die App selbst (Nextcloud, Immich) — Logs sind im Loki, aber kein Sperr-Mechanismus.
|
||||
- **Empfehlung:** CrowdSec als Bouncer fuer Traefik (`crowdsecurity/traefik-bouncer`). Nutzt Loki/Logs fuer Erkennung, sperrt IPs auf Traefik-Ebene, bevor sie die Apps treffen.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** M
|
||||
- **Validierung:** CrowdSec-Dashboard zeigt erste Sperren; Test-Brute-Force gegen `nextcloud.kaleschke.info` wird bei N Versuchen geblockt.
|
||||
|
||||
### F-15 · Healthchecks fehlen grossflaechig
|
||||
|
||||
- **Kategorie:** Docker / Operations
|
||||
- **Fundstelle:** Spot-checks: `apps/paperless/docker-compose.yml`, `apps/immich/docker-compose.yml`, `security/authelia/docker-compose.yml`, `traefik/docker-compose.yml` — keiner hat `healthcheck:`-Block.
|
||||
- **Beobachtung:** Restart-Policy ist ueberall `unless-stopped`, aber ohne Healthcheck kann Docker keinen Crash-Loop bei "Container laeuft, aber App tot" erkennen.
|
||||
- **Risiko:** Bei Soft-Failure (Postgres-Connection-Pool tot, Authelia haengt im Storage-Connect) merkst du nichts, weil Container "running" bleibt.
|
||||
- **Empfehlung:** Fuer Tier-1 (Traefik `wget /ping`, Authelia `/api/health`, PostgreSQL `pg_isready`, Komodo `wget /api/healthcheck`) Healthchecks ergaenzen. Fuer Tier-2 schrittweise.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** M (pro Stack 5–15 Min)
|
||||
- **Validierung:** `docker ps` zeigt `(healthy)` neben den Tier-1-Containern.
|
||||
|
||||
### F-16 · `infra/redis` als "shared" deklariert, faktisch nur Paperless
|
||||
|
||||
- **Kategorie:** Architektur-Konsistenz
|
||||
- **Fundstelle:** `infra/redis/docker-compose.yml`, `docs/SERVICE_CATALOG.md:31` ("shared Redis Cache")
|
||||
- **Beobachtung:** Immich, Nextcloud, Mealie haben jeweils eigene Redis-Instanzen. Authelia nutzt bewusst kein Redis (MASTER 13). Paperless nutzt es laut Compose. Effektiv "Paperless-Redis im Frack des shared-Caches".
|
||||
- **Risiko:** Niedrig. Aber: Wenn du `infra/redis` fuer etwas anderes wegnimmst, denkst du, es kostet Paperless was — und das waere der Fall.
|
||||
- **Empfehlung:** Doku-Update: SERVICE_CATALOG 31 praezisieren ("dediziertes Redis fuer Paperless; andere Stacks haben eigene Redis-Instanzen"). Architektur bleibt, nur Etikett ehrlich machen. Alternativ: in `apps/paperless/` als App-internes Netz konsolidieren wie Mealie.
|
||||
- **Prioritaet:** Nice to have
|
||||
- **Aufwand:** S (Doku) / M (Architektur)
|
||||
|
||||
### F-17 · Plex bleibt als Host-Net-Stack
|
||||
|
||||
- **Kategorie:** Security / Architektur
|
||||
- **Fundstelle:** `host-services/plex/docker-compose.yml`, `MASTER 7.4`
|
||||
- **Beobachtung:** Plex laeuft als Host-Net wegen Discovery/GDM. Dokumentierte Ausnahme.
|
||||
- **Risiko:** Plex hat hoehere Angriffsoberflaeche als Apps mit Traefik. Plex-Login wurde mehrfach Ziel von Account-Uebernahmen (Plex.tv-Auth-Issues 2024/25). Bei Plex.tv-Kompromittierung greift Authelia nicht — Plex authentifiziert gegen Plex.tv.
|
||||
- **Empfehlung:** Plex bewusst beibehalten (Doku stuetzt), aber: (a) "Remote Access" in Plex-UI deaktivieren, wenn nur lokal/Tailscale genutzt. (b) Plex-Server nicht in `frontend_net` (waere schaedlich) — bleibt Host-Net, korrekt.
|
||||
- **Prioritaet:** Nice to have
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** Plex `Remote Access` UI zeigt "disabled".
|
||||
|
||||
### F-18 · Nextcloud ohne ForwardAuth, ohne dedizierte Brute-Force-Doku
|
||||
|
||||
- **Kategorie:** Security
|
||||
- **Fundstelle:** `apps/nextcloud/docker-compose.yml`, `MASTER 13: Nextcloud-Entscheidung`
|
||||
- **Beobachtung:** Bewusste Ausnahme (WebDAV/CardDAV). In Nextcloud selbst sind Brute-Force-Schutz, 2FA-Pflicht und App-Passwords konfigurierbar, aber nicht im Repo dokumentiert.
|
||||
- **Risiko:** Familien-Konto mit schwachem Passwort + Nextcloud oeffentlich = direkter Pfad zu Dokumenten/Fotos.
|
||||
- **Empfehlung:** `apps/nextcloud/POST_INSTALL.md` mit Pflicht-Checkliste: Brute-Force-Plugin aktiv, 2FA-Provider TOTP installiert, Admin-Account hat 2FA, "Enforce 2FA for admin group" gesetzt. Optional: `OCC`-Befehle als Skript in `services/nextcloud-policy/`.
|
||||
- **Prioritaet:** Sollte zeitnah
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** Test-Login ohne 2FA als Admin schlaegt fehl.
|
||||
|
||||
### F-19 · Keine Container-Memory-Limits
|
||||
|
||||
- **Kategorie:** Docker / Hardware-Schutz
|
||||
- **Fundstelle:** Spot-checks aller Composes
|
||||
- **Beobachtung:** Keine `mem_limit:` oder `deploy.resources.limits` Sektion in Tier-1- oder Tier-2-Stacks.
|
||||
- **Risiko:** Bei Image-Bug oder Memory-Leak (z. B. Immich-ML, Paperless-OCR-Loop) kann ein Container den Host in OOM treiben. Posture-Check + Docker-Critical-Events sehen das nachher, aber praeventiver waere Container-Limit + Docker-OOM-Kill fuer den richtigen Prozess.
|
||||
- **Empfehlung:** Fuer Tier-1 (Postgres, Authelia, Traefik, Komodo) sanfte Limits setzen (z. B. Postgres 2 GB, Authelia 256 MB, Traefik 256 MB). Fuer Immich-ML-Container ein hartes Limit, das Verhungern verhindert.
|
||||
- **Prioritaet:** Nice to have
|
||||
- **Aufwand:** M
|
||||
- **Validierung:** `docker stats` zeigt `MEM USAGE / LIMIT` ungleich `unlimited`.
|
||||
|
||||
### F-20 · Paperless-DBPass weiter als Stack-ENV (dokumentierte Ausnahme)
|
||||
|
||||
- **Kategorie:** Secrets
|
||||
- **Fundstelle:** `MASTER 13: Secrets in Komodo Stacks`, `docs/SECRETS_MAP.md:25`
|
||||
- **Beobachtung:** Paperless unterstuetzt `_FILE` nicht fuer DB-Pass. Bewusste Ausnahme.
|
||||
- **Risiko:** Stack-ENV liegt in Komodo-DB (Mongo), nicht im Repo. Bei Komodo-Mongo-Backup-Luecke fehlt das Passwort beim Restore.
|
||||
- **Empfehlung:** Erweiterung der Disaster-Recovery-Doku: explizite Liste aller "Stack-ENV-only"-Secrets mit Zeiger, dass `komodo-mongo.archive.gz` fuer Restore zwingend ist, oder die ENV manuell vorgehalten werden muss (in Vaultwarden + externer Notiz).
|
||||
- **Prioritaet:** Nice to have
|
||||
- **Aufwand:** S
|
||||
- **Validierung:** DR-Doc Abschnitt "Stack-ENV-Werte" referenziert konkrete Restore-Pfade.
|
||||
|
||||
---
|
||||
|
||||
# D. Risiko-Matrix
|
||||
|
||||
| Risiko | Bereich | Wahrscheinlichkeit | Auswirkung | Prioritaet | Massnahme |
|
||||
|---|---|---|---|---|---|
|
||||
| Borg-Passphrase weg -> Restore unmoeglich | Backup | niedrig | katastrophal | P0 | F-02 analoge Sicherung |
|
||||
| Hetzner-Account-Verlust -> halbes 3-2-1 | Backup | niedrig-mittel | hoch | P0/P1 | F-03 Zweitziel |
|
||||
| AdGuard-Admin-Manipulation aus LAN | Security | niedrig | hoch (DNS-Hijack) | P0 | F-01 Bind auf Tailscale |
|
||||
| Operator-Pwd-Leak -> 2FA fehlt fuer Borg-UI/Code-Server | Security | mittel | hoch | P0 | F-04 2FA-ACL erweitern |
|
||||
| Komodo-Self-Bootstrap-Failure nach Totalausfall | DR | niedrig | hoch | P1 | F-09 Bootstrap-Datei in `services/` |
|
||||
| Authelia Repo↔Host Drift unbemerkt | GitOps/Security | mittel | mittel | P1 | F-10 Diff-Check |
|
||||
| Immich Silent Corruption -> kein Restore-Test belegt | Backup | niedrig | sehr hoch (Familien-Fotos) | P1 | F-11 Restore-Test |
|
||||
| Cert-Expiry unbemerkt -> Public Apps down | Operations | niedrig | mittel | P1 | F-08 Alert-Regel |
|
||||
| Nextcloud Brute-Force ohne Bouncer | Security | mittel | mittel-hoch | P1 | F-14 CrowdSec / F-18 Nextcloud-Haerten |
|
||||
| Image-Update-Stillstand -> CVE bleibt | Security | mittel | mittel | P1 | F-12 Renovate |
|
||||
| Hermes-Wartungsschuld | Wartbarkeit | hoch | niedrig | P1 | F-06 Entscheidung |
|
||||
| Repo-Altstaende ueberleben -> Doppel-Deploy | GitOps | mittel | niedrig | P1 | F-05 Cleanup |
|
||||
| OOM durch unlimitierte Container | Hardware | niedrig | mittel | P2 | F-19 mem_limit |
|
||||
| Healthcheck-Luecke -> Soft-Failure stumm | Operations | mittel | niedrig | P2 | F-15 Healthchecks |
|
||||
| Monitoring-Stack ohne Digest-Pin | Reproduzierbarkeit | niedrig | niedrig | P2 | F-07 Digests + Renovate |
|
||||
| Hardware-SPOF (kein zweiter Host) | Hardware | niedrig | sehr hoch | P3 | Cold-Standby / 2. Host |
|
||||
|
||||
---
|
||||
|
||||
# E. Zielarchitektur (realistisch fuer privates Homelab)
|
||||
|
||||
**Hardware**
|
||||
|
||||
- 1× Unraid-Host (bestehend) als Production. CPU mit AVX2/AVX-512 fuer Immich-ML. ≥ 32 GB RAM (fuer 2× Postgres + Immich-ML + Loki/Prometheus + 2 VMs).
|
||||
- 2× NVMe als BTRFS-RAID1-Cache, sobald Cache-Auslastung > 70 % (STORAGE_LAYOUT 15.3).
|
||||
- Parity-Disk ≥ groesste Daten-Disk.
|
||||
- USV mit USB-Steuerung (NUT-faehig: APC Back-UPS RS 700+, Eaton 3S, CyberPower CP1500EPFCLCD). Direkter Shutdown bei Power-Loss.
|
||||
- Optional: zweiter alter Mini-PC oder NUC als Cold-Standby mit Tailscale, der den letzten Komodo-Bootstrap + Gitea-Mirror tragen kann.
|
||||
|
||||
**Netzwerk**
|
||||
|
||||
- FritzBox (bestehend) als Router + NAT.
|
||||
- VLANs nur wenn IoT-WLAN dazukommt (FritzBox-Gast-WLAN reicht fuer Anfang).
|
||||
- DNS: AdGuard -> Unbound (bestehend). Admin-UI nur Tailscale.
|
||||
- Tailscale (bestehend): Operator-Pfad. Subnet-Router optional fuer LAN-Devices ueber Tailscale.
|
||||
|
||||
**Storage**
|
||||
|
||||
- Cache `only` fuer `appdata`, `system`, `domains` (bestehend STORAGE_LAYOUT 4).
|
||||
- Disk1 (XFS) fuer `services`, `documents`, `photos`, `backups`, `media`, `finance`, `projekte`.
|
||||
- Externe Wechselplatte (XFS) fuer Cold-Off-Site mit fester monatlicher Rotation.
|
||||
|
||||
**Ordnerstruktur (Repo)**
|
||||
|
||||
- Beibehalten. Nur Cleanup von Altstaenden (F-05). Naming `kebab-case`-Migration aus STORAGE_LAYOUT 6 schrittweise.
|
||||
|
||||
**Docker**
|
||||
|
||||
- Compose-only via Komodo (bestehend).
|
||||
- Digest-Pin fuer alle Images (F-07).
|
||||
- Healthchecks fuer Tier-1 (F-15).
|
||||
- Mem-Limits fuer Tier-1 + Immich-ML (F-19).
|
||||
- App-interne Netze fuer Stack-Isolation (bestehend).
|
||||
|
||||
**Reverse Proxy**
|
||||
|
||||
- Traefik v3 (bestehend), DNS-Challenge, Wildcard.
|
||||
- Dynamic Config nur fuer Middlewares, TLS, Dashboard (bestehend).
|
||||
- CrowdSec-Bouncer (F-14) fuer oeffentliche Apps.
|
||||
|
||||
**Auth**
|
||||
|
||||
- Authelia als ForwardAuth **und** OIDC-Provider (F-13).
|
||||
- Nextcloud, Immich, Grafana via OIDC.
|
||||
- 2FA-Pflicht fuer alle Operator-Dienste (F-04).
|
||||
- Komodo bewusste Ausnahme (bestehend).
|
||||
|
||||
**Backup**
|
||||
|
||||
- Borg lokal (`/mnt/user/backups/borg/`) + Borg Hetzner + Wechselplatte.
|
||||
- Pre-Dump-Hooks (bestehend).
|
||||
- Borg-Passphrase off-system analog (F-02).
|
||||
- Restore-Tests automatisiert (F-11 Immich, dann andere via CI).
|
||||
|
||||
**Monitoring**
|
||||
|
||||
- `monitoring/`-Stack als alleinige Quelle. Altstaende raus (F-05).
|
||||
- Family-View-Dashboard in Grafana (alles gruen, Backup-Frische, Cert-Tage).
|
||||
- Alerts ausgebaut (F-08).
|
||||
- Posture-Check + Docker-Critical-Events -> ntfy `homelab-alerts` (bestehend).
|
||||
|
||||
**Dokumentation**
|
||||
|
||||
- Aktuelle Doku-Tiefe halten.
|
||||
- `SERVICES_RECOVERY.md` und `STORAGE_LAYOUT.md` (Active) finalisieren.
|
||||
- Familien-/User-Onboarding-Doku als eigenes kleines Dokument.
|
||||
|
||||
**GitOps**
|
||||
|
||||
- Gitea + Komodo (bestehend).
|
||||
- GitHub-Push-Mirror (umgesetzt, bestaetigt durch MASTER 7.1).
|
||||
- Renovate-Bot gegen Gitea (F-12).
|
||||
- Optional: Staging-Branch + zweites Komodo-Ziel in Tailscale-VM (Phase 3).
|
||||
|
||||
**Restore**
|
||||
|
||||
- RESTORE_MATRIX bleibt fuehrend.
|
||||
- Restore-Lab unter `/mnt/user/backups/restore-lab/` (bestehend).
|
||||
- Immich-Restore als Luecke schliessen (F-11).
|
||||
- Komodo-Self-Bootstrap raus aus Komodo (F-09).
|
||||
|
||||
---
|
||||
|
||||
# F. Priorisierte Massnahmenliste
|
||||
|
||||
| # | Aufgabe | Warum | Kategorie | Prio | Aufwand | Risiko (bei Nicht-Tun) | Mehrwert | Abhaengigkeiten | Validierung |
|
||||
|---|---|---|---|---|---|---|---|---|---|
|
||||
| 1 | Borg-Passphrase analog sichern | DR-SPOF schliessen | Backup | P0 | S | katastrophal | DR-Sicherheit | — | Wert ohne Host abrufbar |
|
||||
| 2 | AdGuard-Admin auf Tailscale-IP binden | LAN-Angriffsflaeche | Security | P0 | S | hoch | LAN-IoT-Haertung | — | `ss -ltnp` zeigt nur Tailscale |
|
||||
| 3 | 2FA-ACL erweitern (borg, code, files, traefik) | Operator-Pwd-Leak | Security | P0 | S | hoch | 2FA-Coverage | Authelia-TOTP-Setup | Login erzwingt 2FA |
|
||||
| 4 | Altstaende `ops/grafana-influxdb`+`ops/loki` `git rm` | Repo-Hygiene, kein Re-Deploy | GitOps | P0 | S | niedrig | Klarheit | Tag setzen | Policy-Check clean |
|
||||
| 5 | Hermes 60-Tage-Deadline | Wartungsschuld | App | P1 | S/L | mittel | Komplexitaet raus | Operator-Entscheidung | Entweder produktiv oder weg |
|
||||
| 6 | Immich-Restore-Test einrichten | Groesster Datentopf ungeprueft | Backup | P1 | M | hoch | Restore-Vertrauen | Restore-Lab-Pfad | Smoke-Test-Report |
|
||||
| 7 | Renovate-Bot in Gitea | manuelle Digest-Pflege | Wartung | P1 | M | mittel | Update-Hygiene | Gitea-Runner | erste PR offen |
|
||||
| 8 | Alert-Regeln (Borg-Frische, Cert-Expiry) | Blind-Spot Operations | Monitoring | P1 | M | mittel | echte Alerts | Pushgateway o. textfile | Alert in Test |
|
||||
| 9 | Family-View-Dashboard Grafana | Morgens 30 s Check | Monitoring | P1 | M | niedrig | Uebersicht | Datasources stehen | Dashboard funktioniert |
|
||||
| 10 | Komodo-Self-Bootstrap als `services/komodo-bootstrap/` | Henne-Ei-Problem | GitOps/DR | P1 | M | mittel | sauberer Recovery-Pfad | Komodo-Stack-Doku | Bootstrap aus Repo allein moeglich |
|
||||
| 11 | Authelia-Drift-Diff-Check in posture-check | Repo↔Host Drift | GitOps | P1 | S | mittel | Drift-Detektion | posture-check-Erweiterung | neuer Check sichtbar |
|
||||
| 12 | Healthchecks Tier-1 | Soft-Failure-Erkennung | Docker | P1 | M | niedrig | Self-Healing-Trigger | — | `docker ps` zeigt `healthy` |
|
||||
| 13 | CrowdSec-Bouncer vor Traefik | oeffentliche Apps schuetzen | Security | P1 | M | mittel | Brute-Force-Stop | Traefik-Middleware | Test-IP wird geblockt |
|
||||
| 14 | Nextcloud-Haertung dokumentieren | Public App + native Auth | Security | P1 | S | mittel | App-Haertung | Plugin-Install | 2FA-erzwingt |
|
||||
| 15 | Authelia OIDC-Provider + Nextcloud/Immich/Grafana | SSO, Familien-Onboarding | Security/UX | P2 | L | niedrig | hoher Mehrwert | Authelia-OIDC-Setup | SSO-Login funktioniert |
|
||||
| 16 | Immich-Smartphone-Auto-Backup fuer Familie | Killer-App fuer Familie | App | P2 | S | niedrig | hoher Mehrwert | — | Familien-Foto in Immich |
|
||||
| 17 | Monitoring-Stack Digests + Renovate-Pin | Reproduzierbarkeit | GitOps | P2 | S | niedrig | konsistent | Renovate optional | `@sha256` an allen Images |
|
||||
| 18 | Mem-Limits Tier-1 + Immich-ML | OOM-Schutz | Hardware/Docker | P2 | M | niedrig | Schutz | — | `docker stats` zeigt Limits |
|
||||
| 19 | Off-Site-Zweitziel (rsync.net o. Wechselplatte) | Single-Provider | Backup | P2 | M | mittel | 3-2-1 echt | Borg-Config | beide Repos < 7d |
|
||||
| 20 | Staging-Branch + 2. Komodo-Ziel | Risiko-Aenderung testbar | GitOps | P3 | L | niedrig | Reife | 2. VM/Host | Deploy auf staging klappt |
|
||||
|
||||
---
|
||||
|
||||
# G. Refactoring-Plan (Sprints)
|
||||
|
||||
## Sprint 0 — Sicherheitsnetz und Ist-Zustand sichern (1 Tag)
|
||||
|
||||
- **Ziel:** Du kannst danach im schlimmsten Fall alles, was du jetzt aenderst, sicher zurueckrollen.
|
||||
- **Aufgaben:**
|
||||
- Git-Tag `audit-2026-05-25-baseline` auf `master` setzen und nach Gitea + GitHub-Mirror pushen.
|
||||
- Borg-Lauf manuell ausloesen ("freshen up"), Erfolg im Log dokumentieren.
|
||||
- Aktuellen Komodo-Mongo-Dump verifizieren (`mongorestore --dry-run`).
|
||||
- `docs/MIGRATION_LOG.md` Eintrag "Audit-Sprint-Start".
|
||||
- **Erfolgskriterium:** Tag pushed, Borg-Lauf gruen, Mongo-Dump verifiziert.
|
||||
- **Validierung:** `git fetch && git tag | grep audit-2026-05-25-baseline` und `ls /mnt/user/backups/borg/dumps/latest/` zeigt fresh.
|
||||
- **Rollback:** N/A (rein additiv).
|
||||
- **Risiko bei Nichtumsetzung:** Keine Notbremse fuer Sprint 1.
|
||||
|
||||
## Sprint 1 — Offensichtliche Risiken entschaerfen (1 Woche)
|
||||
|
||||
- **Ziel:** P0-Risiken weg, Repo-Hygiene wieder gruen.
|
||||
- **Aufgaben (in dieser Reihenfolge):**
|
||||
1. F-02 Borg-Passphrase analog sichern (off-system, kein Code-Change).
|
||||
2. F-01 AdGuard-Admin-Port auf Tailscale-IP — Edit `host-services/Adguard/docker-compose.yml:16`.
|
||||
3. F-04 Authelia ACL erweitern (`two_factor` fuer borg, code, files, traefik) — Edit `security/authelia/configuration.yml` + Host-Sync.
|
||||
4. F-05 Altstaende `ops/grafana-influxdb/`, `ops/loki/` entfernen — `git rm`, MIGRATION_LOG.
|
||||
5. Policy-Check-Warnings `SEC001` (ddns-updater, scrutiny) aufraeumen.
|
||||
- **Erfolgskriterium:** Policy-Check 0 Warnings fuer SEC001, AdGuard-Admin nur via Tailscale, 2FA-Login auf borg.kaleschke.info.
|
||||
- **Validierung:** Policy-Check-Report; Browser-Test mit/ohne 2FA-Cookie.
|
||||
- **Rollback:** Commit-Revert pro Block.
|
||||
|
||||
## Sprint 2 — GitOps-Robustheit (1–2 Wochen)
|
||||
|
||||
- **Ziel:** Self-Bootstrap-Problem entschaerft, Drift-Detektion automatisiert.
|
||||
- **Aufgaben:**
|
||||
1. F-09 Komodo-Bootstrap-Compose nach `services/komodo-bootstrap/` extrahieren + dokumentierter Standalone-Restore-Pfad.
|
||||
2. F-10 Authelia-Drift-Diff in posture-check ergaenzen.
|
||||
3. F-11 Immich-Restore-Test einrichten (analog zu vaultwarden/gitea/paperless).
|
||||
4. F-06 Hermes-Entscheidung mit 60-Tage-Deadline schriftlich.
|
||||
- **Erfolgskriterium:** Komodo laesst sich aus Repo allein wiederherstellen. Posture-Check zeigt `authelia_config_drift: false`. Immich-Restore-Report unter `/mnt/user/backups/restore-reports/`.
|
||||
- **Validierung:** Trockenversuch (Komodo-Container stoppen, `docker compose up -d` aus `services/komodo-bootstrap/`).
|
||||
- **Rollback:** Bootstrap-Verzeichnis loeschen, Komodo-Self-Stack wie vorher.
|
||||
|
||||
## Sprint 3 — Backup & Restore belastbar machen (2–3 Wochen)
|
||||
|
||||
- **Ziel:** 3-2-1 echt, Restore-Tests breiter, Stack-ENV im DR-Pfad.
|
||||
- **Aufgaben:**
|
||||
1. F-03 Zweitziel: Wechselplatten-Rotation dokumentieren ODER zweites Borg-Repo (rsync.net / BorgBase EU2).
|
||||
2. F-20 Stack-ENV-Liste in DR-Doc explizit machen (Restore-Reihenfolge).
|
||||
3. Borg-Verifikation Cron fuer `borg check --repository-only` weekly (STORAGE_LAYOUT 8.4).
|
||||
4. Quartalsweise End-to-End-Restore-Drill in Schedule aufnehmen.
|
||||
- **Erfolgskriterium:** Beide Off-Site-Ziele < 7 Tage alt; DR-Doc enthaelt "ENV-Restore-Reihenfolge".
|
||||
- **Validierung:** `borg list` gegen beide Repos.
|
||||
|
||||
## Sprint 4 — Monitoring & Alerting ausbauen (2 Wochen)
|
||||
|
||||
- **Ziel:** Sichtbarkeit auf das, was wirklich weh tut.
|
||||
- **Aufgaben:**
|
||||
1. F-08 Alert-Regeln: `BorgArchiveStale`, `TLSCertExpiryNear`, `ContainerDown`, `PostgresConnSaturation`.
|
||||
2. F-15 Healthchecks fuer Traefik, Authelia, Postgres, Komodo, Gitea.
|
||||
3. F-07 Digest-Pin in `monitoring/docker-compose.yml`.
|
||||
4. Family-View-Dashboard in Grafana (1 Panel: Service-Up, 1 Panel: Backup-Frische, 1 Panel: Cert-Tage, 1 Panel: Disk-Fuellung).
|
||||
- **Erfolgskriterium:** Family-View zeigt alles gruen; Cert-Alert feuert in Test (Datum vorgespult).
|
||||
- **Validierung:** Dashboard sichtbar unter `monitoring.kaleschke.info/d/family-view`.
|
||||
|
||||
## Sprint 5 — Auth-Konsolidierung & Frontdoor-Haertung (3–4 Wochen)
|
||||
|
||||
- **Ziel:** SSO fuer die Familie, Brute-Force-Bouncer vor oeffentlichen Apps.
|
||||
- **Aufgaben:**
|
||||
1. F-13 Authelia OIDC-Provider aktivieren.
|
||||
2. Nextcloud OIDC-Plugin + Test-Login.
|
||||
3. Immich OIDC + Test-Login.
|
||||
4. Grafana OIDC + Test-Login.
|
||||
5. F-14 CrowdSec-Bouncer vor Traefik.
|
||||
6. F-18 Nextcloud-Haertung-Dokument + 2FA-Pflicht.
|
||||
- **Erfolgskriterium:** Familien-Konto loggt sich mit einem Login bei drei Apps ein; CrowdSec sperrt Test-IP nach N fehlerhaften Versuchen.
|
||||
- **Validierung:** OIDC-Sequenz im Browser ohne Eingabe-Wiederholung; CrowdSec-Dashboard zeigt Sperre.
|
||||
|
||||
## Sprint 6 — Automatisierung und Nerd-Level (laufend)
|
||||
|
||||
- **Ziel:** Image-Update-Pipeline, optional Staging.
|
||||
- **Aufgaben:**
|
||||
1. F-12 Renovate-Bot gegen Gitea.
|
||||
2. F-19 Mem-Limits Tier-1.
|
||||
3. Restore-Test-CI via Gitea Actions (P3).
|
||||
4. Optional: Staging-Branch + zweites Komodo-Ziel in Tailscale-VM (P3).
|
||||
5. Optional: Firefly III / Actual Budget fuer `/mnt/user/finance`.
|
||||
- **Erfolgskriterium:** Renovate-PRs erscheinen woechentlich; mindestens ein automatisches Patch-Update gemerged.
|
||||
|
||||
---
|
||||
|
||||
# H. Fehlende Informationen
|
||||
|
||||
> Nur, was den Audit konkret schaerfer machen wuerde.
|
||||
|
||||
| Frage | Warum | Bereich | Kommando / Datei |
|
||||
|---|---|---|---|
|
||||
| CPU-Modell, RAM-Groesse, Mainboard | Hardware-Bewertung, OOM-Risiko, Immich-ML-Eignung, AVX-Verfuegbarkeit | Hardware | `cat /proc/cpuinfo \| grep -E 'model name\|flags'`, `free -h`, `dmidecode -t baseboard \| head -20` |
|
||||
| USV vorhanden? Modell? | DR-Beurteilung Power-Loss, Shutdown-Pfad | Hardware/DR | physische Sichtpruefung; `apcaccess` falls APC mit NUT |
|
||||
| Stromverbrauch idle / Last | Betriebskosten, Sizing | Hardware | Smartmeter / Tibber-API |
|
||||
| NIC-Speed (1 GbE? 2.5 GbE?) | Backup-Durchsatz, Plex-Streaming | Netzwerk | `ip -br link`, `ethtool eth0` |
|
||||
| Disk-Inventar (Anzahl, Modelle, Alter) | Storage-Health, Replacement-Plan | Storage | `lsblk -o NAME,SIZE,MODEL,SERIAL`, Scrutiny-UI |
|
||||
| Aktueller Cache-Fuellstand | Wann zweite NVMe? | Storage | `df -h /mnt/cache` |
|
||||
| FritzBox-Modell + Firmware | Net-Sicherheit, VLAN-Faehigkeit | Netzwerk | FritzBox-UI / `fritzconnection` |
|
||||
| Tatsaechlich genutzte Plex- vs. ungenutzte App | Konsolidierungs-Belege | App-Landschaft | Plex-Server-Logs, ggf. Glances-Container-CPU pro Stack |
|
||||
| Existiert `/mnt/user/finance/`-Share schon? | Ist Firefly-Vorbereitung trivial? | Storage | `ls /mnt/user/finance/` |
|
||||
| Authelia Live-User-DB-Tiefe (Anzahl User, 2FA-Status) | 2FA-Coverage-Bewertung | Security | `cat /mnt/user/appdata/authelia/config/users_database.yml` (nur Strukturansicht, keine Hashes hier zitieren) |
|
||||
| Komodo-Mongo-Dump letzter Integrity-Check | F-09-Vorbereitung | Backup | `mongorestore --dry-run --archive=komodo-mongo.archive.gz --gzip` |
|
||||
| Aktuelle Cert-Restlaufzeit | F-08-Test-Vorbereitung | Operations | `openssl s_client -connect git.kaleschke.info:443 -servername git.kaleschke.info < /dev/null \| openssl x509 -noout -dates` |
|
||||
|
||||
---
|
||||
|
||||
# I. Pruefkommandos (Linux / Unraid / Docker / Windows)
|
||||
|
||||
> Strukturiert nach Bereich. Sicher zum Ausfuehren am Host.
|
||||
|
||||
### Hardware
|
||||
|
||||
```bash
|
||||
# CPU + Flags (AVX fuer Immich-ML)
|
||||
cat /proc/cpuinfo | awk '/model name|flags/ {print; if(/flags/) exit}'
|
||||
|
||||
# RAM
|
||||
free -h
|
||||
dmidecode -t memory | grep -E "Size|Speed" | head -20
|
||||
|
||||
# Mainboard
|
||||
dmidecode -t baseboard | head -20
|
||||
|
||||
# PCI / SATA / NVMe
|
||||
lspci
|
||||
nvme list
|
||||
lsblk -o NAME,SIZE,MODEL,SERIAL,FSTYPE,MOUNTPOINT,VENDOR
|
||||
|
||||
# SMART
|
||||
smartctl -a /dev/nvme0n1 | head -40
|
||||
smartctl -a /dev/sdb | head -40
|
||||
|
||||
# Stromverbrauch (Unraid Plugin oder ipmitool falls IPMI)
|
||||
sensors | head -30
|
||||
```
|
||||
|
||||
### Filesystem / Storage / Mounts
|
||||
|
||||
```bash
|
||||
# Filesystem-Typen (Hard Rule 12.1)
|
||||
findmnt -no FSTYPE /mnt/cache /mnt/disk1 /boot
|
||||
mount | grep -E "ntfs3|fuseblk" # darf leer sein
|
||||
|
||||
# Share-Settings
|
||||
ls -la /boot/config/shares/
|
||||
|
||||
# Cache-Fuellstand
|
||||
df -h /mnt/cache /mnt/disk1 /mnt/user
|
||||
du -sh /mnt/user/appdata/* | sort -hr | head -20
|
||||
```
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
# Container-Inventur
|
||||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | sort
|
||||
docker ps -a --filter "status=exited" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
|
||||
|
||||
# Netzwerke
|
||||
docker network ls
|
||||
docker network inspect frontend_net | jq '.[0].Containers | keys'
|
||||
docker network inspect backend_net | jq '.[0].Internal'
|
||||
|
||||
# Volumes ohne Container (Waisen)
|
||||
docker volume ls -qf dangling=true
|
||||
|
||||
# Effektive Ports
|
||||
ss -ltnp | sort -k4
|
||||
|
||||
# Healthchecks
|
||||
docker ps --format "{{.Names}}\t{{.Status}}" | grep -E "healthy|unhealthy|starting"
|
||||
```
|
||||
|
||||
### Security
|
||||
|
||||
```bash
|
||||
# Privileged-Container und Docker-Socket-Mounts
|
||||
for c in $(docker ps -q); do
|
||||
docker inspect "$c" --format '{{.Name}}: priv={{.HostConfig.Privileged}}; sock={{range .HostConfig.Binds}}{{println .}}{{end}}'
|
||||
done | grep -E "priv=true|docker.sock"
|
||||
|
||||
# Direkte Host-Ports
|
||||
docker ps --format "{{.Names}}: {{.Ports}}" | grep -v "^[^:]*: $"
|
||||
|
||||
# Secret-Datei-Rechte
|
||||
ls -la /mnt/user/appdata/secrets/
|
||||
stat -c "%a %n" /mnt/user/appdata/secrets/*.txt
|
||||
```
|
||||
|
||||
### Backup / Restore
|
||||
|
||||
```bash
|
||||
# Borg-Frische
|
||||
ls -lat /mnt/user/backups/borg/dumps/latest/ | head
|
||||
find /mnt/user/backups/borg/dumps/latest -mmin +1440 -type f # aelter 24h
|
||||
|
||||
# Borg-Repo (Passphrase per File)
|
||||
export BORG_PASSPHRASE=$(cat /mnt/user/appdata/secrets/borg_repo_passphrase.txt)
|
||||
borg list ssh://... --short | tail -5
|
||||
borg info ssh://... ::Taegliche-Sicherung-2026-05-25T05:52:44.157
|
||||
|
||||
# Posture-Check
|
||||
cat /mnt/user/services/posture-check/last.json | jq '.warning_count, .critical_count'
|
||||
```
|
||||
|
||||
### Netzwerk / DNS
|
||||
|
||||
```bash
|
||||
# Tailscale
|
||||
tailscale status
|
||||
|
||||
# DNS auf AdGuard testen
|
||||
dig @127.0.0.1 git.kaleschke.info
|
||||
dig @127.0.0.1 example.com # Unbound-Recursion
|
||||
|
||||
# Cert-Restlaufzeit
|
||||
for h in vault git immich cloud paperless mealie ntfy; do
|
||||
echo -n "$h.kaleschke.info: "
|
||||
openssl s_client -connect ${h}.kaleschke.info:443 -servername ${h}.kaleschke.info </dev/null 2>/dev/null \
|
||||
| openssl x509 -noout -dates 2>/dev/null
|
||||
done
|
||||
```
|
||||
|
||||
### GitOps-Konsistenz
|
||||
|
||||
```bash
|
||||
# Komodo Stack-Workspace vs. Repo
|
||||
cd /mnt/user/services/stacks/<stackname>
|
||||
git rev-parse HEAD
|
||||
git status --short
|
||||
|
||||
# Webhook-Liveness
|
||||
docker logs komodo-core 2>&1 | grep -i "webhook\|deploy" | tail -20
|
||||
```
|
||||
|
||||
### Windows (lokal)
|
||||
|
||||
```powershell
|
||||
# Repo-Status
|
||||
git status --short
|
||||
git fetch origin
|
||||
git log origin/master..HEAD --oneline # ungepushte Commits
|
||||
git log HEAD..origin/master --oneline # ungepullte Commits
|
||||
|
||||
# Policy-Check
|
||||
.\ops\policy-checks\check_repo.ps1
|
||||
|
||||
# Restore-Freshness
|
||||
.\ops\restore-tests\check-restore-freshness.ps1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# J. Community- / Best-Practice-Abgleich
|
||||
|
||||
> Nur fuer die Architekturentscheidungen, bei denen der Markt eindeutig ist oder Gegenpositionen relevant sind.
|
||||
|
||||
| Entscheidung | Markt-Best-Practice | Stuetzende Quellen | Bewertung |
|
||||
|---|---|---|---|
|
||||
| Traefik mit Docker-Labels statt File-Provider | Standard in Selfhosted (siehe `awesome-selfhosted-docker`, Smarthome-Beginner Templates) | Traefik-Doc v3 docs.traefik.io/providers/docker | passt zu MASTER 13 (Wechsel 2026-03-28) |
|
||||
| DNS-Challenge mit Cloudflare statt HTTP-01 | Standard fuer Wildcard und reduzierte Angriffsflaeche | acme.sh / lego docs | passt, korrekt |
|
||||
| Authelia ForwardAuth statt Authentik | Authelia ist leichtgewichtiger, Authentik maechtiger; beide valide | r/selfhosted-Konsens 2024-25 | Authelia richtig fuer Single-Family-Setup |
|
||||
| Authelia ohne Redis-Session-Backend | Markt-Standard ist mit Redis; deine Vereinfachung ist begruendet (MASTER 13 2026-05-04) | Authelia-Doc | Trade-off klar; Bewertung: vertretbar fuer Homelab |
|
||||
| Komodo statt Portainer/Dockge | Komodo ist neuer (2024), Dockge etabliert, Portainer kommerziell | Selfh.st 2025 Comparison | Komodo legitim, mehr GitOps-nativ als Dockge |
|
||||
| Borg statt Restic/Kopia | Borg ist klassische Wahl fuer Linux-Backup mit Deduplikation; Kopia/Restic gewinnen mit Multi-Backend | r/datahoarder, ServeTheHome 2024 | Borg passt zu Unraid-Stack; bewusste Vereinfachung |
|
||||
| Glance statt Homepage als Single-Dashboard | beide auf Augenhoehe; Homepage etablierter, Glance moderner, schneller, mit Live-Widgets | github.com/glanceapp/glance vs. github.com/gethomepage/homepage | Glance legitim; Bewertung: deine Wahl ist verteidigbar |
|
||||
| Immich nicht hinter Authelia ForwardAuth | offizielle Immich-Doku raet bei nativer App-Auth davon ab, weil Sync-Clients OIDC oder direkte Auth brauchen | immich.app/docs/administration/reverse-proxy | korrekt; OIDC spaeter (F-13) ist der Weg |
|
||||
| Nextcloud klassisch statt AIO | NC-AIO ist offizielle Empfehlung fuer Neuaufbau, klassisch hat mehr Flexibilitaet fuer GitOps | NC-Blog 2024 | bewusste Ausnahme MASTER 13; vertretbar, da GitOps-Anbindung wichtiger |
|
||||
| Single-Host + Borg statt Proxmox-Cluster + ZFS-Send | fuer Familien-Homelab ist Cluster Overkill | r/homelab, LTT-Forum | Single-Host korrekt; Cold-Standby (Sprint 6) ist die richtige naechste Stufe |
|
||||
| AdGuard + Unbound statt Pi-hole | aequivalent; AdGuard hat moderne UI, Unbound recursion | gowri/networkchuck Tutorials 2024 | passt |
|
||||
| Posture-Check als Skript statt Goss/InSpec | fuer Single-Host pragmatisch | Goss ist maechtiger, aber Overkill | Skript-Loesung legitim |
|
||||
| Renovate gegen Gitea | mehrere Erfahrungsberichte in Gitea-Issues + Renovate-Docs | docs.renovatebot.com/modules/platform/gitea/ | Standard-Pfad |
|
||||
| CrowdSec vor Traefik | starker Trend 2024-25 in Selfhosted-Community | crowdsec.net/blog, Marius-Hosting-Tutorials | sinnvolle Haertung |
|
||||
|
||||
**Gegenpositionen, die du kennen solltest:**
|
||||
|
||||
- **"Authelia OIDC ist kompliziert, lieber Authentik."** Korrekt, wenn du auch B2B-SAML brauchst. Fuer reine Familien-OIDC ist Authelia leichter wartbar.
|
||||
- **"CrowdSec laedt zentrale Reputation-Listen -> Privacy-Bedenken."** Stimmt, du kannst Local-Only-Mode fahren. Fuer Homelab egal.
|
||||
- **"Renovate-Bot erzeugt Laerm."** Mit Group/Schedule-Rules zaehmbar. Wert > Laerm.
|
||||
- **"Komodo ist zu jung."** Gegenargument: du benutzt es seit Q1/2026 produktiv, Major-Inzidenz war beherrschbar. Der Wechsel zurueck zu Portainer/Dockge waere hoehere Kosten als der Reifegrad-Nachteil.
|
||||
|
||||
---
|
||||
|
||||
# K. Endziel — "Nerd-Level Homelab"
|
||||
|
||||
So sieht dein Homelab aus, wenn es wirklich auf Senior-Level ist:
|
||||
|
||||
**Betrieb im Alltag**
|
||||
|
||||
- Morgens 30 Sekunden auf `monitoring.kaleschke.info`: Family-View zeigt 7 Tier-1-Services gruen, Backup-Job in der Nacht hat 100 % Files erfasst, alle Certs > 30 Tage, Disk < 80 %.
|
||||
- Push-Benachrichtigung auf dem Handy nur, wenn wirklich etwas brennt (Posture-Check critical, Borg > 30 h, Endpoint down ≥ 8 Min, Cert < 14 Tage).
|
||||
- Familienmitglieder loggen sich mit einem Login bei Nextcloud, Immich, Mealie ein. 2FA per TOTP-App, kein App-by-App-Passwortzettel mehr.
|
||||
|
||||
**Updates**
|
||||
|
||||
- Renovate oeffnet woechentlich 5–10 Pull-Requests in Gitea fuer Patch-Versionen. Du siehst sie im Web-UI, pruefst Release Notes, klickst Merge. Komodo deployt automatisch via Webhook. Smoke-Test in der naechsten Glance-Seite.
|
||||
- Major-Updates kommen separat mit Label `major`, behandelst du in einem geplanten Slot mit Restore-Snapshot davor.
|
||||
|
||||
**Backups**
|
||||
|
||||
- Borg lokal alle 6 h, Borg Hetzner taeglich, Wechselplatte monatlich. Borg-Passphrase auf Papier im Bankschliessfach. Alle drei Ziele juenger als 36 h Alert-Schwelle.
|
||||
- Pre-Dump-Hooks erzeugen 15 konsistente Dump-Artefakte pro Lauf, automatische Posture-Check-Vor-Hook bricht Backup ab, wenn FS oder Mount sich veraendert haben.
|
||||
|
||||
**Restore**
|
||||
|
||||
- Monatlicher Mini-Restore-Test fuer Vaultwarden/Gitea/Paperless/Immich nach `/mnt/user/backups/restore-lab/<dienst>/` laeuft automatisiert per Gitea Actions, Erfolgs-Report landet als Datei + ntfy-Info.
|
||||
- Quartalsweise End-to-End-Drill: ein kompletter Stack restauriert, App startet, Smoke-Test passt, Doku validiert. Komodo-Bootstrap-Pfad ist getestet.
|
||||
- Im Ernstfall folgst du `docs/DISASTER_RECOVERY.md` Phase 0–5 und bist nach < 8 h wieder im Vollbetrieb. Repo-Bootstrap aus GitHub-Mirror, Stacks in Stufen 1–5, Verifikation pro Stufe.
|
||||
|
||||
**Monitoring**
|
||||
|
||||
- Prometheus + Loki + Grafana + Alertmanager-ntfy-Bridge. ~15 Alert-Regeln, alle in `alerts.yml` versioniert.
|
||||
- Family-View, Host-Overview, Containers+Logs, Traefik-Standalone, Backup-Frische, Cert-Tage. Sechs Dashboards mehr braucht keine Familie.
|
||||
- Loki sammelt 30 Tage Logs aus allen Containern via Promtail. cAdvisor + node-exporter liefern Container- und Host-Metriken. Blackbox testet oeffentliche Endpoints alle 60 s.
|
||||
|
||||
**Security**
|
||||
|
||||
- Authelia OIDC fuer Nextcloud, Immich, Grafana, Mealie. ForwardAuth fuer Operator-UIs mit 2FA-Pflicht ab Tier-2.
|
||||
- CrowdSec sperrt Brute-Force-IPs auf Traefik-Ebene bevor sie die Apps treffen.
|
||||
- AdGuard-Admin nur via Tailscale. Operator-Pfad ausschliesslich Tailscale.
|
||||
- Authelia-Repo-Baseline und Host-Config sind per Diff-Check im posture-check abgesichert.
|
||||
- Secrets-Mounts mode 600, Borg-Passphrase analog.
|
||||
|
||||
**Dokumentation**
|
||||
|
||||
- SERVICE_CATALOG, RESTORE_MATRIX, DISASTER_RECOVERY, STORAGE_LAYOUT, SECRETS_MAP, WORKFLOW, GITOPS_DRIFT_RUNBOOK, ALERTING_MAP, HOMELAB_ARCHITECTURE_MASTER bleiben aktuelle Single-Source-of-Truth.
|
||||
- `services/komodo-bootstrap/` loest das Henne-Ei. `SERVICES_RECOVERY.md` ist final, nicht Draft.
|
||||
- Familien-Onboarding-Doku als Markdown: "So nutzt du Nextcloud-Web", "So aktivierst du Immich-Foto-Backup auf dem Handy", "So loggst du dich neu per 2FA ein".
|
||||
|
||||
**Taegliche Nutzung**
|
||||
|
||||
- Familie scannt Briefe per ASN-Barcode in `scans_inbox/`, Paperless tagged via paperless-gpt automatisch, alles durchsuchbar.
|
||||
- Immich erfasst Smartphone-Fotos aller Familienmitglieder automatisch, Familie blaettert per Web/App, Tagging per ML.
|
||||
- Nextcloud traegt Kalender, Kontakte, geteilte Familienordner per WebDAV/CardDAV — kein Google/Apple-Lock-In.
|
||||
- Mealie speichert Rezepte, Einkaufsliste auf dem Handy.
|
||||
- Vaultwarden ist der einzige Passwort-Tresor der Familie; Familien-Organisation aktiv.
|
||||
- Plex streamt Heim-Medien an alle Endgeraete.
|
||||
- ntfy schickt dir Vorfaelle aufs Handy — und sonst nichts.
|
||||
- Optional: Firefly III fuer die Familien-Finanzen, Ecowitt-Wetter-Dashboard, Home-Assistant-Automationen fuer Strom-Eigenverbrauch.
|
||||
|
||||
**Was bewusst weggelassen ist**
|
||||
|
||||
- Kein Kubernetes. Komodo + Compose reicht.
|
||||
- Kein zweiter Medienserver neben Plex (Jellyfin-Entscheidung 2026-05-25).
|
||||
- Kein zweites Dashboard neben Glance (Homepage-Entscheidung 2026-05-25).
|
||||
- Kein Uptime-Kuma neben Blackbox (Entscheidung 2026-05-25).
|
||||
- Kein Hermes-Agent, wenn er bis 2026-07-25 keinen klaren Alltagsnutzen liefert.
|
||||
- Kein BentoPDF/paperless-gpt 24/7, wenn nicht aktiv genutzt.
|
||||
- Kein Self-Stack-Komodo (durch `services/komodo-bootstrap/` ersetzt).
|
||||
|
||||
---
|
||||
|
||||
## Schlussbemerkung
|
||||
|
||||
Das Setup ist naeher an Senior-Reife als an Bastel-Niveau. Der groesste Hebel der naechsten drei Monate ist **Konsolidieren statt erweitern** (Hermes-Entscheidung, Altstaende raus, Auth-SSO, Off-Site-Diversitaet), kombiniert mit der einen Aktivierung, die das Setup vom Operator-Tool zum **Familien-Tool** macht: Immich-Smartphone-Backup fuer alle.
|
||||
|
||||
Das vorhandene 2026-05-23-Audit hat die richtigen Sprintziele bereits identifiziert. Diese externe Audit-Sicht ergaenzt:
|
||||
|
||||
- **2FA-Pflicht auf Tier-1-Operator-UIs** (F-04) — fehlt in der Bewertung 2026-05-23 in dieser Klarheit.
|
||||
- **Healthcheck-Luecke** (F-15) und **fehlende Mem-Limits** (F-19) — operative Detail-Findings, die in der strategischen Bewertung nicht auftauchen.
|
||||
- **Komodo-Self-Bootstrap als konkreter Code-Vorschlag** (F-09) statt nur als Risiko-Erwaehnung.
|
||||
- **Authelia-Drift-Detection automatisieren** (F-10) statt nur "manuell merge".
|
||||
- **Monitoring-Stack ohne Digest-Pin** (F-07) — Inkonsistenz mit der eigenen Image-Pinning-Disziplin.
|
||||
- **`infra/redis` ist faktisch nicht shared** (F-16) — Etikett-Realitaet-Drift.
|
||||
- **Alert-Regeln deutlich zu duenn** (F-08) — Sichtbarkeitsluecken bei Cert/Borg/Container-Down.
|
||||
|
||||
Wenn Sprint 1–3 in 4–6 Wochen sitzen, bist du auf einer 1-Note. Wenn dann Sprint 4–5 in weiteren 6–8 Wochen kommen, hat die Familie ein echtes Self-Hosting-System, kein "Container-Sammlung im Keller". Das ist der Unterschied, den der Audit-Auftrag adressiert.
|
||||
@@ -0,0 +1,136 @@
|
||||
# Audit TODO 2026-05-25
|
||||
|
||||
Quelle: `docs/AUDIT_2026-05-25.md`
|
||||
|
||||
Status: Arbeitsliste fuer die Umsetzung. Authelia-2FA/OIDC, CrowdSec und Nextcloud-2FA-Haertung bleiben ganz hinten und werden bewusst nicht in diesem Audit-Zyklus angefasst.
|
||||
|
||||
## Leitplanken
|
||||
|
||||
- Authelia-2FA-ACL, Authelia-OIDC und CrowdSec werden in diesem Audit-Zyklus **nicht** umgesetzt (Operator-Vorgabe 2026-05-26).
|
||||
- Keine Live-riskanten Bind-/Port-Aenderungen ohne vorher erfasste Host-Werte, insbesondere Tailscale-IP.
|
||||
- Hermes-Agent ist geparkt, nicht entfernt; Review-Deadline 2026-07-25.
|
||||
- USV-Anschaffung ist verschoben; Power-Loss-Risiko ist als Operator-Entscheidung 2026-05-26 bewusst akzeptiert.
|
||||
- Borg-Passphrase ist offline gesichert (bestaetigt 2026-05-26).
|
||||
- H:/ ist evaluiert als zweite lokale Nearline-Kopie, nicht als Offsite-Ersatz (siehe `docs/CAPACITY_AND_LIFECYCLE.md`).
|
||||
- Familien-Einladung ist fuer das Wochenende **nach** Erreichen des finalen Stands geplant; Family-Onboarding muss familienverstaendlich werden, nicht technisch.
|
||||
- Jede produktive Aenderung bekommt Validierung und Rollback-Hinweis.
|
||||
|
||||
## Naechster Startpunkt 2026-05-26
|
||||
|
||||
Kontext bewusst gesichert, bevor weitere Live-Aenderungen passieren:
|
||||
|
||||
1. Host-Schedule fuer Gitea-Bundles und Restore-Freshness pruefen.
|
||||
2. FRITZ!Box-Portfreigaben (UI) gegen Repo-Soll abgleichen (`443/tcp` + `222/tcp`).
|
||||
3. H:/ Pull-Workflow festlegen.
|
||||
4. Family-Onboarding-Doku familienverstaendlich umarbeiten, vor der Wochenend-Einladung.
|
||||
5. Authelia 2FA/OIDC und CrowdSec weiterhin nicht anfassen; bleibt bewusst der letzte Block.
|
||||
|
||||
## Sprint 0 - Inventar und Baseline
|
||||
|
||||
| Status | Aufgabe | Ergebnis |
|
||||
|---|---|---|
|
||||
| erledigt | Hardware-Inventar ausfuellen | CPU, RAM, Mainboard, BIOS, NIC, Controller, Disks, SMART und Capacity-Baseline erfasst; USV ist als nicht validiert dokumentiert |
|
||||
| erledigt | Netzwerk-Inventar ausfuellen | Host-IP, Gateway, Tailscale-IP, AdGuard-Bind und FRITZ!Box-Baseline (7590, FRITZ!OS 8.21, Telekom DSL 87/36, 36 Geraete, Gast-WLAN inaktiv, Ausfallschutz inaktiv, 2 Portfreigaben aktiv) erfasst; IPv6 und FRITZ!OS-Update bleiben Operator-Folgeaufgaben |
|
||||
| erledigt (Baseline) | Externe Abhaengigkeiten dokumentieren | `docs/EXTERNAL_DEPENDENCIES.md` enthaelt bekannte Provider, Kritikalitaet, Ausfallplaene; Account-Recovery-Codes/Zahlungswege bleiben Off-Repo-Operatorcheck |
|
||||
| erledigt (Baseline) | Services-Recovery-Pfade beschreiben | `docs/SERVICES_RECOVERY.md` enthaelt Gitea-/Komodo-/Secrets-Sonderpfade; Gitea-Bundle-/Mirror-Mechanik bleibt als Umsetzungsentscheidung offen |
|
||||
| erledigt | Baseline-Tag setzen | `audit-2026-05-25-baseline` ist lokal und remote vorhanden |
|
||||
| erledigt | Policy-Check neu ausfuehren | SEC001-Warnings aus altem Report sind nicht mehr aktuell |
|
||||
|
||||
## Sprint 1 - Nicht-kontroverse Sicherheits- und Repo-Hygiene
|
||||
|
||||
| Status | Aufgabe | Ergebnis |
|
||||
|---|---|---|
|
||||
| erledigt | Borg-Passphrase analog sichern | Operator bestaetigt am 2026-05-26: Passphrase ist offline gesichert und ohne Host/Vaultwarden wiederherstellbar |
|
||||
| erledigt (repo) | AdGuard Admin-Bind vorbereiten | Tailscale-IP `100.80.98.33` erfasst, Compose-Soll geaendert |
|
||||
| erledigt | AdGuard Admin-Port auf Tailscale-IP binden | Live validiert: `ss -ltnp` zeigt `100.80.98.33:8082`, DNS auf Port 53 funktioniert, LAN-Zugriff auf `192.168.178.58:8082` schlaegt fehl |
|
||||
| erledigt | Alte Monitoring-Verzeichnisse entfernen | `ops/grafana-influxdb/` und `ops/loki/` sind aus dem aktiven Repo entfernt; Rollback erfolgt ueber Git-Historie |
|
||||
| erledigt | Komodo/Gitea-Restdrift bereinigen | alter Komodo-Stack `grafana` ist inert und ohne Repo-Pfad/Webhook; Gitea-Hook `35` und `komodo`-Self-Hook `11` sind inaktiv; aktive Gitea-Hooks haben keine Fehlstatus |
|
||||
| erledigt | Policy-Warnings triagieren | Plex Host-Netz und digest-gepinnte mutable Tags sind dokumentierte Info-Ausnahmen; `monitoring-influxdb3-core` als Root-Ausnahme bleibt bewusst als Warning sichtbar |
|
||||
|
||||
## Sprint 2 - Storage und Recovery verbindlich machen
|
||||
|
||||
| Status | Aufgabe | Ergebnis |
|
||||
|---|---|---|
|
||||
| erledigt | `docs/STORAGE_LAYOUT.draft.md` finalisieren | Datei als `docs/STORAGE_LAYOUT.md` Active v1.4 gefuehrt; Draft-Blocker entfernt |
|
||||
| erledigt (Baseline) | Disk- und Share-TBDs eintragen | Disk-Modelle, Seriennummern, Groessen, Filesysteme und Share-Cache-Settings aus `docs/HARDWARE_INVENTORY.md` und Host-Readout 2026-05-27 uebernommen; Retention-/Schwellen-Kalibrierung bleibt Folgeaufgabe |
|
||||
| erledigt | Gitea-Repo-Mirror-Mechanik definieren | `ops/borg-ui/scripts/gitea-bundle-mirror.sh` erzeugt verifizierte Bundles unter `/mnt/user/backups/git-bundles/gitea`; Host-Erstlauf 2026-05-26: 4 Bundles, Checksums OK, `homelab-infra.bundle` klonbar und `git fsck` sauber. Schedule live seit 2026-05-27 ueber User-Script `gitea-bundle-mirror-6h` (`10 */6 * * *`); Bundles werden mit `chmod 644` geschrieben damit der Nearline-Pull sie greift. |
|
||||
| erledigt (Doku) | Komodo-Bootstrap-Pfad beschreiben | `docs/SERVICES_RECOVERY.md` enthaelt linearen Bootstrap in Stufen A-F mit Recovery-Anker `ops/komodo/docker-compose.yml`, expliziter Abgrenzung zum Self-Stack, Secret-Reihenfolge und Validierungs-Kommandos; `docs/DISASTER_RECOVERY.md` Stufe 3 verlinkt auf Bootstrap-Pfad. Trockenlauf-Skript bleibt als offene Folgeaufgabe. |
|
||||
| erledigt | Immich-Restore-Test planen | Testumfang, Datenpfade und Smoke-Test-Kriterium sind in `docs/IMMICH_RESTORE_TEST.md`, `ops/restore-tests/immich-plan.md` und `ops/restore-tests/immich-runbook.md` festgehalten; erster Host-Lauf am 2026-05-27 erfolgreich |
|
||||
|
||||
## Sprint 3 - Restore und Monitoring
|
||||
|
||||
| Status | Aufgabe | Ergebnis |
|
||||
|---|---|---|
|
||||
| erledigt | Immich-Restore-Test implementieren | Echter Host-Lauf 2026-05-27 erfolgreich: Borg-Archiv `Tägliche-Sicherung-2026-05-27T04:30:06.778`, `immich.dump` extrahiert, isolierter pgvecto-rs-Postgres importiert, Immich-Server ohne ML gestartet, HTTP `200`, Login-Marker ok, `11977` Assets und `1` User im Test-DB-Check; Report `/mnt/user/backups/restore-reports/immich-2026-05-27.md` |
|
||||
| erledigt | Borg-Stale-Alert bauen | Cron `*/5 * * * *` (`export-prometheus-textfile-5min` User-Script) schreibt `homelab.prom`; node-exporter scraped, Prometheus laedt Regel `HomelabBorgBackupStale` aktiv. Live 2026-05-27 20:33 reloaded; `lastConfigTime: 2026-05-27T18:33:06Z`; Smoke-Query `(time() - homelab_borg_last_completed_timestamp_seconds)/3600 = 16h`. Borg-Job-Warning ist aktuell `pending` (Letzter Lauf `completed_with_warnings`). |
|
||||
| erledigt | TLS-Cert-Expiry-Alert bauen | Regeln `HomelabCertificateExpiresSoon` (21d) und `HomelabCertificateExpiresCritical` (7d) sind in `alerts.yml` aktiv und nach Prometheus-Reload geladen. Smoke `inactive` (keine Cert <21d). |
|
||||
| erledigt | Container-Down-Alert bauen | `HomelabCriticalContainerDown` aktiv; Live-Smoke 2026-05-27 `sum(homelab_critical_container_running) = 30`, alle aktuellen Critical-Container `1`. Aktualisierung alle 5 Min ueber Cron. |
|
||||
| erledigt (Spezifikation) | Family-View Dashboard definieren | `docs/FAMILY_VIEW_DASHBOARD.md` enthaelt Layout, PromQL-Queries, Thresholds und Build-Reihenfolge fuer ein `homelab-family-view`-Dashboard. JSON wird bewusst erst angelegt, sobald Borg-Stale-/Cert-Expiry-/Container-Down-Metriken stabil live sind und ein manueller Build im Grafana-UI das Layout bestaetigt hat. |
|
||||
|
||||
## Sprint 4 - Familien- und Betriebsdoku
|
||||
|
||||
| Status | Aufgabe | Ergebnis |
|
||||
|---|---|---|
|
||||
| erledigt (final vor Einladung) | Familien-Onboarding schreiben | `docs/FAMILY_ONBOARDING.md` ist final redigiert: familienverstaendliche Sprache, App-eigene 2FA statt SSO-Versprechen, neuer "Bewusst nicht versprochen"-Block (kein Einheits-Login, kein 24/7-SLA, kein Hotline-Support, keine Datenweitergabe), konkrete Was-tun-Anleitungen. Einladungstermin bleibt Operator-Aufgabe. |
|
||||
| erledigt (Baseline) | Capacity-/Lifecycle-Review erstellen | Cache 6 %, Array/User-Shares 33 %, lokale Backups 2.2G; H:/-Nearline-Bewertung ergaenzt; externe Cold-Storage-Groessen bleiben offen |
|
||||
| erledigt | USV-Test oder USV-Entscheidung | Operator-Entscheidung 2026-05-26: aktuell keine USV-Anschaffung; Power-Loss-Risiko wird bewusst akzeptiert und dokumentiert |
|
||||
| erledigt (Baseline) | H:/ als zusaetzliches lokales Backupziel bewerten | Als zweite Nearline-Kopie und Freeze-Sicherung sinnvoll; kein Offsite-Ersatz, kein CIFS-Hard-Mount am Unraid; Pull-Modell vom Windows-PC ist der getestete Weg (siehe `docs/CAPACITY_AND_LIFECYCLE.md`) |
|
||||
| erledigt (Pull live, Scheduled Task offen) | H:/ Groesse und Pull-Schedule festschreiben | Groesse erfasst: 8.0T NTFS, 3.91T belegt, 4.10T frei, `Healthy`. Erster echter Pull 2026-05-27 20:45 erfolgreich: 19 Borg-Dumps + 10 Gitea-Bundle-Files unter `H:\kallilab-nearline-backups`. `unraid-flash-config.*` bewusst ausserhalb Scope (`/XF`-Exclude, Restore aus Hetzner-Borg). Permission-Fixes in `pre-backup-dumps.sh` (alle Dumps 0644 ausser Flash-Config), `gitea-bundle-mirror.sh` (Bundles 0644), `export-prometheus-textfile.sh` (Metric-File 0644) und `pull-critical-backups.ps1` (Report-Bug + ExcludeFiles). Windows Scheduled Task taeglich 05:30 bleibt offen (Operator-Bestaetigung). |
|
||||
| erledigt 2026-05-28 | FRITZ!Box-Portfreigaben gegen Repo-Soll abgleichen | Bereinigt: `80/tcp` entfernt (Mobilfunk-validiert: HTTP timeout, HTTPS weiter erreichbar). `222/tcp` bleibt bewusst nicht eingerichtet (Tailscale-only-Linie). UPnP-Selbstfreigabe-Recht fuer `PC-192-168-178-71` (VONETS-Bridge, vermutlich SolarEdge-Wechselrichter) deaktiviert. Aktiver Endstand: ausschliesslich `443/tcp -> 192.168.178.58`. Details in `docs/FRITZBOX_PORT_CORRECTION_PLAN.md`. |
|
||||
|
||||
## Sprint 5 - Auth und Frontdoor, bewusst zuletzt
|
||||
|
||||
In diesem Audit-Zyklus werden diese Punkte **nicht** umgesetzt. Sie sind dokumentiert, damit sie bei einer kuenftigen Policy-Entscheidung sofort priorisiert werden koennen.
|
||||
|
||||
| Status | Aufgabe | Begruendung der Parkung |
|
||||
|---|---|---|
|
||||
| geparkt | Authelia 2FA fuer Operator-UIs erweitern (F-04) | Operator-Vorgabe 2026-05-26: keine Auth-Aenderungen in diesem Zyklus |
|
||||
| geparkt | Authelia OIDC fuer Apps pruefen (F-13) | Operator-Vorgabe 2026-05-26: keine Auth-Aenderungen in diesem Zyklus |
|
||||
| geparkt | CrowdSec vor Traefik pruefen (F-14) | Operator-Vorgabe 2026-05-26: erst nach finaler Auth-Policy |
|
||||
| geparkt | Nextcloud-2FA-/Brute-Force-Haertung dokumentieren (F-18) | beruehrt Auth-Policy fuer Familien-Konten; gemeinsam mit OIDC-Entscheidung |
|
||||
|
||||
## Sprint 6 - Geparkte Apps und Folgeentscheidungen
|
||||
|
||||
| Status | Aufgabe | Naechster Pruefschritt |
|
||||
|---|---|---|
|
||||
| geparkt | Hermes-Agent (F-06) — Operator-Entscheidung produktiv vs. entfernen | Review-Deadline **2026-07-25**; bis dahin bleibt der NAS-Stack deaktiviert, das Repo-Verzeichnis erhalten, Dashboard-Domain und ACL-Eintrag unveraendert |
|
||||
| erledigt 2026-05-28 | paperless-gpt / BentoPDF Nutzungsentscheidung | Operator behaelt beide. **paperless-gpt** bleibt bis Paperless-NGX 3.0 (erwartete native KI-Features); danach neu bewerten. **BentoPDF** bleibt als situatives Tool (Resource-Footprint ~4 MB). Beide ohne aktive Traefik-Zugriffe in der letzten Woche, aber bewusste Behalten-Entscheidung mit Begruendungs-Anker im SERVICE_CATALOG. |
|
||||
| erledigt 2026-05-28 | Plex Remote Access in UI deaktivieren falls nur LAN/Tailscale (F-17) | Beim Versuch entdeckt: Server war seit 18.05. unclaimed und Bibliotheken leer. Reclaim als `Xeridos` via inline `PLEX_CLAIM`-Token, danach Bibliotheken (`/data/movies` 1.4 TB, `/data/Heimatfilme` 300 GB) neu angelegt und Remote Access deaktiviert (`PublishServerOnPlexOnlineKey=0`, Plex-Relay aus). Details in `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 13. |
|
||||
| erledigt | `infra/redis` Doku-Etikett korrigieren (F-16) | SERVICE_CATALOG, REPO_MAP, MASTER (Sektion 13) und DISASTER_RECOVERY Bootstrap-Stufe 2 auf "primaer Paperless-Redis" praezisiert; keine Compose-Aenderung |
|
||||
| erledigt | Paperless-DBPass DR-Restore-Reihenfolge in DR-Doc (F-20) | DISASTER_RECOVERY 6.2.1 (Restore-Quellen fuer Stack-ENV-Werte) ergaenzt; SECRETS_MAP um Abschnitt "Stack-ENV-only Secrets - Restore-Wege" mit Reihenfolge Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz erweitert; Paperless, Immich, Mail-Archiver, Speedtest, Komodo, Hermes und Glance je mit Restore-Quelle dokumentiert |
|
||||
|
||||
## Sprint 8 - Reife der Stack-Hygiene (2026-05-29)
|
||||
|
||||
| Status | Aufgabe | Ergebnis |
|
||||
|---|---|---|
|
||||
| erledigt 2026-05-29 | Healthchecks fuer Tier-1 (F-15) | postgresql17 (`pg_isready`), Redis (`redis-cli ping` mit Auth), Vaultwarden (`curl /alive`), Gitea (`wget /api/healthz`), Traefik (`traefik healthcheck --ping`, `--ping=true` in CLI), Authelia (`wget /api/health`, weil v4.39 `helper health-check` entfernt hat); komodo-mongo war bereits gepinnt healthy. Live-Smoke: alle 6 healthy nach Recreate. Postgres- und Gitea-Stack-Workspace waren Komodo-seitig zurueckgeblieben (124 bzw. 52 commits behind); manuell per `cp` + `docker compose up -d` synchronisiert. |
|
||||
| erledigt 2026-05-29 | Monitoring-Stack Digest-Pinning (F-07) | 9 Container in `monitoring/docker-compose.yml` per Tag@sha256 gepinnt: prometheus, alertmanager, alertmanager-ntfy-bridge (python:3.13-alpine), blackbox-exporter, loki, promtail, grafana, node-exporter, cadvisor. Digests aus dem aktuell laufenden Container ausgelesen, damit der Pin den Live-Stand reflektiert. influxdb3-core war bereits gepinnt. |
|
||||
| erledigt 2026-05-29 | Komodo-Bootstrap-Trockenlauf-Skript (F-09 Rest) | `ops/restore-tests/komodo-bootstrap-{compose.test.yml,test.sh,plan.md,runbook.md}` analog zum Immich-Restore-Test angelegt. Test-Compose nutzt dieselben Image-Digests wie Produktion, isoliert unter Project `restoretest-komodo`, Test-Periphery ohne docker.sock-Mount, Test-Port nur `127.0.0.1:19120`. Wegwerf-Secrets im Compose. Erster Lauf manuell durch Operator. |
|
||||
| vorbereitet 2026-05-29 (Setup-Schritte Operator-Aufgabe) | Renovate-Bot gegen Gitea (F-12) | `renovate.json` im Repo-Root mit Group-Rules (Major getrennt, Minor/Patch/Digest gruppiert, Tier-1-Datenhalter einzeln, Komodo-Major deaktiviert). `ops/renovate/run-renovate.sh` als One-Shot-Wrapper. `docs/RENOVATE.md` mit Setup-Anleitung: Gitea-Service-Account `renovate` anlegen, PAT erzeugen, in `/mnt/user/appdata/secrets/renovate_token.txt` ablegen, User-Script `renovate-six-hourly` (`20 */6 * * *`) aktivieren. Kein Auto-Merge, jede PR braucht Operator-Sichtpruefung. |
|
||||
|
||||
## Sprint 7 - Off-site und 3-2-1 (offen)
|
||||
|
||||
| Status | Aufgabe | Bemerkung |
|
||||
|---|---|---|
|
||||
| erledigt 2026-05-28 (bewusst nicht umgesetzt) | Zweites echtes Off-site (F-03) | Operator-Entscheidung 2026-05-28: kein zweites Off-site. 3-2-1 ist mit Live + lokalem Borg + Hetzner + H:/-Nearline erfuellt; ein zweites Off-site wuerde nur den Fall "Hetzner-Account verloren" zusaetzlich abdecken, Aufwand/Kosten unverhaeltnismaessig fuer Familien-Homelab. Statt dessen drei Hetzner-Haertungen als Folge-TODOs (siehe `docs/OFFSITE_BACKUP_OPTIONS.md` Beschluss-Block). Review-Trigger sind dort definiert. |
|
||||
| offen (Operator-Aufgabe) | Hetzner-Account-Hygiene ohne 2FA | Starkes, einzigartiges Passwort in Vaultwarden + Backup-Zahlungsweg + Login-Benachrichtigungen per E-Mail. 2FA bewusst nicht (analog USV: Risiko bewusst akzeptiert, Aufwand ueberwiegt Risiko-Reduktion fuer Familien-Homelab). |
|
||||
| offen (Folge-Sprint) | Borg `--append-only` auf Hetzner setzen | Aktuell laeuft Repo `appdata-critical` im Mode `full`, `custom_flags` leer. Setup server-seitig in Hetzner `~/.ssh/authorized_keys` mit `command="borg serve --append-only"`. Schuetzt gegen Ransomware, die client-seitig Borg-Credentials abgreifen koennte. |
|
||||
| erledigt 2026-05-28 | H:/-Pull als Windows Scheduled Task | Task `KalliLab H Drive Nearline Pull` registriert: taeglich 05:30, `RunLevel Limited`, `AllowStartIfOnBatteries`, `StartWhenAvailable`, `ExecutionTimeLimit 2h`. Naechster Lauf 2026-05-29 05:30. Erstlauf manuell 2026-05-27 20:45 erfolgreich, Task-Setup in `docs/H_DRIVE_NEARLINE_PULL.md` aktualisiert (RunLevel-Enum-Fix `LeastPrivilege` -> `Limited`). |
|
||||
| erledigt (Routine dokumentiert) | Restore-Lab-Drill quartalsweise dokumentieren | `docs/RESTORE_DRILL_ROUTINE.md` definiert Drei-Stufen-Modell (Freshness woechentlich / Mini-Restore monatlich-bimonatlich / DR-Sanity quartalsweise), Quartals-Belegung Q1-Q4 mit Dienst-Rotation, Immich 2026-05-27 als bestaetigter Erstlauf gefuehrt, 10-Punkte-Sanity-Check, kein Host-Schedule angelegt. `ops/restore-tests/schedule.md` verweist jetzt auf Drill-Routine. |
|
||||
|
||||
## Offene Host-Werte
|
||||
|
||||
Diese Werte muessen am Unraid-Host erhoben werden, bevor die entsprechenden Aenderungen sauber umgesetzt werden:
|
||||
|
||||
```bash
|
||||
hostname
|
||||
cat /proc/cpuinfo | awk '/model name|flags/ {print; if(/flags/) exit}'
|
||||
free -h
|
||||
dmidecode -t baseboard | head -30
|
||||
ip -br link
|
||||
tailscale ip -4
|
||||
lsblk -o NAME,SIZE,MODEL,SERIAL,FSTYPE,MOUNTPOINT,VENDOR
|
||||
df -h /mnt/cache /mnt/disk1 /mnt/user
|
||||
smartctl -a /dev/nvme0n1 | head -80
|
||||
smartctl -a /dev/sdb | head -80
|
||||
```
|
||||
@@ -0,0 +1,80 @@
|
||||
# Audit Report - KalliLab CORE
|
||||
Datum: 2026-05-16
|
||||
Gepruefte Compose-Dateien: 30
|
||||
|
||||
## Kritische Befunde
|
||||
|
||||
Keine kritischen Befunde im Repo-Sollzustand gefunden.
|
||||
|
||||
- Keine Datenbank und kein Cache haengt in `frontend_net`.
|
||||
- Keine produktive Compose-Datei ohne explizites `networks:`-Feld gefunden.
|
||||
- Keine produktive `.env`- oder `stack.env`-Datei ohne `.example`-Suffix im Repository gefunden.
|
||||
- Keine Klartext-Passwoerter, Tokens oder API-Keys in Compose-`environment:`-Bloecken gefunden.
|
||||
|
||||
## Mittlere Befunde
|
||||
|
||||
- Docker-Socket ausserhalb der im Audit-Prompt genannten Allowlist: `traefik` mountet `/var/run/docker.sock:/var/run/docker.sock:ro` in `traefik/docker-compose.yml:34`. Der Socket ist fuer den Docker-Provider fachlich nachvollziehbar, aber in `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 10 nicht explizit als Docker-Socket-Ausnahme aufgefuehrt.
|
||||
- Docker-Socket ausserhalb der im Audit-Prompt genannten Allowlist: `alloy` mountet `/var/run/docker.sock:/var/run/docker.sock:ro` in `ops/loki/docker-compose.yml:26`. [AUSNAHME - dokumentiert] in `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 10 als `alloy` Docker-Socket read-only, aber nicht in der Prompt-Allowlist genannt.
|
||||
- `komodo-periphery` haengt ohne Web-UI im `frontend_net` in `ops/komodo/docker-compose.yml:92-94`. Die Compose-Datei dokumentiert an `ops/komodo/docker-compose.yml:77-79` den Grund als Git-Zugriff auf internes Gitea und Docker-Agent-Sonderfall. [AUSNAHME - lokal in Compose dokumentiert]
|
||||
- `hermes_net` ist ein app-internes Netz ohne `internal: true`: `ops/hermes-agent/docker-compose.yml:91-93`. Das ist nicht Teil der explizit geforderten `internal: true`-Liste, aber strukturell auffaellig, weil Gateway und Dashboard intern ueber dieses Netz sprechen.
|
||||
- `grafana` nutzt zusaetzlich `backend_net` in `ops/grafana-influxdb/docker-compose.yml:27-30`, obwohl die Architektur das Grafana/Influx-Paar primaer als `frontend_net` + `grafana_influx_internal` beschreibt. Grund ist vermutlich Loki-Datasource-Zugriff; `docs/REPO_MAP.md` nennt `backend_net` fuer Grafana-Loki-Datasource. [AUSNAHME - dokumentiert]
|
||||
- `paperless-gpt` verwendet `PAPERLESS_API_TOKEN` als Stack-ENV in `apps/paperless-gpt/docker-compose.yml:15`, taucht aber in `docs/SECRETS_MAP.md` nicht als eigener aktiver Secret-Eintrag auf.
|
||||
|
||||
## Hinweise
|
||||
|
||||
- Direkte Host-Ports sind nur bei dokumentierten Ausnahmen vorhanden:
|
||||
- [AUSNAHME - dokumentiert] `traefik`: `80:80`, `443:443` in `traefik/docker-compose.yml:30-32`.
|
||||
- [AUSNAHME - dokumentiert] `gitea`: `222:22` in `core/gitea/docker-compose.yml:17-18`.
|
||||
- [AUSNAHME - dokumentiert] `adguard`: `53:53/tcp`, `53:53/udp`, `8082:80` in `host-services/Adguard/docker-compose.yml:13-16`.
|
||||
- [AUSNAHME - dokumentiert] `influxdb3-core`: `${INFLUXDB_BIND_IP:-127.0.0.1}:8181:8181` in `ops/grafana-influxdb/docker-compose.yml:54-55`.
|
||||
- `backend_net` wird in allen Compose-Dateien als `external: true` referenziert, z. B. `infra/postgresql17/docker-compose.yml:25-26`, `infra/redis/docker-compose.yml:22-23`, `traefik/docker-compose.yml:59-60`. Ob das externe Docker-Netz live wirklich `internal: true` ist, ist aus dem Repo allein nicht verifizierbar.
|
||||
- `grafana_influx_lan` hat bewusst kein `internal: true`: `ops/grafana-influxdb/docker-compose.yml:88-89`. [AUSNAHME - dokumentiert]
|
||||
- Mutable Tags sind mit Digests gepinnt, aber semantisch weiterhin mutable:
|
||||
- `immich-server`: `release@sha256` in `apps/immich/docker-compose.yml:4`.
|
||||
- `immich-machine-learning`: `release@sha256` in `apps/immich/docker-compose.yml:35`.
|
||||
- `tailscale`: `stable@sha256` in `host-services/tailscale/docker-compose.yml:3`.
|
||||
- `ddns-updater`: `latest@sha256` in `infra/ddns-updater/docker-compose.yml:3`.
|
||||
- `komodo-core`: Major-Tag `2@sha256` in `ops/komodo/docker-compose.yml:36`.
|
||||
- `komodo-periphery`: Major-Tag `2@sha256` in `ops/komodo/docker-compose.yml:82`.
|
||||
- `uptime-kuma`: Major-Tag `1@sha256` in `ops/uptime-kuma/docker-compose.yml:3`.
|
||||
- Reines `image: name:latest` ohne Digest wurde in produktiven Compose-Dateien nicht gefunden.
|
||||
- Alle Services haben `restart: unless-stopped`.
|
||||
- Alle Services haben `security_opt: no-new-privileges:true`.
|
||||
- [AUSNAHME - dokumentiert] `scrutiny` nutzt `privileged: true` in `ops/scrutiny/docker-compose.yml:6`.
|
||||
- [AUSNAHME - dokumentiert] `tailscale` nutzt `network_mode: host` in `host-services/tailscale/docker-compose.yml:6`.
|
||||
|
||||
## Dokumentations-Abweichungen
|
||||
|
||||
- Service-Namen in Compose vs. `docs/SERVICE_CATALOG.md` weichen bei Immich ab: Compose nutzt `immich-server`, `immich-machine-learning`, `database`, `redis` in `apps/immich/docker-compose.yml:2`, `:33`, `:44`, `:53`; der Katalog dokumentiert `immich_server`, `immich_machine_learning`, `immich_postgres`, `immich_redis`.
|
||||
- Service-Name in Compose vs. `docs/SERVICE_CATALOG.md` weicht bei Paperless ab: Compose nutzt `paperless` in `apps/paperless/docker-compose.yml:2`; der Katalog dokumentiert `paperless-ngx`.
|
||||
- Service-Name in Compose vs. `docs/SERVICE_CATALOG.md` weicht bei Redis ab: Compose nutzt `redis` in `infra/redis/docker-compose.yml:2`; der Katalog dokumentiert `Redis`.
|
||||
- Traefik-Host bei Hermes ist im Compose variabel: `Host(`${HERMES_DASHBOARD_HOST}`)` in `ops/hermes-agent/docker-compose.yml:81`; `docs/REPO_MAP.md` dokumentiert konkret `hermes.kaleschke.info`. Das ist plausibel, aber maschinell nicht eindeutig abgleichbar.
|
||||
- `docs/REPO_MAP.md` Volumes-Tabelle ist fuer mehrere Mounts nur zusammenfassend, nicht pfadgenau. Beispiele mit Compose-Pfaden, die dort nicht wortgleich auftauchen:
|
||||
- `/mnt/user/appdata/unbound/config` in `apps/unbound/docker-compose.yml:7`.
|
||||
- `/mnt/user/appdata/ddns-updater` in `infra/ddns-updater/docker-compose.yml:17`.
|
||||
- `/mnt/user/appdata/filebrowser/database` und `/mnt/user/appdata/filebrowser/config` in `ops/filebrowser/docker-compose.yml:15-16`.
|
||||
- `/mnt/user/appdata/borg-ui/restore` in `ops/borg-ui/docker-compose.yml:27`.
|
||||
- Netzwerke in Compose sind alle in `docs/REPO_MAP.md` aufgefuehrt.
|
||||
- Traefik-Hosts aus Compose sind in `docs/REPO_MAP.md` aufgefuehrt; einzige Besonderheit ist der variable Hermes-Host.
|
||||
- `.example`-Dateien haben passende Gegenspieler in `.gitignore`: `.env`, `*.env`, `!*.env.example`, `**/stack.env`, `!**/stack.env.example`.
|
||||
- Keine `.keep`-Platzhalter-Dateien gefunden.
|
||||
|
||||
## Offene Architektur-Punkte: aktueller Stand
|
||||
|
||||
- `immich_redis`: weiterhin kein named volume. Compose-Service `redis` in `apps/immich/docker-compose.yml:44-50` hat aktuell gar keinen `volumes:`-Block. Architekturpunkt bleibt offen.
|
||||
- `AdGuard Home`: Admin-Port ist weiterhin direkt veroeffentlicht: `8082:80` in `host-services/Adguard/docker-compose.yml:15`; keine Traefik-Labels vorhanden. Block F bleibt offen.
|
||||
- `filebrowser`: Appdata-Breitmount ist entfernt; aktuelle Mounts sind `/mnt/user/documents`, `/mnt/user/photos`, `/mnt/user/projekte` plus eigene DB/Config in `ops/filebrowser/docker-compose.yml:12-16`. Langfristiges Hardening bleibt moeglich, aber der groesste alte Breitmount ist erledigt.
|
||||
- `bentopdf`: Compose ist vorhanden und Traefik-abgesichert in `apps/bentopdf/docker-compose.yml:2-27`. Runtime-Deploy und fachliche Abnahme koennen aus dem Repo allein nicht bestaetigt werden; Architekturpunkt bleibt als Live-Pruefung offen.
|
||||
- `grafana` und `influxdb3-core`: laufen weiterhin als `user: "0"` in `ops/grafana-influxdb/docker-compose.yml:6` und `ops/grafana-influxdb/docker-compose.yml:53`. [AUSNAHME - dokumentiert]
|
||||
- `plex-media-server`: keine Compose-Datei im Repo gefunden; bleibt Dockerman-/Host-Sonderfall laut Architektur.
|
||||
|
||||
## Bestanden
|
||||
|
||||
- 30 produktive `docker-compose.yml` wurden geprueft.
|
||||
- Keine Datenbanken oder Caches im `frontend_net`: `postgresql17` nur `backend_net` in `infra/postgresql17/docker-compose.yml:18`; shared `redis` nur `backend_net` in `infra/redis/docker-compose.yml:15`; `mealie-postgres` nur `mealie_internal` in `apps/mealie/docker-compose.yml:56`; Immich `database` und `redis` nur `immich_default` in `apps/immich/docker-compose.yml:48` und `:64`; Nextcloud DB/Redis nur `nextcloud_internal` in `apps/nextcloud/docker-compose.yml:61` und `:73`; `komodo-mongo` nur `komodo_net` in `ops/komodo/docker-compose.yml:16`.
|
||||
- App-interne Pflichtnetze sind korrekt `internal: true`: `immich_default` in `apps/immich/docker-compose.yml:73-75`, `mealie_internal` in `apps/mealie/docker-compose.yml:66-68`, `nextcloud_internal` in `apps/nextcloud/docker-compose.yml:82-84`, `grafana_influx_internal` in `ops/grafana-influxdb/docker-compose.yml:90-91`.
|
||||
- `frontend_net` und `backend_net` werden in Compose-Dateien als `external: true` referenziert.
|
||||
- Alle Services mit `traefik.enable=true` setzen explizit `traefik.docker.network=frontend_net`, `entrypoints=websecure`, `tls=true` und `tls.certresolver=le`.
|
||||
- Kein Traefik-Label mit `yourdomain.tld` gefunden.
|
||||
- Admin-/Ops-Router haben Middleware `authelia@file,secure-headers@file`, u. a. `homepage` in `apps/homepage/docker-compose.yml:31`, `filebrowser` in `ops/filebrowser/docker-compose.yml:27`, `scrutiny` in `ops/scrutiny/docker-compose.yml:32`, `grafana` in `ops/grafana-influxdb/docker-compose.yml:46`. [AUSNAHME - dokumentiert] `komodo-core` hat keine ForwardAuth-Middleware in `ops/komodo/docker-compose.yml:64-71`; [AUSNAHME - dokumentiert] `nextcloud` nutzt native Auth und nur Redirect-Middleware in `apps/nextcloud/docker-compose.yml:42-46`.
|
||||
- Web-UIs ohne Traefik-Labels wurden nur als dokumentierte Sonderfaelle gefunden: `adguard` mit LAN-Admin-Port in `host-services/Adguard/docker-compose.yml:13-16`; `ddns-updater` hat keine Web-UI und braucht Internet in `infra/ddns-updater/docker-compose.yml:8`; `komodo-periphery` ist Agent ohne Traefik-Route in `ops/komodo/docker-compose.yml:81-103`.
|
||||
@@ -1,186 +0,0 @@
|
||||
# Authelia OIDC fuer Apps - Plan & Runbook
|
||||
|
||||
Stand: 2026-06-06. Authelia-Version: **v4.39.20**.
|
||||
|
||||
Ziel: App-uebergreifendes Single-Sign-On ueber Authelia als OpenID-Connect-Provider
|
||||
(`https://auth.kaleschke.info`). Statt pro App eigener Logins meldet man sich einmal
|
||||
bei Authelia an (inkl. 2FA) und wird per OIDC an die App durchgereicht.
|
||||
|
||||
> **Status:** aktives Runbook. Grafana und Mealie sind seit 2026-06-06 live
|
||||
> und per Login-Smoke verifiziert. Der weitere Rollout bleibt additiv: lokale
|
||||
> App-Logins bleiben als Fallback aktiv.
|
||||
|
||||
---
|
||||
|
||||
## Grundregeln (wichtig)
|
||||
|
||||
- **Secrets gehoeren nie ins Repo.** OIDC-Client-Secrets (Klartext und pbkdf2-Hash)
|
||||
liegen ausschliesslich in der Host-Config `/mnt/user/appdata/authelia/config/configuration.yml`
|
||||
(Hash) und im jeweiligen App-Stack (Klartext, via Komodo Stack-ENV / Secret-Datei),
|
||||
plus optional Vaultwarden. Dieses Dokument enthaelt nur Schema und Variablennamen.
|
||||
- **OIDC-Clients leben host-seitig**, wie der bestehende `beszel`-Client. Die Repo-Baseline
|
||||
`security/authelia/configuration.yml` haelt nur die nicht-geheime Struktur
|
||||
(`access_control` etc.); `services/authelia-diff.sh` vergleicht standardmaessig nur
|
||||
`access_control`, OIDC-Clients auf dem Host loesen also keinen Drift-Alarm aus.
|
||||
- **Issuer/Endpoints** (Authelia OIDC):
|
||||
- Issuer: `https://auth.kaleschke.info`
|
||||
- Authorization: `https://auth.kaleschke.info/api/oidc/authorization`
|
||||
- Token: `https://auth.kaleschke.info/api/oidc/token`
|
||||
- Userinfo: `https://auth.kaleschke.info/api/oidc/userinfo`
|
||||
- JWKS: `https://auth.kaleschke.info/jwks.json`
|
||||
- Discovery: `https://auth.kaleschke.info/.well-known/openid-configuration`
|
||||
- **PKCE an, wo moeglich** (`require_pkce: true`, `S256`), wie beim Beszel-Client.
|
||||
|
||||
---
|
||||
|
||||
## Client-Schema (Authelia v4.39, gespiegelt vom bestehenden `beszel`-Client)
|
||||
|
||||
Pro App ein Block unter `identity_providers.oidc.clients` in der **Host-Config**:
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
clients:
|
||||
- client_id: '<app>'
|
||||
client_name: '<App-Name>'
|
||||
client_secret: '<pbkdf2-sha512-Hash - NUR auf dem Host>'
|
||||
public: false
|
||||
authorization_policy: 'two_factor' # admin-Apps: two_factor; Familien-Apps: s.u.
|
||||
require_pkce: true
|
||||
pkce_challenge_method: 'S256'
|
||||
redirect_uris:
|
||||
- 'https://<app>.kaleschke.info/<oidc-callback-pfad>'
|
||||
scopes:
|
||||
- 'openid'
|
||||
- 'profile'
|
||||
- 'email'
|
||||
- 'groups'
|
||||
response_types:
|
||||
- 'code'
|
||||
grant_types:
|
||||
- 'authorization_code'
|
||||
token_endpoint_auth_method: 'client_secret_basic'
|
||||
userinfo_signed_response_alg: 'none'
|
||||
```
|
||||
|
||||
### Client-Secret erzeugen (auf dem Host)
|
||||
|
||||
```bash
|
||||
docker exec authelia authelia crypto hash generate pbkdf2 \
|
||||
--variant sha512 --random --random.length 72 --random.charset rfc3986
|
||||
```
|
||||
|
||||
- Ausgabe: **Random Password** (Klartext) + **Digest** (pbkdf2-Hash).
|
||||
- **Hash** -> Host-Config `client_secret`.
|
||||
- **Klartext** -> App-Stack (Komodo Stack-ENV/Secret) + optional Vaultwarden.
|
||||
- Klartext **nicht** ins Repo, nicht in Logs.
|
||||
|
||||
---
|
||||
|
||||
## Reihenfolge / Rollout
|
||||
|
||||
| Stufe | App | Domain | OIDC-Support | Policy | Risiko | Begruendung |
|
||||
|---|---|---|---|---|---|---|
|
||||
| **1 (Proof) ERLEDIGT 2026-06-06** | Grafana (monitoring) | `monitoring.kaleschke.info` | nativ (`generic_oauth`) | `two_factor` | niedrig | **Live + Login verifiziert.** Authelia-Client `grafana` (host), Secret als Datei `/mnt/user/appdata/secrets/grafana_oidc_client_secret` via `__FILE`, ForwardAuth-Middleware durch OIDC ersetzt, lokaler Admin bleibt Fallback |
|
||||
| 2 | Immich | `immich.kaleschke.info` | nativ (Admin-UI/Config-File) | s. u. (Familie) | mittel | **GEPARKT bis Onboarding (Entscheidung 2026-06-06):** nur `micha` hat Authelia-Account, Familien-SSO-Nutzen entsteht erst mit Familien-Accounts; Immich ist mobil-lastig (hoechste Stoeranfaelligkeit) und braucht UI/Config-File. Erst nach Onboarding gezielt. Runbook bereit. |
|
||||
| 3 | Nextcloud | `cloud.kaleschke.info` | App `user_oidc` (+occ) | s. u. | mittel | **GEPARKT bis Onboarding (Entscheidung 2026-06-06):** wie Immich; braucht `user_oidc`-App-Install + `occ`. Lokaler Login bleibt. Erst nach Onboarding. Runbook bereit. |
|
||||
| **4 ERLEDIGT 2026-06-06** | Mealie | `mealie.kaleschke.info` | nativ | `one_factor` | niedrig | **Live + Login verifiziert.** OIDC-Env additiv (lokaler Login bleibt), Secret als Stack-ENV `${MEALIE_OIDC_CLIENT_SECRET}`, `extra_hosts` noetig (s. Gotchas) |
|
||||
| 5 | Paperless-ngx | `paperless.kaleschke.info` | `django-allauth` (Umgebungsvariablen) | `two_factor` | mittel | dokumentenlastig, Operator-nah |
|
||||
|
||||
**Nicht OIDC:** Vaultwarden hat kein Standard-Endnutzer-OIDC (SSO ist Enterprise/Bitwarden-Feature) -> bleibt eigener Login. ntfy bleibt wie gehabt.
|
||||
|
||||
### Policy Familien-Apps
|
||||
|
||||
- Admin-Apps (Grafana, Paperless): `authorization_policy: two_factor`.
|
||||
- Familien-Apps (Immich, Nextcloud, Mealie): Start mit `one_factor` und lokalen
|
||||
App-Logins als Fallback. 2FA fuer Familie erst spaeter, sobald TOTP-Enrollment
|
||||
pro Person eingerichtet ist; sonst entsteht unnoetiges Lockout-Risiko.
|
||||
|
||||
---
|
||||
|
||||
## Stufe 1 konkret: Grafana (empfohlener Erststart)
|
||||
|
||||
### A) Authelia (Host) - Client anlegen
|
||||
1. Secret erzeugen (Befehl oben). Klartext + Hash notieren.
|
||||
2. In `/mnt/user/appdata/authelia/config/configuration.yml` unter
|
||||
`identity_providers.oidc.clients` neuen Block einfuegen:
|
||||
```yaml
|
||||
- client_id: 'grafana'
|
||||
client_name: 'Grafana'
|
||||
client_secret: '<HASH>'
|
||||
public: false
|
||||
authorization_policy: 'two_factor'
|
||||
require_pkce: true
|
||||
pkce_challenge_method: 'S256'
|
||||
redirect_uris:
|
||||
- 'https://monitoring.kaleschke.info/login/generic_oauth'
|
||||
scopes: ['openid', 'profile', 'email', 'groups']
|
||||
response_types: ['code']
|
||||
grant_types: ['authorization_code']
|
||||
token_endpoint_auth_method: 'client_secret_basic'
|
||||
userinfo_signed_response_alg: 'none'
|
||||
```
|
||||
3. `docker restart authelia`, Health + Log pruefen (`Startup complete`, keine Fehler).
|
||||
|
||||
### B) Grafana (Komodo Stack-ENV) - generic_oauth
|
||||
Im `monitoring`-Stack (Grafana) setzen (Klartext-Secret aus Schritt A):
|
||||
```
|
||||
GF_AUTH_GENERIC_OAUTH_ENABLED=true
|
||||
GF_AUTH_GENERIC_OAUTH_NAME=Authelia
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_ID=grafana
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=<KLARTEXT-SECRET>
|
||||
GF_AUTH_GENERIC_OAUTH_SCOPES=openid profile email groups
|
||||
GF_AUTH_GENERIC_OAUTH_AUTH_URL=https://auth.kaleschke.info/api/oidc/authorization
|
||||
GF_AUTH_GENERIC_OAUTH_TOKEN_URL=https://auth.kaleschke.info/api/oidc/token
|
||||
GF_AUTH_GENERIC_OAUTH_API_URL=https://auth.kaleschke.info/api/oidc/userinfo
|
||||
GF_AUTH_GENERIC_OAUTH_USE_PKCE=true
|
||||
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP=true
|
||||
# optional Rollen-Mapping ueber groups:
|
||||
# GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH=contains(groups[*], 'admins') && 'Admin' || 'Viewer'
|
||||
```
|
||||
- `GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET` als Stack-ENV-only (kein `_FILE`-Support) -> in
|
||||
`docs/SECRETS_MAP.md` als `grafana_oidc_client_secret` (Stack-ENV) nachziehen.
|
||||
|
||||
### C) Test + Rollback
|
||||
- Test: `monitoring.kaleschke.info` -> "Sign in with Authelia" -> Authelia-Login (2FA) -> zurueck in Grafana, eingeloggt.
|
||||
- **Fallback bleibt:** lokaler Grafana-Admin-Login (`/login`) ist weiter aktiv -> kein Lockout.
|
||||
- Rollback: `GF_AUTH_GENERIC_OAUTH_ENABLED=false` (Grafana redeploy) und/oder Client-Block in Authelia entfernen + `docker restart authelia`.
|
||||
|
||||
---
|
||||
|
||||
## Doku-Nachzug bei jedem neuen Client
|
||||
|
||||
- `docs/SECRETS_MAP.md`: pro App `<app>_oidc_client_secret` (Stack-ENV) + Hinweis "Hash in Authelia-Host-Config".
|
||||
- `docs/SERVICE_CATALOG.md`: App-Zeile um "OIDC via Authelia" ergaenzen.
|
||||
- Dieses Dokument: Rollout-Tabelle abhaken.
|
||||
- `docs/MASTER_TODO.md`: Fortschritt im OIDC-Punkt nachziehen.
|
||||
|
||||
---
|
||||
|
||||
## Gotchas (aus dem realen Rollout 2026-06-06)
|
||||
|
||||
- **`extra_hosts` ist Pflicht fuer App-Container, die selbst zu Authelia connecten**
|
||||
(OIDC-Discovery/Token sind Server-zu-Server): Der App-Container loest
|
||||
`auth.kaleschke.info` per Docker-DNS oft nicht auf -> `httpx.ConnectTimeout` /
|
||||
500 beim OAuth-Start. Fix wie Komodo:
|
||||
```yaml
|
||||
extra_hosts:
|
||||
- "auth.kaleschke.info:192.168.178.58"
|
||||
```
|
||||
Cert validiert weiter (SNI/Hostname bleibt gleich, nur die IP wird gemappt).
|
||||
Gilt fuer Mealie (bestaetigt) und sehr wahrscheinlich Paperless/Immich/Nextcloud.
|
||||
- **Additiv heisst additiv:** OIDC als zusaetzlichen Login aktivieren, lokalen
|
||||
Login NICHT abschalten, `AUTO_REDIRECT`/Force-OIDC aus -> kein Lockout.
|
||||
- **Account-Linking per E-Mail:** Apps verknuepfen den OIDC-User i. d. R. per
|
||||
E-Mail-Claim. Stimmt die Authelia-E-Mail mit dem App-Account, wird verknuepft;
|
||||
sonst legt die App (bei aktivem Signup) einen neuen User an.
|
||||
- **Secret-Mechanik je App verschieden:** Grafana `__FILE` (Docker-Secret),
|
||||
Mealie Stack-ENV `${...}`. Hash immer in der Authelia-Host-Config, Klartext nie ins Repo.
|
||||
|
||||
## Spaetere Feinschliffe vor breitem Rollout
|
||||
|
||||
1. Gruppen/Rollen-Mapping: braucht es Authelia-Gruppen (z. B. `admins`, `family`) fuer
|
||||
App-Rollen (Grafana Admin/Viewer, Nextcloud-Gruppen)? Wenn ja, in der Authelia
|
||||
User-Datenbank Gruppen pflegen.
|
||||
2. Familien-2FA spaeter neu bewerten, nachdem echte Familien-Accounts in Authelia
|
||||
angelegt und TOTP pro Person verstanden ist.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Capacity and Lifecycle - KalliLab CORE
|
||||
|
||||
Status: Initiale Capacity-Baseline 2026-05-26; H:/-Nearline-Pull seit 2026-05-28 produktiv; zweites Off-site/Cold-Storage bewusst nicht umgesetzt.
|
||||
Status: Initiale Capacity-Baseline 2026-05-26; H:/-Nearline-Bewertung 2026-05-26; externe Cold-Storage-Groessen offen.
|
||||
|
||||
## Zweck
|
||||
|
||||
@@ -14,8 +14,8 @@ Dieses Dokument haelt Wachstum, Schwellenwerte und Upgrade-Trigger fest. Es verh
|
||||
| Disk1 / Array | 5.5T | 1.8T | 3.7T | 80 % Planung / 90 % Aktion | gruen, 33 % belegt |
|
||||
| User Shares gesamt | 5.5T | 1.8T | 3.7T | 80 % Planung / 90 % Aktion | gruen, entspricht aktuell Disk1 |
|
||||
| Backups lokal | 5.5T geteilter Array-Space | 2.2G unter `/mnt/user/backups` | 3.7T Share-frei | Review bei Borg-/Dump-Wachstum | lokal nicht unabhaengig vom Array |
|
||||
| Hetzner Borg | extern / Storage Box | nicht repo-seitig gemessen | nicht repo-seitig gemessen | Borg-Stale-Alert + Account-Review | einziges echtes Off-site-Ziel |
|
||||
| Externe Cold-Platte | nicht vorhanden | - | - | Review nur bei Trigger | bewusst nicht beschafft; zweites Off-site erst bei Hetzner-Problemen, stark wachsendem Datenwert oder geaenderter Betreiber-Praeferenz |
|
||||
| Hetzner Borg | TBD | TBD | TBD | TBD | TBD |
|
||||
| Externe Cold-Platte | TBD | TBD | TBD | TBD | TBD |
|
||||
|
||||
Pruefkommando:
|
||||
|
||||
@@ -32,7 +32,7 @@ du -sh /mnt/user/documents /mnt/user/photos /mnt/user/media /mnt/user/backups 2>
|
||||
| Medien | aktuell ca. 1.7T | groesster Speicherblock | Array-Erweiterung vor 80 % planen |
|
||||
| Immich Fotos/Videos | aktuell ca. 23G | hoechster privater Datentopf | Restore-Test priorisieren |
|
||||
| Paperless/Dokumente | aktuell ca. 199M im Documents-Share | wichtig, moderates Wachstum | Restore-Test existiert, Share-Wachstum beobachten |
|
||||
| Nextcloud | aktuell klein, kann durch Familiennutzung stark wachsen | Datenwachstum und Quotas koennen spaeter relevant werden | Quota/Backup bei Familien-Onboarding pruefen |
|
||||
| Nextcloud | TBD | Familiennutzung kann stark wachsen | Quota/Backup pruefen |
|
||||
| Monitoring/Loki | begrenzt durch Retention | Retention kann Disk fuellen | Retention und Volume-Groesse bei Reviews pruefen |
|
||||
| Borg Dumps | aktuell ca. 2.2G lokale Backups | Retention und Excludes pruefen | Borg-Stale + Groessenprofil |
|
||||
|
||||
@@ -51,48 +51,63 @@ du -sh /mnt/user/documents /mnt/user/photos /mnt/user/media /mnt/user/backups 2>
|
||||
|
||||
## H:/ als zusaetzliches lokales Backup-Ziel
|
||||
|
||||
`H:/` ist **keine echte Offsite-/Airgap-Kopie und kein Ersatz fuer Hetzner**. Es ist aber sinnvoll als zweite lokale Nearline-Kopie fuer kritische Restore-Quellen (Borg-Dumps, Repo-Bundles, Flash-Backup) und als Freeze-Sicherung vor strukturellen Eingriffen.
|
||||
Operator-Befund 2026-05-26: das Windows-Laufwerk `H:/` laeuft dauerhaft am Arbeits-PC und wurde bereits als `H:-Freeze-Backup` waehrend der Disk1 NTFS->XFS Phase 2 erfolgreich genutzt (siehe `docs/MIGRATION_LOG.md`).
|
||||
|
||||
### Eigenschaften von H:/
|
||||
|
||||
| Eigenschaft | Wert | Konsequenz |
|
||||
|---|---|---|
|
||||
| Anbindung | Windows-PC, dauerhaft verbunden | kein Air-Gap, kein Hardware-Trenn-Schutz |
|
||||
| Standort | gleicher physischer Standort wie Unraid-Host | kein Off-site, kein Schutz gegen Brand/Diebstahl/Wasser |
|
||||
| Schreibzugriff | dauerhaft moeglich | Ransomware oder Operator-Fehler koennen Original und Kopie gleichzeitig treffen |
|
||||
| Filesystem (Windows) | typischerweise NTFS | fuer Borg-Ziel ueber CIFS/SMB ungeeignet als Hard-Mount auf Unraid (STORAGE_LAYOUT §12.6) |
|
||||
| Reproduzierbar nutzbar | ja, bewaehrt durch Disk1-Phase-2-Freeze-Backup | Pull-Modell vom Windows-PC ist der getestete Weg |
|
||||
|
||||
### Bewertung
|
||||
|
||||
H:/ ist **keine echte Offsite-/Airgap-Kopie und kein Ersatz fuer Hetzner**. Es ist aber sinnvoll als:
|
||||
|
||||
- **Zweite lokale Nearline-Kopie** fuer kritische Restore-Quellen (Borg-Dumps, Repo-Bundles, Flash-Backup). Schnellster Restore-Pfad bei Hetzner-Stoerung, weil kein Off-site-Download noetig ist.
|
||||
- **Cold-Storage-Vorstufe**: wenn H:/ kuenftig periodisch (z. B. monatlich) physisch getrennt und durch eine zweite Platte ersetzt wird, wuerde sich daraus ein echtes Air-Gap-Rotationsschema ableiten lassen.
|
||||
- **Freeze-Sicherung** vor strukturellen Eingriffen (Disk-Tausch, Pool-Umzug, Format), wie bereits 2026-05-25 praktiziert.
|
||||
|
||||
### Empfohlene Nutzung
|
||||
|
||||
| Nutzung | Umsetzung | Hinweis |
|
||||
|---|---|---|
|
||||
| Pull von `/mnt/user/backups/borg/dumps/latest` auf H:/ | Windows Scheduled Task per `robocopy` | keine CIFS-Hard-Mounts auf Unraid |
|
||||
| Pull von `/mnt/user/backups/borg/dumps/latest` auf H:/ | Windows-seitiger Scheduled Task per `robocopy` oder `rclone` von einem SMB-Read-Share | keine CIFS-Hard-Mounts auf Unraid; STORAGE_LAYOUT-Konstitution bleibt erhalten |
|
||||
| Pull der Gitea-Bundles aus `/mnt/user/backups/git-bundles/gitea` | identisch | Bundles sind klein und schnell synchronisiert |
|
||||
| Pull des Unraid-Flash-Artefakts `unraid-flash-config.tar.gz` | bewusst nicht im H:/ Scope | Restore-Quelle bleibt Hetzner-Borg; Flash-Config wie Secret behandeln |
|
||||
| Pull des Unraid-Flash-Artefakts `unraid-flash-config.tar.gz` | identisch | wie Secret behandeln, Windows-seitig nicht in geteilten Ordnern ablegen |
|
||||
|
||||
Der konkrete Pull-Pfad ist in `ops/h-drive-nearline/README.md` und `ops/h-drive-nearline/pull-critical-backups.ps1` produktiv. Der Windows Scheduled Task `KalliLab H Drive Nearline Pull` laeuft seit 2026-05-28 taeglich 05:30.
|
||||
|
||||
| Abgrenzung | Bewertung | Begruendung |
|
||||
|---|---|---|
|
||||
| **Nicht** als Ersatz fuer Hetzner-Off-site | bewusst | 3-2-1 ist mit Hetzner als einzigem Off-site erfuellt; H:/ reduziert nur lokale Restore-Abhaengigkeit |
|
||||
| **Nicht** als zweites Borg-Repo am Unraid | bewusst | dauerhafte CIFS-Verbindung im Borg-Lauf verletzt Hard Rule aus `docs/STORAGE_LAYOUT.md` |
|
||||
Der konkrete Pull-Pfad ist in `docs/H_DRIVE_NEARLINE_PULL.md` und `ops/h-drive-nearline/pull-critical-backups.ps1` vorbereitet. Der Windows Scheduled Task wird erst nach Operator-Sichtpruefung aktiviert.
|
||||
| **Nicht** als Ersatz fuer Hetzner-Off-site | — | 3-2-1 bleibt mit Hetzner als einzigem Off-site weiterhin unerfuellt; siehe `docs/AUDIT_2026-05-25.md` F-03 |
|
||||
| **Nicht** als zweites Borg-Repo am Unraid | — | dauerhafte CIFS-Verbindung im Borg-Lauf verletzt Hard Rule §12.6 |
|
||||
|
||||
### Kapazitaets-Eintrag
|
||||
|
||||
| Bereich | Groesse | Belegt | Schwellwert | Bewertung |
|
||||
|---|---:|---:|---:|---|
|
||||
| H:/ (Windows-Arbeitsplatz, `Externe HDD`) | 8.0T | 3.91T belegt / 4.10T frei | Review wenn > 70 % | NTFS, `Healthy`; Pull-Ziel fuer Borg-Dumps und Gitea-Bundles |
|
||||
| H:/ (Windows-Arbeitsplatz, `Externe HDD`) | 8.0T | 3.91T belegt / 4.10T frei | Review wenn > 70 % | NTFS, `Healthy`; Pull-Ziel fuer Borg-Dumps, Gitea-Bundles und Flash-Backup |
|
||||
|
||||
### Naechste Schritte
|
||||
|
||||
- Task-Lauf quartalsweise gegen Reports unter `H:\kallilab-nearline-backups\_reports` pruefen.
|
||||
- Review-Intervall: quartalsweise. Bei jeder grossen Strukturaenderung Freeze-Pull manuell ausloesen.
|
||||
- Pull-Script (Operator-Aufgabe, kein Repo-Pflichtteil) etablieren; alternativ ueber Filebrowser/Nextcloud-Sync abdecken.
|
||||
- Review-Intervall: quartalsweise. Bei jeder grossen Strukturaenderung (Disk-Tausch, Pool-Umzug) Freeze-Pull manuell ausloesen.
|
||||
|
||||
## Restore-Zeitziele
|
||||
|
||||
| Tier | Beispiel | Zielzeit | Status |
|
||||
|---|---|---:|---|
|
||||
| Tier 0 | Repo, Secrets, Traefik, DNS | 2-4 h | Zielwert, per DR-Sanity-Check bestaetigen |
|
||||
| Tier 1 | Gitea, Vaultwarden, Paperless, Immich | 4-8 h | Zielwert, einzelne Restore-Tests vorhanden |
|
||||
| Tier 2 | Nextcloud, Mealie, Monitoring | < 24 h | Zielwert, Restore-Pfade dokumentiert |
|
||||
| Tier 3 | Komfort-/Ops-Tools | Best effort / rebuildbar | Zielwert, keine harte SLA |
|
||||
| Tier 0 | Repo, Secrets, Traefik, DNS | TBD | offen |
|
||||
| Tier 1 | Gitea, Vaultwarden, Paperless, Immich | TBD | offen |
|
||||
| Tier 2 | Nextcloud, Mealie, Monitoring | TBD | offen |
|
||||
| Tier 3 | Komfort-/Ops-Tools | TBD | offen |
|
||||
|
||||
## Review-Log
|
||||
|
||||
| Datum | Befund | Entscheidung |
|
||||
|---|---|---|
|
||||
| 2026-05-26 | Cache 6 %, Array/User-Shares 33 %, lokale Backups 2.2G; keine validierte USV-Abschaltung | Capacity gruen; USV wird aktuell nicht angeschafft, Power-Loss-Risiko bewusst akzeptiert; zweites Off-site/Cold-Storage bewusst nicht umgesetzt |
|
||||
| 2026-05-26 | H:/ als dauerhaft verbundenes Windows-Laufwerk evaluiert | als zweite lokale Nearline-Kopie und Freeze-Sicherung sinnvoll; nicht als Offsite-Ersatz und nicht als Borg-CIFS-Hard-Mount am Unraid |
|
||||
| 2026-05-26 | H:/ Kapazitaet erfasst: 8.0T NTFS, 3.91T belegt, 4.10T frei, `Healthy` | genug Reserve fuer Nearline-Pull der kritischen Restore-Artefakte |
|
||||
| 2026-05-27 | H:/ Pull-Workflow vorbereitet | SMB-Quelle `\\192.168.178.58\backups` erreichbar; PowerShell-Skript und Runbook erstellt |
|
||||
| 2026-05-28 | H:/ Pull-Workflow produktiv | Windows Scheduled Task `KalliLab H Drive Nearline Pull` taeglich 05:30 aktiv |
|
||||
| 2026-06-01 | H:/ Pull nach Redis-/Major-Cutover-Artefakten gehaertet | Borg-Dumps-Job kopiert nur kuratierte Pflichtdateien; manueller Kontrolllauf erzeugte Report `nearline-pull-2026-06-01-082553.md` |
|
||||
| 2026-05-26 | Cache 6 %, Array/User-Shares 33 %, lokale Backups 2.2G; keine validierte USV-Abschaltung | Capacity gruen; USV wird aktuell nicht angeschafft, Power-Loss-Risiko bewusst akzeptiert; externe Backup-/Cold-Storage-Groessen bleiben offen |
|
||||
| 2026-05-26 | H:/ als dauerhaft verbundenes Windows-Laufwerk evaluiert | als zweite lokale Nearline-Kopie und Freeze-Sicherung sinnvoll; nicht als Offsite-Ersatz und nicht als Borg-CIFS-Hard-Mount am Unraid; Pull-Modell vom Windows-PC bleibt der getestete Weg |
|
||||
| 2026-05-26 | H:/ Kapazitaet erfasst: 8.0T NTFS, 3.91T belegt, 4.10T frei, `Healthy` | genug Reserve fuer Nearline-Pull der kritischen Restore-Artefakte; Pull-Schedule bleibt offen |
|
||||
| 2026-05-27 | H:/ Pull-Workflow vorbereitet | SMB-Quelle `\\192.168.178.58\backups` erreichbar; PowerShell-Skript und Runbook erstellt; empfohlener Schedule taeglich 05:30, aber Task noch nicht aktiviert |
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Codex-Prompt: KalliLab Endstufe
|
||||
|
||||
Du hast Vollzugriff auf `G:\Gitea_Clone\homelab-infra`, Gitea-Push, Komodo, und SSH auf Unraid `Kallilabcore`.
|
||||
|
||||
## Lies zuerst
|
||||
1. `CLAUDE.md`
|
||||
2. `docs/AUDIT_2026-05-23.md` — dort steht die komplette Restliste
|
||||
|
||||
## Auftrag
|
||||
Den Audit von oben verifizieren und die offenen Punkte abarbeiten, bis das Homelab in der Endstufe ist. Reihenfolge:
|
||||
|
||||
1. **P0** — Lokalen Commit `cd650b1` nach Gitea pushen, danach Komodo-Reaktion fuer `gitea` und `borg-ui` pruefen.
|
||||
2. **P0** — Live-Daten aus Audit-Abschnitt 9 messen und in `docs/AUDIT_2026-05-23_LIVE.md` ablegen (Secrets redacten).
|
||||
3. **P1** — Monitoring-Stack (`monitoring/`) live deployen, alte `ops/grafana-influxdb` und `ops/loki` `down` (nicht loeschen).
|
||||
4. **P1** — Jellyfin und Plex in `HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md` nachtragen. Plex-Eintrag "nicht als Repo-Stack enthalten" korrigieren.
|
||||
5. **P2** — Borg-Lauf-Frische pruefen, ggf. neuen Lauf ausloesen, alle 14 Dump-Artefakte juenger als 24 h.
|
||||
6. **P3** — Repo-Hygiene: 8 leere Verzeichnisse weg, `.serena/` in `.gitignore`, Entscheidung zu `ops/windows-reinstall/*.ps1`.
|
||||
|
||||
## Regeln (aus CLAUDE.md, nicht verhandelbar)
|
||||
- Secrets nie im Klartext ausgeben.
|
||||
- Keine Aenderungen direkt in Komodo, nur ueber Git → Push → Komodo.
|
||||
- Kein `push --force`, kein blindes Loeschen von `/mnt/user/{appdata,documents,photos,services,backups}`.
|
||||
- Working-Tree-Status nur aus `git status --short` ableiten, nie aus `git diff` ueber Linux-Mount.
|
||||
- Traefik dynamic config wird nicht von Komodo deployed — Aenderungen dort manuell auf `/mnt/user/appdata/traefik/dynamic/` syncen.
|
||||
- Nicht anfassen: Hermes, Disk1 NTFS Phase 2, Komodo-Auth, Grafana/InfluxDB `user: "0"`, Image-Pinning ddns/glances/scrutiny.
|
||||
- Wenn zwei Reparaturversuche scheitern: stoppen, Drift-Runbook Pflichtmatrix, Operator fragen.
|
||||
|
||||
## Arbeitsmodus pro Block
|
||||
Lesen → minimal aendern → `ops/policy-checks/check_repo.ps1` lokal → Commit → Push → Komodo-Reaktion + Smoke-Test → eine Zeile in `docs/MIGRATION_LOG.md`.
|
||||
|
||||
## Fertig
|
||||
Wenn alles abgearbeitet ist (oder ein Punkt bewusst offen bleibt): `docs/AUDIT_2026-05-23_FINAL.md` schreiben mit Ampel + konkretem Beleg pro Punkt, committen, pushen, kurz an mich melden.
|
||||
@@ -1,169 +0,0 @@
|
||||
# Entscheidungs-Register (ADR-light)
|
||||
|
||||
Typ: Entscheidung · Stand: 2026-06-11 · Status: aktiv
|
||||
|
||||
Zentrales Register fuer Architektur- und Betriebsentscheidungen. Neueste oben.
|
||||
Jeder Eintrag: Entscheidung, Kontext, ggf. Alternativen und Review-Trigger.
|
||||
Lange Incident-Erzaehlungen gehoeren nicht hierher, sondern in den Commit bzw.
|
||||
Host-Report; hier steht das Destillat. Vorher lebten diese Eintraege verstreut
|
||||
in `HOMELAB_ARCHITECTURE_MASTER_V2.md` §13, `docs/MASTER_TODO.md` (Geparkt),
|
||||
`docs/HARDWARE_INVENTORY.md` und der Audit-Restliste.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-12 - Home Assistant als Container im GitOps-Stack
|
||||
|
||||
**Entscheidung:** Home Assistant laeuft neu als `homeassistant` Container im
|
||||
Stack `smart-home/`, nicht als HAOS-VM und nicht als Supervised-Installation.
|
||||
Mosquitto laeuft als eigener Container im selben Stack; Zigbee2MQTT und ESPHome
|
||||
werden spaeter ebenfalls als eigenstaendige Container ergaenzt. HA haengt in
|
||||
`frontend_net` fuer Traefik und in `smarthome_net` fuer MQTT/Zigbee2MQTT/ESPHome.
|
||||
Das Fachrepo `smart-home-kalli` liefert versionierte HA-YAML-Dateien read-only;
|
||||
`.storage`, `secrets.yaml` und Integrations-State bleiben in
|
||||
`/mnt/user/appdata/homeassistant`.
|
||||
|
||||
**Kontext:** Das fruehere HAOS-VM-Setup ging bei einem Crash ohne brauchbares
|
||||
Backup verloren. Das Homelab betreibt produktive Dienste inzwischen ueber
|
||||
Gitea, Komodo, Compose, Renovate und Borg. HA Container passt in dieses
|
||||
Betriebsmodell und vermeidet eine zweite Update-/Backup-Welt. Supervised ist
|
||||
kein Zielpfad mehr; HAOS bleibt die Alternative, falls Add-on-Komfort,
|
||||
Matter/Thread/HomeKit-Discovery oder Host-nahe HA-Funktionen wichtiger werden
|
||||
als GitOps-Konformitaet.
|
||||
|
||||
**Review-Trigger:** Viele mDNS-/SSDP-abhaengige lokale Integrationen
|
||||
(HomeKit, Cast, Matter/Thread), Bedarf an HA-Add-ons als Betriebsstandard,
|
||||
oder wiederholte Probleme durch Bridge-Netzwerkbetrieb.
|
||||
|
||||
## 2026-06-12 - Ecowitt-Ingress bleibt bewusste Phase-2-Entscheidung
|
||||
|
||||
**Entscheidung:** In Phase 1 wird kein Host-Port `8123` fuer Home Assistant
|
||||
veroeffentlicht. Ecowitt wird spaeter entweder ueber eine gezielte
|
||||
Traefik-HTTP-Ausnahme fuer den Webhook-Pfad angebunden oder, falls der globale
|
||||
HTTP-zu-HTTPS-EntryPoint-Redirect nicht sauber selektiv abloesbar ist, ueber
|
||||
einen dokumentierten LAN-only Host-Port `8123`.
|
||||
|
||||
**Kontext:** Ecowitt kann nur HTTP und kein HTTPS. Traefik hat aktuell einen
|
||||
globalen `web` -> `websecure` Redirect auf EntryPoint-Ebene. Ein normaler
|
||||
HTTP-Router kann diese Regel voraussichtlich nicht umgehen, ohne Traefik selbst
|
||||
umzubauen. Deshalb wird die Entscheidung nicht vorgezogen.
|
||||
|
||||
**Review-Trigger:** Start der Ecowitt-/InfluxDB-Phase oder Umbau der Traefik
|
||||
HTTP-Redirect-Architektur.
|
||||
|
||||
## 2026-06-11 — Host-DNS-Fallback aktiv (AdGuard-SPOF entschaerft)
|
||||
|
||||
**Entscheidung:** Unraid-Host nutzt `eth0` DNS server 1 = `192.168.178.58` (AdGuard) und **DNS server 2 = `192.168.178.1`** (FRITZ!Box) als Failover.
|
||||
**Kontext:** AdGuard war einziger LAN-Resolver; ein Recreate hat 2026-06 einen Bulk-Deploy zerlegt, weil Docker-Pulls am eigenen DNS-Container scheiterten. Der Fallback bleibt nur passiv aktiv (Go-Resolver springt erst bei Socket-Fehler weiter), der Filter wirkt im Normalbetrieb unveraendert. `options rotate` ist nicht gesetzt. Umsetzung der Empfehlung 3a aus dem Optimierungs-Assessment vom 2026-06-10. Runbook: `docs/runbooks/komodo-bulk-deploy-dns.md`.
|
||||
**Review-Trigger:** Wenn AdGuard durch eine andere Filter-Loesung ersetzt wird oder ein zweiter Host-Resolver verfuegbar ist.
|
||||
|
||||
## 2026-06-11 — Hetzner Storage Box: automatische Snapshots aktiv
|
||||
|
||||
**Entscheidung:** Automatische Snapshots auf der Hetzner Storage Box (BX11, `u565255.your-storagebox.de`) sind aktiv: taeglich um 05:30 UTC (nach dem Borg-Lauf 04:30 lokal), Retention 7 Tage, Snapshot-Verzeichnis sichtbar fuer Einzeldatei-Restore via `.zfs/snapshot/`.
|
||||
**Kontext:** Borg `append-only` ist bewusst nicht umgesetzt (siehe Eintrag 2026-06-01); damit war ein kompromittierter Host bisher in der Lage, auch das Off-site-Backup zu loeschen. Storage-Box-Snapshots sind host-seitig nicht loeschbar und im BX11-Tarif inklusive. Kosten: 0 EUR zusaetzlich. Umsetzung der Empfehlung 2 aus dem Optimierungs-Assessment vom 2026-06-10.
|
||||
**Review-Trigger:** Hetzner-Quota-Druck (aktuell 65 GB / 1 TB - viel Luft) oder Aenderung der Backup-Strategie.
|
||||
|
||||
## 2026-06-11 — Doku-Konsolidierung: ein Fakt, ein Zuhause
|
||||
|
||||
**Entscheidung:** Die Dokumentation wird nach `docs/archive/2026/homelab-doku-optimierung-2026-06-11.md` konsolidiert: `MASTER_TODO.md` ist die einzige Statusliste, dieses Register die einzige Entscheidungssammlung, `docs/archive/` nimmt abgeschlossene Snapshots auf, Erledigtes verlaesst die Arbeitskopie. Keine Ordner-Restruktur des Bestands.
|
||||
**Kontext:** 74 Markdown-Dateien / ~9.400 Zeilen; einzelne Sachverhalte waren an 6–9 Stellen dokumentiert; vier parallele Statuslisten.
|
||||
**Review-Trigger:** Quartals-Gaertnern (siehe `docs/REPO_MAP.md` Doku-Regeln).
|
||||
|
||||
## 2026-06-06 — baerchen: BitLocker und Veeam Storage Encryption bewusst aus
|
||||
|
||||
**Entscheidung:** BitLocker bleibt auf allen Laufwerken deaktiviert; Veeam Storage Encryption bleibt aus (`StorageEncryptionEnabled=False`).
|
||||
**Kontext:** Recovery laeuft ueber das Veeam-Image auf dem lokalen SMB-Share; kein Key-Management-Aufwand, Restrisiko physischer Diebstahl akzeptiert.
|
||||
**Review-Trigger:** Off-host-Auslagerung des Windows-Images oder geaendertes Risikoprofil. Runbook: `ops/windows-reinstall/docs/windows-image-backup-baseline.md`.
|
||||
|
||||
## 2026-06-06 — Tailscale: natives Unraid-Plugin kanonisch, restriktive ACL
|
||||
|
||||
**Entscheidung:** Tailscale laeuft ausschliesslich als natives Unraid-Plugin (`tailscale.plg`, Subnet-Router, State im Flash-Backup); der redundante userspace-Docker-Stack `host-services/tailscale/` wurde entfernt. Tailnet-ACL ist tag-basiert restriktiv (`tag:server`/`tag:operator`, `tag:family` schlafend), Default-Allow entfernt.
|
||||
**Kontext:** Zwei parallele `tailscaled`-Instanzen; nur die Plugin-Instanz routet. Details: `docs/NETWORK_INVENTORY.md`.
|
||||
**Review-Trigger:** Erstes reales Familiengeraet (Familien-Dienste in ACL konkretisieren).
|
||||
|
||||
## 2026-06-06 — Authelia: 2FA-Catch-all aktiv, OIDC-Rollout gestaffelt
|
||||
|
||||
**Entscheidung:** Catch-all `*.kaleschke.info` -> `two_factor` in Repo- und Host-Config. OIDC-SSO wird app-weise ausgerollt (live: Grafana, Mealie; deployed: Paperless). Immich- und Nextcloud-OIDC sowie Nextcloud-Operator-TOTP sind geparkt, bis Familien-Accounts existieren.
|
||||
**Kontext:** Nur der Operator hat aktuell einen Authelia-Account; Familien-SSO-Nutzen entsteht erst mit dem Onboarding. Runbook: `docs/AUTHELIA_OIDC_PLAN.md`.
|
||||
**Review-Trigger:** Family-Onboarding erreicht die App-Login-Ebene.
|
||||
|
||||
## 2026-06-05 — USV geparkt, Cold-Backup Hetzner-only, kein Strom-Monitoring
|
||||
|
||||
**Entscheidung:** Keine USV-Anschaffung dieses Quartal (Power-Loss bewusst akzeptiert). Off-site bleibt allein Hetzner-Borg, keine zweite rotierende Cold-Kopie. Stromverbrauch wird nicht gemessen (kein Messgeraet, kein Beschaffungs-Todo).
|
||||
**Review-Trigger:** USV: Q3-Review ab 2026-07-01, Hardware-Upgrade oder realer Stromausfall mit Datenfolge. Cold-Backup: Hetzner-Probleme oder stark wachsender Datenwert. Strom: nur bei Anschaffung eines Messgeraets.
|
||||
|
||||
## 2026-06-03 — Fix Common Problems Plugin entfernt, keine Neuinstallation
|
||||
|
||||
**Entscheidung:** FCP wurde deinstalliert und wird bewusst nicht wieder installiert.
|
||||
**Kontext:** Ein FCP-Scan hing 7 Tage in einem `grep -R`-Symlink-Loop ueber das gesamte Array (3 Cores 100 %, IOWAIT bis 55 %, Load 14.6 -> 1.08 nach Entfernung). Die abgedeckten Risiken uebernehmen Scrutiny, Monitoring-Stack, Posture-Check und Critical-Events-Watcher.
|
||||
**Review-Trigger:** keiner; Entscheidung ist final.
|
||||
|
||||
## 2026-06-01 — Borg append-only auf Hetzner nicht umgesetzt
|
||||
|
||||
**Entscheidung:** Kein append-only/forced-command auf der Storage Box.
|
||||
**Kontext:** Der forced-command-Test brach die Key-Auth und musste per Passwort-Recovery zurueckgesetzt werden; Nutzen/Betriebsrisiko-Verhaeltnis unguenstig. Kompensation (Storage-Box-Snapshots) siehe `docs/homelab-optimierung.md` Empfehlung 2.
|
||||
**Review-Trigger:** Hetzner bietet robusteren Mechanismus, oder Ransomware-Risikoprofil aendert sich.
|
||||
|
||||
## 2026-05-28 — Plex: Reclaim, Traefik-Route ohne ForwardAuth, kein Remote Access
|
||||
|
||||
**Entscheidung:** Plex-Server ist als Operator-Konto geclaimt; externer Zugriff laeuft ausschliesslich ueber Traefik/443 (`plex.kaleschke.info`, File-Provider-Ausnahme wegen Host-Netz), Plex Remote Access und WAN-Port 32400 bleiben aus, keine Authelia-ForwardAuth (native Plex-Auth).
|
||||
**Kontext:** Preferences waren nach dem Mai-Crash jungfraeulich; Claim-Token wurde nur als Shell-Inline-ENV genutzt, nie persistiert. Details: `docs/SERVICE_CATALOG.md`, `HOMELAB_ARCHITECTURE_MASTER_V2.md` §10.
|
||||
|
||||
## 2026-05-28 — Gitea-SSH (222) bleibt ohne WAN-Freigabe
|
||||
|
||||
**Entscheidung:** Port 222 wird nicht in der FRITZ!Box freigegeben.
|
||||
**Kontext:** Tailscale ist der Operator-Pfad, der GitHub-Mirror deckt DR-Bootstrap ab, SSH-Brute-Force-Vektor extern vermeiden.
|
||||
|
||||
## 2026-05-28 — paperless-gpt und BentoPDF bleiben aktiv
|
||||
|
||||
**Entscheidung:** Beide Container bleiben trotz geringer Nutzung. paperless-gpt-Abloese wird erst mit Paperless-NGX 3.0 (eigene KI-Features) neu bewertet; BentoPDF ist situatives Tool mit vernachlaessigbarem Footprint und ersetzt Stirling-PDF.
|
||||
**Review-Trigger:** Paperless-NGX-3.0-Release.
|
||||
|
||||
## 2026-05-26 — AdGuard-Admin nur auf Tailscale-IP, ohne Traefik/2FA
|
||||
|
||||
**Entscheidung:** Admin-UI bleibt auf `100.80.98.33:8082` (Tailscale-only) gebunden; bewusst keine Traefik-/2FA-Umstellung. DNS-Port 53 bleibt direkte Host-Port-Ausnahme.
|
||||
**Review-Trigger:** Aenderung des Tailnet-Zugangsmodells.
|
||||
|
||||
## 2026-05-25 — Ein Dienst pro Funktion: Jellyfin, Homepage, Uptime-Kuma entfernt
|
||||
|
||||
**Entscheidung:** Plex ist der einzige Medienserver, Glance das einzige Dashboard, Blackbox-Exporter + Prometheus-Alerts + Grafana ersetzen Uptime-Kuma.
|
||||
**Kontext:** Doppelte Dienste = doppelte Pflege/Attack-Surface. Removal-Checkliste: `docs/WORKFLOW.md`.
|
||||
|
||||
## 2026-05-17 — Monitoring-/Logging-Baseline
|
||||
|
||||
**Entscheidung:** `monitoring/` ist der einzige Observability-Stack (Prometheus, Loki, Promtail, Grafana, Exporter, InfluxDB 3 Core). Loki intern ohne Route, Promtail mit read-only Docker-Socket, Loki-Daten sind Diagnosematerial mit Retention, keine Restore-Quelle. Alte Pfade `ops/loki`/`ops/grafana-influxdb` sind entfernt (Rollback nur via Git-Historie).
|
||||
|
||||
## 2026-05-05 — Stateful Digest-Pinning und Versionspolitik
|
||||
|
||||
**Entscheidung:** Tier-1-/stateful Dienste laufen mit sprechendem Versions-Tag plus Digest (z. B. `postgres:17.x@sha256:...`); mutable Tags wurden 2026-04-17 auf laufende Digests eingefroren. Digest-Pinning ist Reproduzierbarkeit, kein Upgrade-Mechanismus; echte Upgrades sind eigene Aenderungsbloecke. Renovate (live seit 2026-05-29) liefert PRs, kein Auto-Merge.
|
||||
**Review-Trigger:** Mutable-Tag-Restbestand siehe `docs/homelab-optimierung.md` Empfehlung 1.
|
||||
|
||||
## 2026-05-04 — Authelia ohne Redis-Session-Backend
|
||||
|
||||
**Entscheidung:** Authelia nutzt PostgreSQL fuer Storage, aber kein Redis-Session-Backend; nach Restart werden Sessions neu aufgebaut.
|
||||
**Kontext:** Haelt den Tier-1-Auth-Pfad einfach. `infra/redis` ist faktisch nur Paperless-Cache; Konsolidierung nach `apps/paperless/` bleibt denkbar, unpriorisiert.
|
||||
|
||||
## 2026-05-04 — Komodo-Self-Stack: Reconcile-Regel nach Drift
|
||||
|
||||
**Entscheidung:** Der Komodo-Self-Stack laeuft aus `/mnt/user/services/stacks/komodo/compose.yaml` (Quelle: `ops/komodo/docker-compose.yml`). Bei Self-Stack-Drift kein pauschales `docker compose up -d`, wenn der Dry-run `komodo-mongo` recreaten wuerde; Core/Periphery gezielt mit `--no-deps` neu erstellen, Mongo unangetastet lassen.
|
||||
**Kontext:** Drift-Recovery 2026-05-04 (Repair-YAMLs aus `/tmp`); Sicherungen unter `/mnt/user/appdata/komodo/_drift_backup_2026-05-04/`.
|
||||
|
||||
## 2026-04-19 — Nextcloud als klassischer Stack, nicht AIO; native Auth
|
||||
|
||||
**Entscheidung:** Nextcloud laeuft als App + eigene PostgreSQL + eigene Redis (kein AIO), ohne zentrale ForwardAuth (Browser-/Client-/WebDAV-Flows brauchen native Auth).
|
||||
|
||||
## 2026-04-12 — Borg-Scope enthaelt bewusst /local/secrets
|
||||
|
||||
**Entscheidung:** Borg sichert ausgewaehltes Secret-Material (`/local/secrets`) als Teil der DR-Strategie; `borg-ui` hat dafuer breite, bewusste Mounts. Dumps statt Raw-DB-Pfade sind der primaere Restore-Weg.
|
||||
**Kontext:** `ops/borg-ui/BACKUP_SCOPE.md`.
|
||||
|
||||
## 2026-03-28/29 — GitOps-Fundament
|
||||
|
||||
**Entscheidung:** Komodo ersetzt Portainer als alleiniger Stack-Manager (Docker-Socket-Ausnahme, native Auth ohne pauschale ForwardAuth wegen Webhooks/`/ws/periphery`). Traefik routet ausschliesslich ueber Docker-Labels; File-Provider nur fuer `middlewares.yml`, `tls.yml`, `dashboards.yml` (+ dokumentierte `plex.yml`-Ausnahme). AdGuard Home + Unbound ersetzen Pi-hole.
|
||||
**Kontext:** Konkurrierende `@file`-/`@docker`-Router hatten Fehlrouting verursacht; Regel: keine neuen Service-Routen im File-Provider.
|
||||
|
||||
## Aelteres / Sonderfaelle
|
||||
|
||||
- **Paperless Stack-ENV-Ausnahme:** `PAPERLESS_DBPASS`/`PAPERLESS_REDIS` bleiben Komodo-Stack-ENV (kein `_FILE`-Support im Image); Konsequenzen fuer DR siehe `docs/DISASTER_RECOVERY.md` Phase 2.
|
||||
- **ddns-updater in `frontend_net`:** braucht Cloudflare-API; `backend_net` ist internal.
|
||||
- **mail-archiver Hybrid:** `frontend_net` (IMAP) + `backend_net` (DB), App-Auth zusaetzlich zu Authelia.
|
||||
- Vollstaendige technische Ausnahmen-Liste mit Begruendung: `HOMELAB_ARCHITECTURE_MASTER_V2.md` §10 (bleibt dort autoritativ).
|
||||
+13
-154
@@ -8,7 +8,7 @@ Verwandte Dokumente:
|
||||
|
||||
- `docs/ROLLBACK.md` - Rueckweg bei Fehlern im laufenden GitOps-Betrieb
|
||||
- `docs/RESTORE_MATRIX.md` - Restore-Quellen und Verifikationsregeln pro Dienst
|
||||
- `ops/restore-tests/README.md` - Restore-Test-Betrieb und Werkzeuge
|
||||
- `docs/RESTORE_HANDBOOK.md` - praktische Restore-Betriebsanleitung
|
||||
- `docs/SERVICES_RECOVERY.md` - Recovery-kritische `/mnt/user/services`-Pfade, Gitea-Mirror und Komodo-Bootstrap
|
||||
- `docs/EXTERNAL_DEPENDENCIES.md` - externe Provider/Konten und Ausfall-Szenarien
|
||||
- `ops/borg-ui/BACKUP_SCOPE.md` - Zielbild des Borg-Scopes
|
||||
@@ -62,8 +62,7 @@ Diese Punkte sollten **vor** einem echten Ausfall geklaert sein:
|
||||
|
||||
| Thema | Sollzustand |
|
||||
|---|---|
|
||||
| Repo-Zugang ausserhalb von Gitea | privater GitHub-Push-Mirror `michaelkaleschke-spec/homelab-infra` und lokaler aktueller Clone vorhanden; fuer Bare-Metal-DR zusaetzlich Read-Only-PAT/Deploy-Key offline im DR-Kit |
|
||||
| Operator-DR-Workstation | Gaming-PC mit aktuellem Repo-Clone, WSL2 + Borg-Client, SSH-Key fuer Hetzner Storage Box, Offline-Kopie Borg-Passphrase; Bestandteile siehe `docs/EXTERNAL_DEPENDENCIES.md` Abschnitt "DR-Workstation Bare-Metal-Kit" |
|
||||
| Repo-Zugang ausserhalb von Gitea | privater GitHub-Push-Mirror `michaelkaleschke-spec/homelab-infra` und lokaler aktueller Clone vorhanden |
|
||||
| Unraid USB-/Flash-Backup | `unraid-flash-config.tar.gz` wird vor Borg unter `/mnt/user/backups/borg/dumps/latest` erzeugt und nach Hetzner/Borg gesichert; Unraid-Connect-Cloud-Backup optional zusaetzlich |
|
||||
| Borg-Ziel | nicht nur lokal auf demselben Ausfallpfad |
|
||||
| Borg-Passphrase | Host-Secret-Datei vorhanden und fuer Borg-Zugriff verifiziert; externe Offline-Hinterlegung vom Operator am 2026-05-26 bestaetigt |
|
||||
@@ -88,15 +87,9 @@ Deshalb gilt:
|
||||
|
||||
Verfuegbare Wege:
|
||||
|
||||
- externer Push-Mirror: `https://github.com/michaelkaleschke-spec/homelab-infra` (privat, Read-PAT/Deploy-Key noetig — siehe `docs/EXTERNAL_DEPENDENCIES.md` Abschnitt "DR-Workstation Bare-Metal-Kit")
|
||||
- lokaler Bare-Clone auf der Operator-DR-Workstation (Standardweg)
|
||||
- normaler lokaler Arbeits-Clone auf der Operator-DR-Workstation
|
||||
|
||||
Operativer Pfad fuer den Repo auf den frisch installierten Unraid-Host:
|
||||
|
||||
1. Operator-DR-Workstation holt den aktuellen Clone (lokaler Stand oder per `git clone` aus dem GitHub-Mirror mit dem offline gesicherten Read-PAT/Deploy-Key).
|
||||
2. Kopie via USB, SMB oder `rsync ueber SSH/Tailscale` nach `/mnt/user/services/homelab-infra/` auf dem Unraid-Host.
|
||||
3. Stand pruefen: `git -C /mnt/user/services/homelab-infra log --oneline -1` zeigt einen plausibel aktuellen Commit.
|
||||
- externer Push-Mirror: `https://github.com/michaelkaleschke-spec/homelab-infra`
|
||||
- lokaler Bare-Clone auf dem PC
|
||||
- normaler lokaler Arbeits-Clone auf dem PC
|
||||
|
||||
Wenn **weder GitHub-Mirror noch lokaler Repo-Clone** verfuegbar sind, ist `services/gitea/data` selbst ein kritischer Restore-Pfad.
|
||||
|
||||
@@ -155,12 +148,6 @@ Erwartete Basis unter `/mnt/user/appdata/secrets/`:
|
||||
- `redis_password.txt`
|
||||
- `borg_repo_passphrase.txt`
|
||||
- `vaultwarden_admin_token.txt`
|
||||
- `homelab_smtp_password.txt`
|
||||
- `n8n_encryption_key.txt`
|
||||
- `monitoring_grafana_admin_password.txt`
|
||||
- `monitoring_grafana_influxdb_token.txt`
|
||||
- `influxdb3_admin_token.json`
|
||||
- `filebrowser_admin_password.txt`
|
||||
- `hermes_runner_id_ed25519`
|
||||
|
||||
Weitere relevante Secret-Pfade:
|
||||
@@ -254,52 +241,17 @@ Besonders kritisch:
|
||||
|
||||
**Nicht blind alles extrahieren**, wenn nur einzelne Pfade oder Dienste betroffen sind.
|
||||
|
||||
### 7.3 Borg-Extract ohne `borg-ui`-Container
|
||||
|
||||
Im Bare-Metal-Fall ist `borg-ui` selbst kalt. Der initiale Borg-Extract laeuft deshalb nicht ueber den Container, sondern wahlweise ueber:
|
||||
|
||||
1. **Operator-DR-Workstation** (Standardweg) - WSL2 + `borgbackup` extrahieren gezielt nach `/mnt/user/backups/restore-lab/...` oder per `rsync`/SMB auf den Unraid-Host.
|
||||
2. **Native Docker-Variante auf Unraid** - `docker run --rm -e BORG_PASSPHRASE=... -v /mnt/user/backups/restore-lab:/restore -v ~/.ssh:/root/.ssh:ro borgbackup/borg:1.4 ...`.
|
||||
|
||||
Erst nach Stufe 5 Phase 4 ist `borg-ui` produktiv und uebernimmt den weiteren Betrieb. Die Borg-Passphrase wird interaktiv aus der Offline-Sicherung eingegeben, nicht in Skripte/Tickets kopiert.
|
||||
|
||||
---
|
||||
|
||||
## 8. Phase 4 - Bootstrap-Reihenfolge der Stacks
|
||||
|
||||
**Nie alle Stacks gleichzeitig starten.**
|
||||
|
||||
### Stufe 0 - Docker-Grundlage
|
||||
|
||||
Vor dem ersten `docker compose up` muss sichergestellt sein:
|
||||
|
||||
1. `docker info` antwortet ohne Fehler.
|
||||
2. Externe Docker-Netze existieren. Wenn nicht vorhanden:
|
||||
|
||||
```bash
|
||||
docker network create --driver bridge frontend_net
|
||||
docker network create --driver bridge --internal backend_net
|
||||
docker network create --driver bridge monitoring_net
|
||||
```
|
||||
|
||||
3. Pfad `/mnt/user/appdata/traefik/dynamic/` enthaelt `middlewares.yml`, `tls.yml`, `dashboards.yml` (Sonderregel siehe Sektion 10). Ohne diese Dateien startet Traefik ohne Middleware-Definitionen und alle Authelia-geschuetzten Routen brechen still.
|
||||
|
||||
Erfolgskriterium: `docker network ls` zeigt `frontend_net`, `backend_net`, `monitoring_net`; Traefik-`dynamic/`-Dateien sind vorhanden und valide.
|
||||
|
||||
### Stufe 1 - Netz und Zugang
|
||||
|
||||
1. `traefik/`
|
||||
2. `host-services/Adguard/`
|
||||
|
||||
> **Tailscale-Hinweis:** Tailscale laeuft als **natives Unraid-Plugin**
|
||||
> (`tailscale.plg`, Interface `tailscale1`, State `/boot/config/plugins/tailscale/state`,
|
||||
> im Flash-Backup gesichert) und ist der Subnet-Router fuer `192.168.178.0/24`.
|
||||
> Es ist **kein** Compose-/Komodo-Stack mehr und kommt mit dem Host hoch — daher
|
||||
> nicht in dieser Bootstrap-Liste. Der frueher hier gelistete Docker-Stack
|
||||
> `host-services/tailscale/` (userspace-only, redundant) wurde am 2026-06-06
|
||||
> entfernt (siehe `docs/NETWORK_INVENTORY.md`).
|
||||
|
||||
**LE-Rate-Limit-Vorsicht:** Wenn `/mnt/user/appdata/traefik/letsencrypt/acme.json` verloren oder unklar ist, zuerst gegen Let's Encrypt Staging ausstellen lassen (`--certificatesresolvers.le.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory`). Erst nach gruenem Smoke wieder auf Production-CA. Hintergrund: 50 Zertifikate pro Domain pro Woche reicht bei einem hektischen Wiederanlauf nicht, wenn man die Sub-Domains mehrfach hochzieht.
|
||||
3. `host-services/tailscale/`
|
||||
|
||||
Ziel:
|
||||
|
||||
@@ -309,7 +261,7 @@ Ziel:
|
||||
|
||||
### Stufe 2 - Gemeinsame Backends und Identity
|
||||
|
||||
4. `infra/postgresql17/` (PostgreSQL 18 runtime, historischer Stack-Name bleibt fuer Service-DNS stabil)
|
||||
4. `infra/postgresql17/`
|
||||
5. `security/authelia/`
|
||||
6. `infra/redis/`
|
||||
7. `core/gitea/`
|
||||
@@ -338,13 +290,6 @@ Ziel:
|
||||
- Periphery verbindet sich wieder
|
||||
- Stacks koennen wieder aus Git konsumiert werden
|
||||
|
||||
**Wichtige Stolperfallen in Stufe 3:**
|
||||
|
||||
- **KOMODO_*-Werte sind nicht aus dem eigenen Mongo-Dump rekonstruierbar.** Pflichtquelle im Bare-Metal: offline gesicherte Operator-Notiz (Status 2026-06-03: noch nicht angelegt, siehe `docs/EXTERNAL_DEPENDENCIES.md` und Audit-Restliste). Vaultwarden ist erst in Stufe 4 verfuegbar.
|
||||
- **Mongo-Datadir und `komodo_mongo_password.txt` muessen aus demselben Snapshot stammen.** Bei Mismatch akzeptiert Mongo den Login nicht und der Stack startet nicht. Auswege: entweder die zur Datadir passende Secret-Datei aus dem gleichen Borg-Stand restaurieren, oder Datadir leeren, neu initialisieren und Daten via `mongorestore --archive --gzip` aus `komodo-mongo.archive.gz` einspielen (Drill belegt 2026-06-03).
|
||||
- **`extra_hosts: git.kaleschke.info:192.168.178.58`** in `ops/komodo/docker-compose.yml` ist hardgecodet. Bei geaenderter Host-LAN-IP auf der Recovery-Hardware den Wert vor `compose up` anpassen, sonst kann Komodo-Core das interne Gitea nicht erreichen.
|
||||
- **Stack-ENV-Werte fuer Apps in Stufe 4** (Paperless/Immich/Mailarchiver/Speedtest) sind in Stufe 3 noch leer. Zwei Wege: (a) optionaler `mongorestore` aus `komodo-mongo.archive.gz` direkt nach Komodo-Start, dann sind alle Stack-ENVs zurueck; (b) Werte manuell in der Komodo-UI eintragen, sobald Vaultwarden in Stufe 4 verfuegbar ist (was Paperless/Immich/Mailarchiver hinter Vaultwarden zwingt, nicht parallel).
|
||||
|
||||
### Stufe 4 - Kritische Anwendungen
|
||||
|
||||
9. `security/vaultwarden/`
|
||||
@@ -397,7 +342,6 @@ Ziel:
|
||||
- Mealie startet
|
||||
- Mail-Archiver startet
|
||||
- Nextcloud startet und sieht Dateien
|
||||
- Pro App: `docker logs <container>` zeigt keine `password authentication failed`-, `FATAL: role does not exist`- oder `Connection refused`-Eintraege (verifiziert, dass Stack-ENV-Werte und DB-Rollen passen)
|
||||
|
||||
### 9.4 Backup-/Beobachtungsebene
|
||||
|
||||
@@ -438,7 +382,7 @@ Vor dem Start muessen vorhanden sein:
|
||||
- `/mnt/user/appdata/secrets/authelia_smtp_password.txt`
|
||||
- SMTP-Zugang fuer `michideheld@gmx.de`
|
||||
|
||||
Beim Smoke-Test muss `authelia config validate` erfolgreich sein; der SMTP-Startup-Check darf den Start nicht blockieren.
|
||||
Beim Smoke-Test muss `authelia validate-config` erfolgreich sein; der SMTP-Startup-Check darf den Start nicht blockieren.
|
||||
|
||||
### `nextcloud`
|
||||
|
||||
@@ -452,12 +396,6 @@ Vor dem Start muessen vorhanden sein:
|
||||
|
||||
Zusaetzlich muss der Nutzdatenpfad `/mnt/user/documents/nextcloud-data` erreichbar sein.
|
||||
|
||||
Beim PostgreSQL-Restore beachten:
|
||||
|
||||
- vor einem produktiven Dump `occ maintenance:mode --on` setzen
|
||||
- die produktive DB-Rolle kann von `POSTGRES_USER` abweichen; aktuell nutzt Nextcloud laut `config.php` die Rolle `oc_admin`
|
||||
- nach Restore und erfolgreichem `occ status` den Wartungsmodus mit `occ maintenance:mode --off` beenden
|
||||
|
||||
### Borg-Dumps
|
||||
|
||||
Die Dump-Erzeugung ist host-seitig gedacht, nicht als Borg-UI-Inline-Hook.
|
||||
@@ -468,50 +406,6 @@ Relevant:
|
||||
- Skript: `ops/borg-ui/scripts/pre-backup-dumps.sh`
|
||||
- Unraid-Flash-Artefakt: `unraid-flash-config.tar.gz` plus `.sha256` und Manifest im selben Zielpfad
|
||||
|
||||
### Redis 8 Restore / Rollback
|
||||
|
||||
Redis-Instanzen laufen auf der 8.x-Schiene. Vor Major-Upgrades wird `redis-cli SAVE` ausgefuehrt und der jeweilige Datenpfad kopiert.
|
||||
|
||||
Aktive Pfade und Besonderheiten:
|
||||
|
||||
- Shared Redis: `/mnt/user/appdata/redis`, Passwort aus `redis_password.txt`, AOF aktiv.
|
||||
- Nextcloud Redis: `/mnt/user/appdata/nextcloud/redis`, ohne Redis-Passwort, Snapshot-Persistenz.
|
||||
- Immich Redis: cache/queue-only ohne bind-mounted Datenpfad; Restore-Wahrheit ist Immich Postgres + Foto-Dateien, nicht Redis.
|
||||
|
||||
Rollback:
|
||||
|
||||
1. Abhaengige App stoppen.
|
||||
2. Redis stoppen.
|
||||
3. Compose auf das vorherige Redis-7.4-Image zuruecksetzen.
|
||||
4. Bei Shared/Nextcloud den vor dem Cutover kopierten Datenpfad zurueckkopieren.
|
||||
5. Redis und App starten, `redis-cli INFO server` und App-Smoke pruefen.
|
||||
|
||||
### PostgreSQL 18 Major-Upgrade / Rollback
|
||||
|
||||
Produktive PostgreSQL-18-Cluster verwenden das Docker-Image-Layout mit Host-Mount auf `/var/lib/postgresql` und `PGDATA=/var/lib/postgresql/18/docker`.
|
||||
|
||||
Aktive Datenpfade:
|
||||
|
||||
- Shared PostgreSQL: `/mnt/user/appdata/postgresql18`
|
||||
- Mealie PostgreSQL: `/mnt/user/appdata/mealie/postgres18`
|
||||
- Nextcloud PostgreSQL: `/mnt/user/appdata/nextcloud/postgres18`
|
||||
|
||||
Rollback-Altstaende wurden nach Burn-in am 2026-06-02 reversibel archiviert:
|
||||
|
||||
- Shared PostgreSQL 17: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/postgresql17`
|
||||
- Mealie PostgreSQL 17: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/mealie-postgres17`
|
||||
- Nextcloud PostgreSQL 17: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/nextcloud-postgres17`
|
||||
|
||||
Restore-Reihenfolge fuer den Shared-Cluster:
|
||||
|
||||
1. Frischen PostgreSQL-18-Cluster starten.
|
||||
2. Globals aus `pg_dumpall --globals-only` einspielen.
|
||||
3. Den bekannten Bootstrap-Konflikt fuer `CREATE ROLE mailarchiver;` gezielt tolerieren bzw. herausfiltern, danach `ALTER ROLE mailarchiver ...` dennoch einspielen.
|
||||
4. Datenbanken anlegen und Custom-Format-Dumps mit `pg_restore` einspielen.
|
||||
5. Restore-Logs auf echte `ERROR`, `FATAL` und `PANIC` pruefen.
|
||||
|
||||
Immich ist bewusst nicht Teil dieses PostgreSQL-18-Laufs: Die produktive DB bleibt auf PostgreSQL 14 und nutzt das Immich-Postgres-Image mit VectorChord/pgvector. VectorChord-Backups brauchen zum Restore ein Image mit VectorChord; der alte pgvecto.rs-Datenpfad ist als Rollback-Altstand unter `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/immich-postgres-pgvecto-rs` archiviert.
|
||||
|
||||
### Hermes Agent
|
||||
|
||||
Hermes nutzt einen lokalen Build und hostseitige Runtime-Daten.
|
||||
@@ -529,50 +423,15 @@ Smoke-Test: `hermes-gateway` healthcheck ist gruen, `hermes.kaleschke.info` leit
|
||||
|
||||
`Micha/homelab-infra` wird als privater GitHub-Push-Mirror gespiegelt. Dieser Mirror ist der bevorzugte Repo-Bootstrap, falls Gitea selbst nach einem Ausfall noch nicht laeuft. Wenn weder GitHub-Mirror noch lokaler Clone verfuegbar sind, ist `services/gitea/data` selbst Teil des kritischen Wiederanlaufs.
|
||||
|
||||
### Windows-Workstation `baerchen`
|
||||
|
||||
`baerchen` ist die Operator-Workstation und haelt den lokalen Clone unter
|
||||
`G:\Gitea_Clone\homelab-infra`. Fuer einen schnellen Windows-Bare-Metal-Restore
|
||||
existiert ein Veeam-Agent-Image-Workflow.
|
||||
|
||||
Wichtige Pfade und Artefakte:
|
||||
|
||||
- Runbook: `ops/windows-reinstall/docs/windows-image-backup-baseline.md`
|
||||
- Backup-Ziel: `\\kallilabcore\backups\windows-images\baerchen`
|
||||
- Host-Pfad: `/mnt/user/backups/windows-images/baerchen/`
|
||||
- Recovery-Medium: USB-Stick `VEEAMRE`, beschriftet
|
||||
`baerchen Veeam Recovery - 2026-06-05`
|
||||
- Veeam Job: `baerchen-c-image`
|
||||
- Veeam Storage Encryption: erster Full-Lauf 2026-06-05 laut Job-Log
|
||||
unverschluesselt (`StorageEncryptionEnabled=False`); falls spaeter aktiviert,
|
||||
Passwort in Vaultwarden Secure Note `Veeam baerchen backup encryption password`
|
||||
sichern
|
||||
|
||||
Restore-Kurzpfad:
|
||||
|
||||
1. Von `VEEAMRE` booten.
|
||||
2. SMB-Ziel `\\kallilabcore\backups\windows-images\baerchen` oeffnen.
|
||||
3. Mit bestehendem SMB-User `micha` authentifizieren.
|
||||
4. Restore Point auswaehlen.
|
||||
5. Falls der Restore Point verschluesselt ist: Veeam-Encryption-Passwort aus
|
||||
Vaultwarden eingeben.
|
||||
6. Bare-Metal-Restore nur auf die Windows-Systemdisk ausfuehren.
|
||||
|
||||
BitLocker ist am 2026-06-05 bewusst noch nicht aktiv. Falls BitLocker spaeter
|
||||
aktiviert wird, muss der Recovery-Key vor dem naechsten Restore-Drill in
|
||||
Vaultwarden, unter `D:\30_Finanzen\BitLocker-RecoveryKey-baerchen-<DATUM>.txt`
|
||||
und physisch ausserhalb des Rechners abgelegt sein.
|
||||
|
||||
---
|
||||
|
||||
## 11. Laufende Vorbereitung
|
||||
## 11. Offene Vorbereitungs-To-dos
|
||||
|
||||
Offene Punkte werden in `docs/MASTER_TODO.md` gefuehrt. Daueraufgaben:
|
||||
|
||||
- Unraid-Flash-Artefakt regelmaessig pruefen (`ops/maintenance/check-unraid-flash-backup.sh`)
|
||||
- Offline-Kopien (Borg-Passphrase, KOMODO_*-Notiz, DR-Keys) bei Reviews nur auf Auffindbarkeit pruefen, nie Werte dokumentieren
|
||||
- Unraid-USB-/Flash-Backup regelmaessig ueber `unraid-flash-config.tar.gz` und optional Unraid Connect pruefen
|
||||
- Borg-Passphrase ist laut Operator-Bestaetigung vom 2026-05-26 extern/offline hinterlegt; bei Reviews nur Existenz/Lesbarkeit der Offline-Kopie pruefen, nie den Wert dokumentieren
|
||||
- Komodo Stack-ENV-Werte zentral ausserhalb von Komodo dokumentieren
|
||||
- regelmaessige automatisierte Restore-Smoke-Tests fuer Vaultwarden, Gitea und Paperless etablieren
|
||||
- `komodo-mongo`-Dump nach Major-Upgrades gezielt kontrollieren
|
||||
- Restore-Drills nach Kadenz aus `ops/restore-tests/schedule.md` rotieren
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# Disk1 Phase 2 - NTFS to XFS Migration
|
||||
|
||||
Stand: 2026-05-25 06:15 CEST. Ziel erreicht: `/mnt/disk1` wurde von `ntfs3` auf XFS migriert, ohne produktive Compose-Pfade zu aendern. Container nutzen weiter `/mnt/user/...`.
|
||||
|
||||
## Preflight
|
||||
|
||||
| Check | Ergebnis |
|
||||
|---|---|
|
||||
| Disk1 Mount | `/dev/md1p1` auf `/mnt/disk1`, `ntfs3`, 5.5T, 1.7T genutzt, 3.8T frei |
|
||||
| Cache Mount | `/dev/nvme0n1p1` auf `/mnt/cache`, `xfs`, 1.9T, 100G genutzt |
|
||||
| H: Backup-Ziel | `H:\`, Label `Externe HDD`, NTFS, 8T, 5.96T frei, healthy |
|
||||
| Compose-Binds | Keine Treffer fuer direkte `/mnt/disk1`, `/mnt/cache`, `/mnt/disks`, `/mnt/remotes` Binds |
|
||||
| SMB-Zugriff | `\\Kallilabcore\services`, `documents`, `photos`, `media` erreichbar |
|
||||
|
||||
## Zu sichernde Shares
|
||||
|
||||
| Share | Groesse laut Preflight |
|
||||
|---|---:|
|
||||
| `services` | 451M |
|
||||
| `documents` | 196M |
|
||||
| `photos` | 23G |
|
||||
| `backups` | 2.2G |
|
||||
| `media` | 1.7T |
|
||||
| `finance` | 0 |
|
||||
| `projekte` | 92K |
|
||||
|
||||
Zusaetzliche Disk1-Top-Level-Pfade: `scripts` 3.3M, `isos` 0, `System Volume Information` 0.
|
||||
|
||||
## Backup-Strategie
|
||||
|
||||
- Zielroot: `H:\kallilab-recovery\disk1-phase2-2026-05-23`.
|
||||
- Kritischer Linux-/GitOps-Pfad `services` wird zusaetzlich als Tar-Archiv ueber SSH gesichert, damit Linux-Metadaten erhalten bleiben.
|
||||
- User-Shares werden per SMB/Robocopy kopiert, mit Logs und anschliessender Zaehler-/Groessenverifikation.
|
||||
- Keine produktiven Datenpfade werden geloescht.
|
||||
|
||||
## Gates
|
||||
|
||||
1. Backup komplett und verifiziert.
|
||||
2. Dienste-Freeze vorbereitet und letzte Dumps frisch.
|
||||
3. Direkt vor Format/Array-Prozedur: Operator-Bestaetigung im konkreten Moment.
|
||||
|
||||
## Backup-Ergebnis
|
||||
|
||||
Stand: 2026-05-24 13:07 CEST.
|
||||
|
||||
| Bereich | Sicherungsart | Ergebnis |
|
||||
|---|---|---|
|
||||
| `media` | Robocopy/SMB nach `H:\kallilab-recovery\disk1-phase2-2026-05-23\shares\media` | 2722 Dateien, 1677.11 GiB, Manifestvergleich: 0 missing, 0 size mismatch, 0 extra |
|
||||
| `services` | Host-Tar auf Unraid Cache, danach binaer per `scp` nach H: | `services.tar`, 0.441 GiB, `tar -tf` gueltig |
|
||||
| `documents` | Host-Tar auf Unraid Cache, danach binaer per `scp` nach H: | `documents.tar`, 0.192 GiB, `tar -tf` gueltig |
|
||||
| `photos` | Host-Tar auf Unraid Cache, danach binaer per `scp` nach H: | `photos.tar`, 22.876 GiB, `tar -tf` gueltig |
|
||||
| `backups` | Host-Tar auf Unraid Cache, danach binaer per `scp` nach H: | `backups.tar`, 2.099 GiB, `tar -tf` gueltig |
|
||||
| `finance` | Host-Tar auf Unraid Cache, danach binaer per `scp` nach H: | `finance.tar`, leerer Share, `tar -tf` gueltig |
|
||||
| `projekte` | Host-Tar auf Unraid Cache, danach binaer per `scp` nach H: | `projekte.tar`, klein, `tar -tf` gueltig |
|
||||
| Disk1-Extras `scripts`, `isos` | Host-Tar auf Unraid Cache, danach binaer per `scp` nach H: | `disk1-extra.tar`, 0.003 GiB, `tar -tf` gueltig |
|
||||
|
||||
Hinweis: Erste Tar-Versuche per PowerShell-Redirect wurden verworfen, weil PowerShell den binaeren SSH-Stream als UTF-16 geschrieben hatte. Die ungueltige `media.tar` und unvollstaendige SMB-Teilkopien fuer `services`/`documents` wurden vom Backup-Ziel entfernt, damit nur verwertbare Sicherungen uebrig bleiben.
|
||||
|
||||
## Abschluss
|
||||
|
||||
Stand: 2026-05-25 06:15 CEST.
|
||||
|
||||
| Check | Ergebnis |
|
||||
|---|---|
|
||||
| Freeze-Dumps | `pre-backup-dumps.sh` vor Format ausgefuehrt; nach Wiederanlauf erneut erfolgreich, 15 kanonische Dump-Artefakte juenger als 24 h |
|
||||
| Disk1 Filesystem | `/dev/md1p1` auf `/mnt/disk1`, `xfs`, 5.5T, 1.8T genutzt, 3.7T frei |
|
||||
| Restore `media` | 2722 Dateien, 1,800,782,188,226 Bytes; finaler Manifestvergleich: 0 missing, 0 size mismatch, 0 extra |
|
||||
| Restore Tar-Shares | `services`, `documents`, `photos`, `backups`, `finance`, `projekte` und Disk1-Extras aus H:-Freeze-Archiven nach `/mnt/disk1` extrahiert |
|
||||
| Docker/Services | 49 Container laufend, 0 stopped, 0 unhealthy, 0 starting |
|
||||
| Smoke-Tests | `git.kaleschke.info` 200, `komodo.kaleschke.info` 200, `borg.kaleschke.info` 302, `jellyfin.kaleschke.info` 302, `monitoring.kaleschke.info` 302 |
|
||||
| Service-Mounts | Gitea SSH `:222` offen; Jellyfin und Plex sehen `/media`; Prometheus readiness ok |
|
||||
| Backup-Lauf | Borg-UI Repository `appdata-critical`, letzter Job `completed`, Archiv `Taegliche-Sicherung-2026-05-25T05:52:44.157`, `nfiles=100221` |
|
||||
| Temp-Cleanup | `/mnt/cache/disk1-phase2-tmp/*.tar` nach H:-Verifikation geloescht; Cache weiter XFS mit ca. 1.7T frei |
|
||||
|
||||
Hinweis zum Docker-Wiederanlauf: Nach dem manuellen Docker-Start liefen die Container, aber Healthcheck-Execs scheiterten wegen `dockerd` mit `XDG_RUNTIME_DIR=/run/user/0`. Ein gezielter Docker-Neustart mit unsetztem `XDG_RUNTIME_DIR` behob den Runtime-Fehler; danach wurden alle Healthchecks gruen. `monitoring-prometheus` war durch den geplanten Docker-Stop sauber beendet und wurde als bestehender Container wieder gestartet.
|
||||
|
||||
Offener Nachlauf: Die Array-Parity-Anzeige zeigte nach Abschluss weiter `mdNumDisabled=1`, `mdNumInvalid=1` und `mdResyncAction=check P`, waehrend beide beteiligten Devices `rdevStatus=DISK_OK` und `rdevNumErrors=0` melden. Parity-Zustand separat in Unraid pruefen und keinen Parity-/Disk-Slot ohne Operator-Entscheid aendern.
|
||||
@@ -1,225 +0,0 @@
|
||||
# DR-Workstation Setup-Runbook
|
||||
|
||||
Stand: 2026-06-03
|
||||
|
||||
Konkrete Schritte, um den Operator-Gaming-PC als DR-Workstation einzurichten. Der Endzustand ist in `docs/EXTERNAL_DEPENDENCIES.md` Abschnitt "DR-Workstation Bare-Metal-Kit" beschrieben; dieses Dokument ist der Weg dahin.
|
||||
|
||||
Vorbedingung: Repo-Clone unter `G:\Gitea_Clone\homelab-infra`, Hetzner-DR-SSH-Key und GitHub-Deploy-Key liegen offline auf USB.
|
||||
|
||||
Aufwand: einmalig ~30-60 Min interaktiv.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 1 - WSL2 + Ubuntu installieren (~15 Min)
|
||||
|
||||
PowerShell als **Administrator** oeffnen:
|
||||
|
||||
```powershell
|
||||
wsl --install -d Ubuntu
|
||||
```
|
||||
|
||||
- Bei "Virtualization nicht aktiviert"-Fehler: BIOS rein, Intel VT-x / AMD-V einschalten, neu starten, Befehl wiederholen.
|
||||
- Nach Install: Ubuntu startet automatisch und fragt nach Username + Passwort. Username egal (z. B. `dr`), Passwort merken (wird fuer `sudo` gebraucht).
|
||||
- Reboot kann noetig sein - PowerShell sagt es.
|
||||
|
||||
Verifikation in Ubuntu (oeffnet sich automatisch):
|
||||
|
||||
```bash
|
||||
lsb_release -a
|
||||
uname -r
|
||||
```
|
||||
|
||||
Erwartet: `Ubuntu 24.04 LTS`, Kernel beginnt mit `5.x` oder `6.x` und enthaelt `microsoft-standard-WSL2`.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 2 - Borg-Client installieren (~3 Min)
|
||||
|
||||
In der Ubuntu-Shell:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install -y borgbackup openssh-client
|
||||
borg --version
|
||||
```
|
||||
|
||||
Erwartet: `borg 1.2.x` oder `1.4.x`. Beides reicht fuer das produktive Borg-Repo auf Hetzner.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 3 - Hetzner-DR-SSH-Key in WSL ablegen (~5 Min)
|
||||
|
||||
Wichtig: der Private-Key liegt offline auf USB. Fuer die Workstation-Routine wird er auf das WSL-Filesystem kopiert - **das ist die Arbeitskopie**, nicht die Offline-Sicherung. Wenn die WSL kaputtgeht, kommt der Key zurueck vom USB; das Offline-Original bleibt unangetastet.
|
||||
|
||||
USB einstecken. In WSL kopieren (Pfad anpassen je nach Laufwerksbuchstabe):
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.ssh
|
||||
cp /mnt/<USB-Buchstabe>/dr-hetzner-2026-06-03/dr-hetzner ~/.ssh/dr-hetzner
|
||||
chmod 600 ~/.ssh/dr-hetzner
|
||||
```
|
||||
|
||||
`<USB-Buchstabe>` ist meistens `e`, `f` oder `g` - Windows-Laufwerke werden in WSL unter `/mnt/<buchstabe>` gemountet.
|
||||
|
||||
Smoke-Test:
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/dr-hetzner -o IdentitiesOnly=yes -p 23 \
|
||||
u565255@u565255.your-storagebox.de "ls"
|
||||
```
|
||||
|
||||
Erwartet: vier Verzeichnisse (`backup`, `backup2`, `hetzner_borg_appdata`, `hetzner_borg_appdata_critical`), exit 0, kein Passwort-Prompt.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 4 - Borg-Passphrase eingeben und `borg list` testen (~5 Min)
|
||||
|
||||
Borg verlangt die Passphrase beim ersten Repo-Zugriff. Die liegt offline gesichert (Operator-Bestaetigung 2026-05-26).
|
||||
|
||||
Einmaliger Smoke gegen das wichtige Repo:
|
||||
|
||||
```bash
|
||||
export BORG_RSH="ssh -i ~/.ssh/dr-hetzner -o IdentitiesOnly=yes -p 23"
|
||||
borg list ssh://u565255@u565255.your-storagebox.de/./hetzner_borg_appdata_critical
|
||||
```
|
||||
|
||||
Borg fragt nach der Passphrase. Eingeben (sie wird nicht angezeigt, das ist normal).
|
||||
|
||||
Erwartet: Liste mit Archiv-Namen, jeder im Stil `Taegliche-Sicherung-YYYY-MM-DDTHH:MM:SS.xxx`. Wenn ja: Borg-Schicht funktioniert.
|
||||
|
||||
**Wert wird nirgendwo gespeichert.** `BORG_PASSPHRASE`-Env-Variable wird **nicht** dauerhaft gesetzt; Passphrase wird im Notfall immer interaktiv eingegeben.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 5 - GitHub-Deploy-Key in WSL ablegen (~3 Min)
|
||||
|
||||
Gleiches Muster wie Hetzner-Key:
|
||||
|
||||
```bash
|
||||
cp /mnt/<USB-Buchstabe>/dr-readonly-2026-06-03/dr-readonly ~/.ssh/dr-readonly
|
||||
chmod 600 ~/.ssh/dr-readonly
|
||||
```
|
||||
|
||||
Smoke-Test gegen den privaten GitHub-Mirror:
|
||||
|
||||
```bash
|
||||
GIT_SSH_COMMAND="ssh -i ~/.ssh/dr-readonly -o IdentitiesOnly=yes" \
|
||||
git ls-remote git@github.com:michaelkaleschke-spec/homelab-infra.git | head -3
|
||||
```
|
||||
|
||||
Erwartet: HEAD und mindestens ein `refs/heads/master`-Eintrag.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 6 - Quartals-Smoke als Skript ablegen (~5 Min)
|
||||
|
||||
Damit der "ich pruefe das vierteljaehrlich"-Schritt zur Routine wird, ein kleines Skript ins WSL-Home:
|
||||
|
||||
Stand 2026-06-06: Das Skript liegt zusaetzlich versioniert unter
|
||||
`ops/maintenance/dr-workstation-smoke.sh` und wurde auf `baerchen` bereits nach
|
||||
`~/dr-smoke.sh` in die Ubuntu-WSL kopiert. Borg 1.2.8 ist installiert, die
|
||||
DR-Key-Arbeitskopien liegen unter `~/.ssh/dr-readonly` und
|
||||
`~/.ssh/dr-hetzner`, GitHub-Read-Smoke und Hetzner-SSH-Smoke sind erfolgreich.
|
||||
Der finale Borg-Smoke via `bash ~/dr-smoke.sh` wurde am 2026-06-06 ebenfalls
|
||||
erfolgreich gefahren (`DR-Smoke OK (2026-06-06 10:05:30)`). Die Borg-Passphrase
|
||||
wurde nur interaktiv eingegeben und nicht gespeichert.
|
||||
|
||||
```bash
|
||||
cat > ~/dr-smoke.sh <<'EOF'
|
||||
#!/bin/bash
|
||||
# DR-Workstation Quartals-Smoke
|
||||
# Pruefen: GitHub-Read, Hetzner-SSH, Borg-Repo-Erreichbarkeit
|
||||
# Passphrase wird interaktiv abgefragt - Skript speichert keinen Wert.
|
||||
set -e
|
||||
echo "=== GitHub Deploy-Key ==="
|
||||
GIT_SSH_COMMAND="ssh -i ~/.ssh/dr-readonly -o IdentitiesOnly=yes" \
|
||||
git ls-remote git@github.com:michaelkaleschke-spec/homelab-infra.git \
|
||||
| head -1
|
||||
echo
|
||||
echo "=== Hetzner SSH-Login ==="
|
||||
ssh -i ~/.ssh/dr-hetzner -o IdentitiesOnly=yes -p 23 \
|
||||
u565255@u565255.your-storagebox.de "ls" | head -5
|
||||
echo
|
||||
echo "=== Borg-Repo (Passphrase wird abgefragt) ==="
|
||||
export BORG_RSH="ssh -i ~/.ssh/dr-hetzner -o IdentitiesOnly=yes -p 23"
|
||||
borg info ssh://u565255@u565255.your-storagebox.de/./hetzner_borg_appdata_critical | head -10
|
||||
echo
|
||||
echo "DR-Smoke OK ($(date '+%F %T'))"
|
||||
EOF
|
||||
chmod +x ~/dr-smoke.sh
|
||||
```
|
||||
|
||||
Aufrufen mit:
|
||||
|
||||
```bash
|
||||
bash ~/dr-smoke.sh
|
||||
```
|
||||
|
||||
Termin im Kalender: einmal pro Quartal, ~5 Min Aufwand.
|
||||
|
||||
---
|
||||
|
||||
## Schritt 7 - Eintrag in EXTERNAL_DEPENDENCIES Review nachziehen
|
||||
|
||||
Nach erfolgreicher Einrichtung im Repo dokumentieren. In `docs/EXTERNAL_DEPENDENCIES.md` unter "Review":
|
||||
|
||||
```
|
||||
| 2026-06-XX | DR-Workstation produktiv: WSL2 Ubuntu auf Gaming-PC, borgbackup installiert, Hetzner-DR-Key und GitHub-Deploy-Key in ~/.ssh, Quartals-Smoke-Skript ~/dr-smoke.sh. Bare-Metal-DR-Pillars sind damit alle vier produktionsreif. | Quartalsweise Smoke laufen lassen |
|
||||
```
|
||||
|
||||
Falls der Punkt noch als offen in `docs/MASTER_TODO.md` steht, dort in den Kurzlog uebernehmen.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### `wsl --install` schlaegt fehl mit "WSL 2 requires an update"
|
||||
|
||||
```powershell
|
||||
wsl --update
|
||||
wsl --shutdown
|
||||
wsl --install -d Ubuntu
|
||||
```
|
||||
|
||||
### Hetzner-SSH fragt nach Passwort statt Key-Login zu akzeptieren
|
||||
|
||||
Permissions des Keys pruefen:
|
||||
|
||||
```bash
|
||||
ls -la ~/.ssh/dr-hetzner
|
||||
```
|
||||
|
||||
Muss `-rw-------` (also `600`) sein. Wenn anders:
|
||||
|
||||
```bash
|
||||
chmod 600 ~/.ssh/dr-hetzner
|
||||
```
|
||||
|
||||
Bei weiterhin Passwort-Prompt: Pubkey-Inhalt gegen das authorized_keys-Format der Storage Box pruefen (sollte `ssh-ed25519 AAAA...` ohne Leerzeilen sein).
|
||||
|
||||
### `borg list` haengt oder schlaegt mit "Connection refused" fehl
|
||||
|
||||
Port 23 explizit pruefen:
|
||||
|
||||
```bash
|
||||
nc -vz u565255.your-storagebox.de 23
|
||||
```
|
||||
|
||||
Wenn das fehlschlaegt: Hetzner-Status-Page pruefen, sonst SSH-Verbindung an sich blockiert (Firewall, ISP).
|
||||
|
||||
### GitHub-Pull fragt nach Username/Passwort
|
||||
|
||||
Stelle sicher dass die URL `git@github.com:...` ist (SSH), nicht `https://github.com/...`. Bei HTTPS wuerde GitHub Username/PAT verlangen, was wir bewusst nicht eingerichtet haben.
|
||||
|
||||
---
|
||||
|
||||
## Was nach diesem Runbook gilt
|
||||
|
||||
Mit allen Schritten erledigt ist der vierte Bare-Metal-DR-Pillar zu (siehe `docs/EXTERNAL_DEPENDENCIES.md`). Der DR-Workstation-Status ist dann:
|
||||
|
||||
- WSL2 Ubuntu installiert
|
||||
- borgbackup einsatzbereit
|
||||
- SSH-Keys (Hetzner, GitHub) in `~/.ssh/`
|
||||
- Quartals-Smoke-Skript laeuft
|
||||
|
||||
Damit ist im Bare-Metal-Fall der Pfad "Unraid tot -> Gaming-PC nimmt die DR-Arbeit auf" tatsaechlich gangbar, nicht nur in Doku theoretisch.
|
||||
@@ -1,6 +1,6 @@
|
||||
# External Dependencies - KalliLab CORE
|
||||
|
||||
Status: Betreiber-Baseline 2026-06-01; Account-Recovery, Schluessel und Besitznachweise bleiben ausserhalb des Repos.
|
||||
Status: Initiale Betreiber-Baseline 2026-05-26; konkrete Account-Recovery-Codes und Besitznachweise muessen ausserhalb des Repos bestaetigt werden.
|
||||
|
||||
## Zweck
|
||||
|
||||
@@ -11,19 +11,17 @@ Dieses Dokument beschreibt externe Anbieter und Konten, von denen Betrieb, Recov
|
||||
| Anbieter / System | Zweck | Kritikalitaet | Recovery-Auswirkung | Zugang / Besitz | Notfallplan |
|
||||
|---|---|---:|---|---|---|
|
||||
| Telekom DSL | Internet-Uplink | hoch | Public Apps, ACME, DDNS, Hetzner-Off-site und Tailscale-Initial-Verbindung fallen aus | Telekom-Kundenkonto | Kein WAN-Failover am Standort eingerichtet (FRITZ!Box-Ausfallschutz inaktiv); lokale LAN-Dienste laufen weiter; Hotspot-Behelf nur fuer Operator-Arbeit, nicht fuer Public Apps |
|
||||
| FRITZ!Box 7590 | Router, DHCP, Telefonie, WAN | hoch | LAN ohne DHCP/Routing; auch lokale Inter-Subnet-Kommunikation kann brechen | Operator-Login auf `192.168.178.1` | FRITZ!Box-Konfig-Backup vom 2026-06-01 liegt extern/off-system in Vaultwarden; Reset-Pin und Account-Pfad bereithalten; Remote-HTTPS/FTP/FTPS aus dem Internet sind aus |
|
||||
| FRITZ!Box 7590 | Router, DHCP, Telefonie, WAN | hoch | LAN ohne DHCP/Routing; auch lokale Inter-Subnet-Kommunikation kann brechen | Operator-Login auf `192.168.178.1` | FRITZ!Box-Konfig regelmaessig sichern (FRITZ!OS-Backup), Reset-Pin und Account-Pfad bereithalten |
|
||||
| Domain-Registrar | Besitz `kaleschke.info` | hoch | Ohne Domain brechen Public URLs/TLS-Erneuerung | Operator-Konto ausserhalb Repo, konkreten Registrar im Account pruefen | Registrar-Zugang, 2FA-Recovery und Zahlungsweg analog/off-system sichern |
|
||||
| Cloudflare DNS | Authoritative DNS, ACME DNS-Challenge, DDNS | hoch | Neue Zertifikate/DNS-Aenderungen blockiert | Cloudflare-Konto; API-Token liegt als Host-Secret | API-Token rotierbar halten, Account-Recovery und Zone-Besitz pruefen |
|
||||
| Hetzner Storage Box | Off-site Borg Backup | kritisch | Restore aus Off-site ggf. nicht moeglich | Hetzner-Konto / Storage-Box-Zugang ausserhalb Repo | Borg-Passphrase ist offline gesichert; Hetzner 2FA/Recovery/Zahlung sind bestaetigt; Storage Box ist SSH-only, Maintenance-Key liegt in Vaultwarden; Borg `append-only` wird per Operator-Entscheidung nicht umgesetzt |
|
||||
| GitHub Mirror | Externer Repo-Mirror `michaelkaleschke-spec/homelab-infra` (privat) | mittel/hoch | Gitea-Verlust abfederbar, aber Bare-Metal-Bootstrap braucht Read-Zugang (PAT oder SSH-Deploy-Key); ohne diesen ist der Mirror im DR nicht klonbar | GitHub-Konto; Push-PAT liegt in Gitea-Mirror-Settings; **Read-PAT/Deploy-Key fuer DR muss zusaetzlich offline im DR-Kit liegen** | Mirror-Status regelmaessig pruefen; lokalen Clone als zweite Kopie behalten; Read-PAT mit Scope `repo:read` separat erzeugen und im DR-Kit ablegen |
|
||||
| Hetzner Storage Box | Off-site Borg Backup | kritisch | Restore aus Off-site ggf. nicht moeglich | Hetzner-Konto / Storage-Box-Zugang ausserhalb Repo | Zweites Off-site-Ziel oder Cold-Platte etablieren; Borg-Passphrase extern sichern |
|
||||
| GitHub Mirror | Externer Repo-Mirror `michaelkaleschke-spec/homelab-infra` | mittel/hoch | Gitea-Verlust abfederbar, Repo-Bootstrap bleibt moeglich | GitHub-Konto; PAT liegt in Gitea-Mirror-Settings, nicht im Repo | Mirror-Status regelmaessig pruefen; lokalen Clone als zweite Kopie behalten |
|
||||
| Tailscale | Remote-/Operator-Zugang | hoch | Remote-Zugriff erschwert, lokale Bedienung bleibt | Tailnet-Konto; Node `Kallilabcore`, IPv4 `100.80.98.33` | Break-glass per LAN und physischem Zugriff; Tailnet-Recovery-Codes sichern |
|
||||
| GMX SMTP | Authelia Notifier, Vaultwarden-Einladungen, Ops-Report-Mail | mittel | Mail-Notifier und Vaultwarden-Einladungen fallen aus; Login selbst nicht zwingend | GMX-Konto; SMTP-Secrets liegen hostseitig | ntfy/zweiter SMTP als Fallback pruefen |
|
||||
| OpenAI API | Paperless-GPT LLM und Vision-OCR | mittel | Automatische Dokument-Titel, Tags, Korrespondenten und LLM-OCR fallen aus; Paperless selbst laeuft weiter | OpenAI-Projekt/API-Key ausserhalb Repo | Key in Vaultwarden/Komodo sichern, bei Offenlegung rotieren; Kosten/Usage im OpenAI-Projekt beobachten |
|
||||
| GMX SMTP | Authelia Notifier | mittel | Mail-Notifier faellt aus, Login selbst nicht zwingend | GMX-Konto; SMTP-Secret liegt hostseitig | ntfy/zweiter SMTP als Fallback pruefen |
|
||||
| Let's Encrypt | TLS-Zertifikate | hoch | Cert-Erneuerung faellt aus | automatisch via Traefik und Cloudflare DNS-Challenge | Cert-Expiry Alert einrichten; Cloudflare-Token und Traefik-Storage pruefen |
|
||||
| Container Registries | Image Pulls von Docker Hub, GHCR, LSCR, Gitea Registry u. a. | mittel | Redeploy/Update blockiert | ueberwiegend oeffentlich; keine produktiven Registry-Tokens im Repo | Gepinnte Digests und lokale Runtime helfen kurzfristig; Updates geplant und einzeln deployen |
|
||||
| Plex Konto | Plex native Auth, Claim und Client-Zugriff ueber `plex.kaleschke.info` | mittel | Plex-Web/App-Login und Clients koennen ausfallen; LAN-Medienpfade bleiben lokal | Plex-Konto ausserhalb Repo; `PLEX_CLAIM` nur fuer Setup | Plex Remote Access bleibt aus; externer Zugriff laeuft ueber Traefik/443. Konto-Recovery separat sichern |
|
||||
| Plex Konto/Remote Access | Plex native Auth, ggf. Remote Access und Claim | mittel | Plex-Clients/Remote-Funktionen koennen ausfallen | Plex-Konto ausserhalb Repo; `PLEX_CLAIM` nur fuer Setup | LAN-Medienpfade bleiben lokal; Konto-Recovery separat sichern |
|
||||
| Mobile Push | ntfy und ggf. mobile Plattform-Pushes | niedrig/mittel | Alerts erreichen Mobilgeraete ggf. nicht | App-/Device-seitig | Kritische Alerts zusaetzlich in Grafana/Glance sichtbar halten |
|
||||
| Operator-DR-Workstation | Bare-Metal-Recovery-Arbeitsplatz (Gaming-PC Windows, lokaler Repo-Clone `G:\Gitea_Clone\homelab-infra`) | kritisch | Ohne Workstation kein Borg-Extract, kein Hetzner-Zugriff, kein Repo-Bootstrap; der Unraid-Host ist im Bare-Metal-Fall gerade weg | Operator-PC, WSL2 + Borg-Client, SSH-Key fuer Hetzner Storage Box, Offline-Kopie der Borg-Passphrase | Setup als bewusste DR-Vorbedingung pflegen (siehe Abschnitt "DR-Workstation Bare-Metal-Kit") |
|
||||
|
||||
## Kritische Secrets ausserhalb des Repos
|
||||
|
||||
@@ -35,28 +33,9 @@ Authoritativ ist `docs/SECRETS_MAP.md`. Diese Liste markiert nur externe Abhaeng
|
||||
| Cloudflare DNS API Token | ACME DNS-Challenge | Token-Rotation und Scope pruefen |
|
||||
| GitHub Mirror Token | Push-Mirror | In Gitea/GitHub verwaltet, nicht im Repo |
|
||||
| Tailscale Account Recovery | Tailnet-Zugang | Account-2FA/Recovery Codes sichern |
|
||||
| SMTP Passwort | Authelia Mail, Vaultwarden-Einladungen, Ops-Report-Mail | In Host-Secrets, Fallback pruefen |
|
||||
| SMTP Passwort | Authelia Mail | In Host-Secret, Fallback pruefen |
|
||||
| Domain-Registrar Recovery | Domain-Besitz und Zahlung | Account, 2FA und Zahlungsweg ausserhalb des Homelabs sichern |
|
||||
| Hetzner Storage Box Zugang | Off-site Backup-Ziel | Account 2FA aktiv, Recovery Key offline gedruckt, Zahlungsweg ok; Maintenance-Key und Storage-Box-Passwort in Vaultwarden |
|
||||
| OpenAI API Key | Paperless-GPT GPT-Zugriff | Als Stack ENV / Vaultwarden-Eintrag sichern; bei Verdacht auf Leak rotieren |
|
||||
| KOMODO_* Stack-ENV-Notiz | Offline-Sicherung der 5 Komodo-Werte (`KOMODO_SECRET_KEY`, `KOMODO_WEBHOOK_SECRET`, `KOMODO_JWT_SECRET`, `KOMODO_MONGO_PASSWORD`, `KOMODO_PERIPHERY_PASSKEY`) | **Status 2026-06-03: offline gesichert (Operator-Bestaetigung)**. Quelle der Werte ist die host-seitige Self-Stack-`.env` (`/mnt/user/services/stacks/komodo/.env`) bzw. die Drift-Recovery-Kopie unter `/mnt/user/appdata/secrets/_komodo_stack_env_recovery_2026-05-04.env`. Nicht im Repo, nicht in ntfy, nicht in Logs |
|
||||
| GitHub-Mirror Read-Only Deploy-Key | DR-Read-Zugang zum privaten Mirror `michaelkaleschke-spec/homelab-infra` | **Status 2026-06-03: offline gesichert (Operator-Bestaetigung).** SSH-Deploy-Key `dr-readonly-2026-06-03` (ed25519, Passphrase-frei), Title in GitHub Repo Settings -> Deploy Keys: `DR Read-Only 2026-06-03`, Write-Access bewusst deaktiviert. Private Key liegt offline neben der KOMODO_*-Notiz. Smoke `git ls-remote` am 2026-06-03 erfolgreich. |
|
||||
|
||||
## DR-Workstation Bare-Metal-Kit
|
||||
|
||||
Der Operator-Gaming-PC ist im Bare-Metal-Fall die einzige Stelle, von der aus Recovery starten kann. Folgende Bestandteile gehoeren zum minimalen DR-Kit auf diesem Rechner:
|
||||
|
||||
| Bestandteil | Zweck | Pruefen |
|
||||
|---|---|---|
|
||||
| Repo-Clone `G:\Gitea_Clone\homelab-infra` (master, gefetcht) | Recovery-Anker fuer `ops/komodo/docker-compose.yml`, Restore-Skripte | `git -C G:\Gitea_Clone\homelab-infra log --oneline -1` plausibel aktuell |
|
||||
| Read-Zugang zum privaten GitHub-Mirror | Fallback, falls lokaler Clone defekt | SSH-Deploy-Key `dr-readonly-2026-06-03` (ed25519, Passphrase-frei) offline im DR-Kit, ein Test-Clone pro Quartal mit `GIT_SSH_COMMAND="ssh -i <pfad-zum-key> -o IdentitiesOnly=yes" git ls-remote git@github.com:michaelkaleschke-spec/homelab-infra.git` |
|
||||
| WSL2 mit Borg-Client (`apt install borgbackup`) | Borg-Extract von Hetzner Storage Box ohne laufenden Unraid-Host | `borg --version` antwortet; ein `borg list` gegen Hetzner-Repo laeuft |
|
||||
| SSH-Key fuer Hetzner Storage Box | Login auf `u565255.your-storagebox.de:23` | **Status 2026-06-03: ed25519-DR-Key `dr-hetzner-2026-06-03` offline gesichert.** Pubkey via `install-ssh-key` auf der Storage Box autorisiert, passwortloser Login erfolgreich, `ls` zeigt vier Borg-Repos (`backup`, `backup2`, `hetzner_borg_appdata`, `hetzner_borg_appdata_critical`). Private Key liegt offline neben KOMODO_*-Notiz und GitHub-Deploy-Key |
|
||||
| Offline-Kopie Borg-Passphrase | Entschluesselung des Borg-Repos | Operator-Bestaetigung 2026-05-26; bei Reviews nur Auffindbarkeit pruefen |
|
||||
| Offline-Kopie KOMODO_* Stack-ENV | Komodo-Bootstrap ohne Vaultwarden | **Status 2026-06-03: offline gesichert (Operator-Bestaetigung)** |
|
||||
| Vaultwarden Master-Passwort offline | Zugriff auf Vaultwarden-Export im DR | Operator-Wissen, ggf. analog gesichert |
|
||||
|
||||
Operative Regel: Die DR-Workstation wird nicht als Test-/Spiel-PC betrachtet. WSL und das DR-Kit duerfen nicht unbemerkt unbrauchbar werden. Quartalsweise minimaler Trockenlauf: `borg list <hetzner-repo>` muss antworten und der Repo-Clone muss fetchbar bleiben.
|
||||
| Hetzner Storage Box Zugang | Off-site Backup-Ziel | SSH-/Web-Zugang und Zahlungsweg extern sichern |
|
||||
|
||||
## Ausfall-Szenarien
|
||||
|
||||
@@ -64,8 +43,7 @@ Operative Regel: Die DR-Workstation wird nicht als Test-/Spiel-PC betrachtet. WS
|
||||
|
||||
- Lokales Borg-Repo und aktuelle Dumps pruefen.
|
||||
- Keine destruktiven Host-Aenderungen starten, solange Off-site unklar ist.
|
||||
- H:/ Nearline-Pull als schnelle lokale Zweitkopie fuer kritische Restore-Artefakte nutzen.
|
||||
- Zweites Off-site-Ziel nur neu bewerten bei Hetzner-Problemen, stark wachsendem Datenwert oder geaenderter Betreiber-Praeferenz.
|
||||
- Zweites Off-site-Ziel oder Cold-Platte als Folgeaufgabe umsetzen.
|
||||
|
||||
### Cloudflare Account/DNS gestoert
|
||||
|
||||
@@ -85,7 +63,7 @@ Operative Regel: Die DR-Workstation wird nicht als Test-/Spiel-PC betrachtet. WS
|
||||
- Lokale LAN-Apps (Plex, AdGuard-DNS, lokales Borg-Dump-Repository) bleiben verfuegbar, solange Host und Switch laufen.
|
||||
- Tailscale-Sessions, die bereits stehen, koennen ueber DERP/Relays kurzzeitig weiterlaufen; neue Verbindungen koennen ausfallen.
|
||||
- ACME-/DDNS-/Hetzner-Backup-Laeufe pausieren bis WAN zurueck ist.
|
||||
- FRITZ!OS ist am 2026-06-01 auf 8.25 (`154.08.25`) beobachtet; weitere Updates nur in einem geplanten Service-Fenster einspielen, weil Reboot WAN/Tailscale-Aufbau unterbricht.
|
||||
- FRITZ!OS 8.21 Update wird bewusst nur in einem geplanten Service-Fenster eingespielt, weil Reboot WAN/Tailscale-Aufbau unterbricht.
|
||||
|
||||
### Domain verloren oder Registrar-Zugriff verloren
|
||||
|
||||
@@ -96,6 +74,6 @@ Operative Regel: Die DR-Workstation wird nicht als Test-/Spiel-PC betrachtet. WS
|
||||
|
||||
| Datum | Ergebnis | Naechste Aktion |
|
||||
|---|---|---|
|
||||
| 2026-05-26 bis 2026-06-03 | Baseline und Haertung abgeschlossen: externe Abhaengigkeiten dokumentiert; FRITZ!Box-WAN auf 443/tcp bereinigt, Remote-Dienste aus, Konfig-Backup in Vaultwarden; Hetzner-Account-Hygiene (2FA, Recovery Key offline); KOMODO_*-Notiz und GitHub-Read-Deploy-Key offline gesichert. Detailhistorie in Git. | Keine Folgeaktion |
|
||||
| 2026-06-03 | Hetzner Storage Box DR-SSH-Key `dr-hetzner-2026-06-03` (ed25519, Passphrase-frei) erzeugt, via `install-ssh-key` auf Storage Box `u565255.your-storagebox.de:23` autorisiert, passwortloser Login erfolgreich (Borg-Repos sichtbar), Private-Key offline neben KOMODO_*-Notiz und GitHub-Deploy-Key abgelegt, Arbeitsplatz-Kopie geloescht. Bare-Metal-Borg-Restore von der DR-Workstation ist damit moeglich, sobald WSL2 + Borg-Client installiert sind. | Restliche P1-Operator-Aufgaben: WSL2 + Borg-Client auf DR-Workstation installieren, Nextcloud-Restore-Test |
|
||||
| 2026-06-06 | DR-Workstation produktiv: WSL2 Ubuntu 24.04 vorhanden, SSH/Git und Borg 1.2.8 in WSL vorhanden, DR-Key-Arbeitskopien unter `~/.ssh/dr-readonly` und `~/.ssh/dr-hetzner`, GitHub-Read-Smoke und Hetzner-SSH-Smoke erfolgreich, `ops/maintenance/dr-workstation-smoke.sh` nach `~/dr-smoke.sh` kopiert. Finaler Operator-Smoke erfolgreich: GitHub HEAD `3a263a4...`, Hetzner Storage Box Repos sichtbar, Borg-Repo `hetzner_borg_appdata_critical` gelesen, Repository ID `5dd9b949...`, encrypted `Yes (repokey)`, `DR-Smoke OK (2026-06-06 10:05:30)`. | Quartalsweise `bash ~/dr-smoke.sh`; Borg-Passphrase weiterhin nur interaktiv eingeben und nicht speichern |
|
||||
| 2026-05-26 | Bekannte externe Abhaengigkeiten aus Repo-/Betriebsdoku dokumentiert; keine Secret-Werte aufgenommen. Borg-Passphrase ist laut Operator offline gesichert. | Account-Besitz, 2FA-Recovery-Codes und Zahlungswege extern bestaetigen |
|
||||
| 2026-05-26 | Telekom-DSL und FRITZ!Box 7590 (FRITZ!OS 8.21) als WAN-/Router-Abhaengigkeit aufgenommen; Ausfallschutz nicht eingerichtet; 2 Portfreigaben aktiv (Soll: 443/tcp + 222/tcp) | FRITZ!OS-Update im Service-Fenster pruefen; Portfreigaben-UI gegen Repo-Soll abgleichen |
|
||||
| 2026-05-27 | FRITZ!Box-Portfreigaben-UI abgeglichen: aktiv sind `80/tcp` und `443/tcp` auf Kallilabcore; `222/tcp` fehlt gegen Repo-Soll. Keine Router-Aenderung vorgenommen. | Nach Operator-Freigabe `80/tcp` entfernen und `222/tcp` nur anlegen, wenn externes Gitea-SSH weiter gewuenscht ist |
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
# External Operator Runbook
|
||||
|
||||
Stand: 2026-06-01
|
||||
|
||||
Dieses Runbook schliesst die Betreiber-Aufgaben, die nicht vollstaendig aus dem
|
||||
Repo automatisierbar sind: Hetzner-Account-Hygiene, Borg-Append-Only und
|
||||
FRITZ!Box-Servicefenster. Keine Secret-Werte ins Repo schreiben.
|
||||
|
||||
## 1. Vorher pruefen
|
||||
|
||||
Auf dem Unraid-Host:
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab-infra/ops/maintenance/check-external-operator.sh
|
||||
```
|
||||
|
||||
Erwarteter Stand vom 2026-06-01:
|
||||
|
||||
- FRITZ!Box 7590 meldet FRITZ!OS `154.08.25`.
|
||||
- FRITZ!Box IPv6-Firewall meldet `FirewallEnabled=1`; `InboundPinholeAllowed=1` bedeutet, dass IPv6-Freigaben technisch moeglich sind und in der UI gegengeprueft werden muessen.
|
||||
- Public DNS fuer `*.kaleschke.info` liefert A-Records auf `217.249.115.154`, keine AAAA-Records.
|
||||
- Host hat keine globale Provider-IPv6-Adresse; sichtbar ist nur Tailscale-IPv6 `fd7a:115c:a1e0::2c01:62b2`.
|
||||
- WAN-Smoke gegen die Public-IP: `443/tcp` offen, `80/tcp` und `222/tcp` geschlossen.
|
||||
- FRITZ!Box-UI-Gegencheck vom 2026-06-01: Remote-HTTPS auf die FRITZ!Box ist aus, FTP/FTPS auf Speichermedien ist aus, nur `443/tcp -> 192.168.178.58` ist als WAN-Freigabe sichtbar, keine aktive IPv6-Freigabe sichtbar, UPnP-Selbstfreigaben aus.
|
||||
- FRITZ!Box-Konfig-Backup vom 2026-06-01 ist extern/off-system in Vaultwarden abgelegt; Datei und Kennwort nicht ins Repo schreiben.
|
||||
- Borg UI nutzt `borg 1.4.x`; Repository `appdata-critical` liegt auf Hetzner Storage Box `ssh://...your-storagebox.de:23/./hetzner_borg_appdata_critical`.
|
||||
- Hetzner-Account-Hygiene vom 2026-06-01: 2FA aktiv, Recovery Key offline gedruckt, Zahlung ok.
|
||||
- Storage Box vom 2026-06-01: SSH aktiv, SMB/WebDAV aus, separater Maintenance-Key in Vaultwarden, produktiver Borg-UI-Key und Maintenance-Key nach Passwort-Recovery getestet.
|
||||
- Restore-Freshness: `Critical 0`, `Warnings 0`.
|
||||
|
||||
## 2. Hetzner Account-Hygiene
|
||||
|
||||
Im Hetzner-/Storage-Box-Konto pruefen und extern/off-system dokumentieren:
|
||||
|
||||
| Punkt | Soll |
|
||||
|---|---|
|
||||
| Passwort | stark, eindeutig, im Passwortmanager |
|
||||
| 2FA | aktiv, Recovery Key offline auffindbar |
|
||||
| Kontakt-E-Mail | aktuell und ohne Homelab-Abhaengigkeit erreichbar |
|
||||
| Zahlungsweg | gueltig, Fallback bekannt |
|
||||
| Storage Box | Produkt, Benutzer und Rechnungsstatus sichtbar |
|
||||
| SSH/SFTP/WebDAV/SMB | nur benoetigte Protokolle aktiv |
|
||||
| Recovery | Kundennummer, Login-Pfad und Support-Pfad extern notiert |
|
||||
|
||||
Im Repo nur das Datum der Bestaetigung dokumentieren, nie Zugangsdaten.
|
||||
|
||||
## 3. Borg Append-Only
|
||||
|
||||
Status: **bewusst nicht umgesetzt**.
|
||||
|
||||
Ziel der Haertung waere gewesen: Der produktive Backup-Client darf neue Archive
|
||||
schreiben, aber nicht normal prune/delete/compact als unbeschraenkter Client
|
||||
ausfuehren.
|
||||
|
||||
Hetzner dokumentiert Borg-Zugriff auf Storage Boxen inklusive `--remote-path`
|
||||
fuer Borg-Versionen; fuer Borg 1.4 wird `--remote-path=borg-1.4` empfohlen.
|
||||
Hetzner bestaetigt auch, dass append-only moeglich ist. Borg selbst setzt
|
||||
append-only pro SSH-Key typischerweise ueber einen forced command in
|
||||
`authorized_keys` um.
|
||||
|
||||
Getestetes Zielmodell, aber **nicht auf der produktiven Storage Box aktiv**:
|
||||
|
||||
```text
|
||||
command="borg-1.4 serve --append-only --restrict-to-repository /home/hetzner_borg_appdata_critical",restrict ssh-ed25519 <backup-public-key> borg-ui-append-only
|
||||
ssh-ed25519 <maintenance-public-key> borg-maintenance
|
||||
```
|
||||
|
||||
Hinweise:
|
||||
|
||||
- Stand 2026-06-01: Ein forced-command-Versuch auf der produktiven
|
||||
Storage-Box-`authorized_keys` brach die Key-Authentifizierung. Recovery
|
||||
erfolgte per Storage-Box-Passwort und Upload einer bereinigten
|
||||
`authorized_keys` mit Borg-UI-Key und Maintenance-Key.
|
||||
- Operator-Entscheidung 2026-06-01: Append-only wird fuer dieses Homelab nicht
|
||||
umgesetzt. Der zusaetzliche Schutz steht hier nicht im Verhaeltnis zum
|
||||
Betriebsrisiko und zur Komplexitaet.
|
||||
- Pfad auf der Storage Box vor dem Eintragen pruefen. Bei Hetzner werden Pfade
|
||||
im Borg-Repo haeufig relativ als `./repo-name` verwendet; in
|
||||
`authorized_keys` muss der serverseitige Pfad zur Storage-Box-Home-Struktur
|
||||
passen.
|
||||
- Der produktive Borg-UI-Key bleibt bewusst uneingeschraenkt, damit die
|
||||
produktiven Backups laufen.
|
||||
- Ein separater Maintenance-Key bleibt fuer bewusste Retention/Prune/Compact
|
||||
noetig und liegt in Vaultwarden; lokale temporare Key-Dateien wurden geloescht.
|
||||
- Append-only verhindert nicht, dass ein kompromittierter Client Archive als
|
||||
geloescht markiert; es verhindert die unmittelbare physische Entfernung.
|
||||
Nach einem Vorfall keine unbeschraenkte Schreiboperation ausfuehren, bevor
|
||||
die Borg-Transaktionen bewertet wurden.
|
||||
|
||||
Nach Aenderung:
|
||||
|
||||
1. Einen regulaeren Borg-Lauf abwarten oder manuell starten.
|
||||
2. `check-external-operator.sh` ausfuehren.
|
||||
3. Nur das Ergebnis dokumentieren: Datum/Befund im Review-Log von `docs/EXTERNAL_DEPENDENCIES.md`.
|
||||
|
||||
## 4. FRITZ!Box-Servicefenster
|
||||
|
||||
Vor dem Fenster:
|
||||
|
||||
1. Familie informieren: Internet/Telefonie koennen kurz weg sein.
|
||||
2. Aktuellen Repo-Stand und Borg-Freshness pruefen.
|
||||
3. FRITZ!Box-Konfig exportieren: `System -> Sicherung -> Sichern`.
|
||||
4. Sicherungsdatei nicht ins Repo legen; im Passwortmanager/off-system ablegen.
|
||||
|
||||
In der FRITZ!Box:
|
||||
|
||||
| Bereich | Soll |
|
||||
|---|---|
|
||||
| `System -> Update` | FRITZ!OS aktuell; am 2026-06-01 per TR-064 `154.08.25` beobachtet |
|
||||
| `Internet -> Freigaben -> Portfreigaben` | nur `443/tcp -> 192.168.178.58:443` |
|
||||
| `Internet -> Freigaben -> FRITZ!Box-Dienste` | Remote-HTTPS auf FRITZ!Box-UI aus; FTP/FTPS auf Speichermedien aus |
|
||||
| IPv6-Portfreigaben | keine aktiven Freigaben; insbesondere kein `222/tcp`, kein Admin-Port |
|
||||
| Selbststaendige Portfreigaben/UPnP | fuer `Kallilabcore` aus; neue Geraete nur bewusst erlauben |
|
||||
| Gastnetz | bleibt aus, solange keine Gastnetz-Policy gepflegt wird |
|
||||
| Ausfallschutz | bewusst aus; nur neu bewerten, wenn ein Mobilfunk-Fallback gewuenscht ist |
|
||||
|
||||
Nach dem Fenster:
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab-infra/ops/maintenance/check-external-operator.sh
|
||||
```
|
||||
|
||||
Dann in `docs/NETWORK_INVENTORY.md` aktualisieren:
|
||||
|
||||
- FRITZ!OS-Version
|
||||
- IPv6-Status
|
||||
- aktive Portfreigaben
|
||||
- FRITZ!Box-Dienste aus dem Internet
|
||||
- Datum der Konfig-Sicherung
|
||||
|
||||
## Quellen
|
||||
|
||||
- Hetzner Docs: Storage Box Zugriff mit SSH/rsync/BorgBackup, inklusive
|
||||
Borg-Versionen, `--remote-path` und Append-Only-Hinweis:
|
||||
<https://docs.hetzner.com/storage/storage-box/access/access-ssh-rsync-borg/>
|
||||
- BorgBackup Docs: `borg serve --append-only` und forced commands in
|
||||
`authorized_keys`:
|
||||
<https://borgbackup.readthedocs.io/en/stable/deployment/pull-backup.html>
|
||||
- AVM FRITZ!Box Hilfe: IPv6-Portfreigaben werden separat verwaltet; eingehende
|
||||
Zugriffe sind standardmaessig nicht offen:
|
||||
<https://help.avm.de/fritzbox.php?hardware=145&language=en&oem=avme&set=009&topic=hilfe_internet_freigabe_ipv6>
|
||||
- AVM FRITZ!Box Hilfe: Sicherung der FRITZ!Box-Einstellungen:
|
||||
<https://help.avm.de/fritzbox.php?hardware=145&language=en&oem=avme&set=009&topic=hilfe_system_export>
|
||||
+14
-121
@@ -1,6 +1,6 @@
|
||||
# Familien-Willkommen - KalliLab CORE
|
||||
|
||||
Status: **Praxis-Onboarding** (2026-06-01). Zielgruppe: Familie. Kein Technik-Wortschatz noetig.
|
||||
Status: **Final-Stand vor Wochenend-Einladung** (2026-05-27). Zielgruppe: Familie. Kein Technik-Wortschatz noetig.
|
||||
|
||||
Diese Seite richtet sich an alle, die zuhause unsere eigenen Apps nutzen. Du brauchst kein Technikwissen. Wenn etwas unklar ist: einfach Michi fragen.
|
||||
|
||||
@@ -25,44 +25,12 @@ Nachteile, ehrlich gesagt: Wenn der Server zuhause aus ist, sind die Apps weg, b
|
||||
| **Vaultwarden** | Passwoerter sicher speichern und auf jedem Geraet nachschauen | Bitwarden-App (kostenlos), beim ersten Start Server-URL auf `vault.kaleschke.info` aendern lassen |
|
||||
| **Mealie** | Rezepte sammeln, Wochenplan, Einkaufsliste | Web `mealie.kaleschke.info` oder Mealie-App |
|
||||
| **Paperless** | Briefe und wichtige Dokumente scannen, durchsuchen, ablegen | Web `paperless.kaleschke.info`; Scan-Workflow erklaert Michi |
|
||||
| **Plex** | Filme und Musik auf Fernseher, Handy und Tablet | Web `https://plex.kaleschke.info` oder Plex-App auf dem Geraet, mit Konto anmelden |
|
||||
| **Plex** | Filme und Musik auf Fernseher, Handy und Tablet | Plex-App auf dem Geraet, mit Konto anmelden |
|
||||
|
||||
> Wenn du eine App auf dem Handy installierst und sie fragt nach einer Server-URL, ist das immer eine `...kaleschke.info`-Adresse. Wenn du dir nicht sicher bist, frag bevor du etwas eintippst.
|
||||
|
||||
---
|
||||
|
||||
## Unser erster gemeinsamer Ablauf
|
||||
|
||||
Wir richten nicht alles auf einmal perfekt ein. Wichtig ist, dass drei Dinge
|
||||
wirklich benutzt werden:
|
||||
|
||||
1. **Vaultwarden**: Passwoerter landen dort, nicht im Browser.
|
||||
2. **Immich**: Handy-Fotos werden automatisch gesichert.
|
||||
3. **Mealie**: Rezepte und Einkaufsliste werden gemeinsam ausprobiert.
|
||||
|
||||
Wenn diese drei Dinge laufen, ist das Familien-Onboarding praktisch erfolgreich.
|
||||
|
||||
## Vaultwarden zuerst
|
||||
|
||||
Vaultwarden ist die Grundlage fuer alle anderen Logins.
|
||||
|
||||
1. App **Bitwarden Passwortmanager** auf Handy und ggf. PC installieren.
|
||||
2. Beim ersten Start die Server-URL auf `https://vault.kaleschke.info` setzen.
|
||||
3. Mit dem persoenlichen Konto anmelden.
|
||||
4. Master-Passwort gemeinsam festlegen und merken. Das Master-Passwort wird
|
||||
nicht bei Michi gespeichert.
|
||||
5. Browser-Passwortspeicher fuer neue Homelab-Passwoerter nicht verwenden.
|
||||
6. Test: Einen neuen Eintrag "Test KalliLab" anlegen und wiederfinden.
|
||||
|
||||
Was in Vaultwarden gehoert:
|
||||
|
||||
- Homelab-App-Passwoerter
|
||||
- wichtige Familien-Logins
|
||||
- Recovery-Codes, wenn eine App welche zeigt
|
||||
- keine losen Passwort-Zettel und keine Screenshots von Passwoertern
|
||||
|
||||
---
|
||||
|
||||
## Wie du dich anmeldest
|
||||
|
||||
Beim ersten Mal bekommst du von Michi:
|
||||
@@ -89,40 +57,13 @@ Das ist die App, die deinen Eltern wahrscheinlich am meisten bringt.
|
||||
1. App **Immich** im App-Store / Play Store installieren.
|
||||
2. Beim ersten Start nach Server fragen lassen: `https://immich.kaleschke.info`.
|
||||
3. Mit deinem Login anmelden.
|
||||
4. In den App-Einstellungen "Hintergrund-Backup" aktivieren - am besten nur
|
||||
ueber WLAN.
|
||||
5. Das richtige Album / die normale Kamera-Galerie auswaehlen.
|
||||
6. App einmal offen lassen, bis erste Fotos hochgeladen wurden.
|
||||
7. Test: In der Weboberflaeche `https://immich.kaleschke.info` pruefen, ob die
|
||||
ersten Fotos sichtbar sind.
|
||||
8. Fertig. Neue Fotos landen automatisch zuhause auf dem Server.
|
||||
4. In den App-Einstellungen "Hintergrund-Backup" aktivieren — am besten nur ueber WLAN.
|
||||
5. Fertig. Neue Fotos landen automatisch zuhause auf dem Server.
|
||||
|
||||
> Wenn dein Handy 4 Wochen nicht im Haus-WLAN war, sind die Fotos noch in der Handy-Galerie, aber noch nicht zuhause. Sobald du wieder im WLAN bist und die App startest, holt sie alles nach.
|
||||
|
||||
---
|
||||
|
||||
## Rezepte und Einkaufsliste einrichten (Mealie)
|
||||
|
||||
Mealie soll nicht nur "auch da" sein, sondern wirklich genutzt werden.
|
||||
|
||||
1. `https://mealie.kaleschke.info` oeffnen.
|
||||
2. Mit dem persoenlichen Konto anmelden.
|
||||
3. Gemeinsam ein erstes echtes Rezept anlegen oder importieren.
|
||||
4. Rezept mindestens einer Kategorie geben, z. B. `Alltag`, `Schnell`,
|
||||
`Wochenende`, `Vegetarisch`.
|
||||
5. Aus dem Rezept Zutaten auf die Einkaufsliste setzen.
|
||||
6. Test: Einkaufsliste auf dem Handy oeffnen und einen Eintrag abhaken.
|
||||
7. Optional: Einen Wochenplan fuer die naechsten 2-3 Tage anlegen.
|
||||
|
||||
Start-Regeln fuer Mealie:
|
||||
|
||||
- Rezepte nur dann speichern, wenn wir sie wirklich kochen wuerden.
|
||||
- Namen schlicht halten: `Chili`, `Bolognese`, `Kartoffelsuppe`.
|
||||
- Zutaten so eintragen, dass sie beim Einkaufen verstaendlich sind.
|
||||
- Wenn ein Rezept nicht schmeckt: loeschen oder klar als "nicht wieder" markieren.
|
||||
|
||||
---
|
||||
|
||||
## Was tun, wenn etwas nicht geht
|
||||
|
||||
### "Die Webseite oeffnet nicht."
|
||||
@@ -193,66 +134,18 @@ Michi laesst es dich wissen, wenn ein Wartungsfenster geplant ist.
|
||||
|
||||
---
|
||||
|
||||
## Erster Onboarding-Termin - Ablauf fuer Michi
|
||||
## Offene Inhalte (Operator-Notiz)
|
||||
|
||||
Diese Sektion ist die konkrete Checkliste fuer den **ersten echten
|
||||
Familien-Onboarding-Termin**. Sie ist als ein zusammenhaengender Termin von
|
||||
ca. 30-45 Minuten pro Person gedacht. Keine Secret-Werte in diese Datei
|
||||
schreiben.
|
||||
Diese Punkte gehoeren in das Wochenend-Onboarding-Gespraech und sind nicht Teil dieser Familien-Seite:
|
||||
|
||||
> Operator-Eingabe vor dem Termin: festlegen, **wer** beim ersten Termin dabei
|
||||
> ist und **welche Geraete** real vorliegen. Die Checkliste funktioniert pro
|
||||
> Person identisch.
|
||||
|
||||
### Vorher bereitlegen (Operator-Vorbereitung)
|
||||
|
||||
Diese Dinge muessen **vor** dem Termin fertig sein, sonst stockt der Ablauf:
|
||||
|
||||
- [ ] Pro Teilnehmer ist in **Vaultwarden** ein Benutzerkonto angelegt (Benutzername = Vorname klein).
|
||||
- [ ] Pro Teilnehmer ist in **Immich** ein Benutzerkonto angelegt.
|
||||
- [ ] Pro Teilnehmer ist in **Mealie** ein Benutzerkonto angelegt.
|
||||
- [ ] Start-Passwoerter sind erzeugt und liegen so bereit, dass sie persoenlich uebergeben werden koennen (nicht per Chat, nicht in diese Datei).
|
||||
- [ ] Die Apps `cloud`, `immich`, `vault`, `mealie` sind erreichbar (kurzer eigener Smoke-Test ueber `https://...kaleschke.info`).
|
||||
- [ ] Das Familien-Handy/Geraet jedes Teilnehmers ist da, entsperrt und im **Haus-WLAN**.
|
||||
- [ ] App-Store-/Play-Store-Login auf dem Geraet funktioniert (zum Installieren der Apps).
|
||||
|
||||
### Reihenfolge beim Termin (pro Person)
|
||||
|
||||
Die Reihenfolge ist bewusst gewaehlt: erst der Passwort-Speicher, dann das, was
|
||||
am meisten bringt (Fotos), dann das Gemeinsame (Rezepte).
|
||||
|
||||
1. **Konto-Uebergabe**: Benutzername + Start-Passwort persoenlich uebergeben, Person aendert das Passwort beim ersten Login.
|
||||
2. **Vaultwarden / Bitwarden** (Abschnitt "Vaultwarden zuerst"):
|
||||
- Bitwarden-App installieren, Server-URL `https://vault.kaleschke.info` setzen, anmelden.
|
||||
- Master-Passwort gemeinsam festlegen (wird **nicht** bei Michi gespeichert).
|
||||
- Testeintrag "Test KalliLab" anlegen und wiederfinden.
|
||||
3. **Immich** (Abschnitt "Foto-Backup vom Handy einrichten"):
|
||||
- Immich-App installieren, Server `https://immich.kaleschke.info`, anmelden.
|
||||
- Hintergrund-Backup nur ueber WLAN aktivieren, Kamera-Album auswaehlen.
|
||||
- App offen lassen, bis erste Fotos hochgeladen sind; in der Weboberflaeche sichtbar pruefen.
|
||||
4. **Mealie** (Abschnitt "Rezepte und Einkaufsliste einrichten"):
|
||||
- `https://mealie.kaleschke.info` anmelden.
|
||||
- Gemeinsam ein erstes echtes Rezept anlegen, kategorisieren, Zutaten auf die Einkaufsliste setzen.
|
||||
- Einkaufsliste auf dem Handy oeffnen und einen Eintrag abhaken.
|
||||
5. **Abschluss**: kurz zeigen, was bei Problemen zu tun ist (Abschnitt "Was tun, wenn etwas nicht geht"), besonders Passwort-vergessen und 2FA-verloren.
|
||||
|
||||
### Erfolgskriterium des ersten Termins
|
||||
|
||||
Der Termin gilt als erfolgreich, wenn pro Person **diese drei** Dinge real laufen:
|
||||
|
||||
- [ ] Vaultwarden ist eingerichtet und ein Testeintrag wurde gefunden.
|
||||
- [ ] Immich sichert Handy-Fotos und die ersten Fotos sind in der Weboberflaeche sichtbar.
|
||||
- [ ] In Mealie existiert ein erstes Rezept mit einer Einkaufslisten-Position.
|
||||
|
||||
### Bewusst spaeter (nicht im ersten Termin)
|
||||
|
||||
Damit der erste Termin nicht ueberladen wird, kommen diese Punkte bewusst erst
|
||||
in einem Folgetermin:
|
||||
|
||||
- **Nextcloud** (Dateien/Kalender/Adressbuch) - erst wenn die drei Kern-Apps sitzen.
|
||||
- **Paperless** (Dokumente scannen) - braucht eigenen Scan-Workflow, separater Termin.
|
||||
- **Plex** (Filme/Musik) - reines Komfort-Thema, kein Onboarding-Kern.
|
||||
- **App-uebergreifendes Einheits-Login (SSO/OIDC)** - nicht eingerichtet, nur als Idee notiert (siehe "Bewusst nicht versprochen").
|
||||
| Status | Aufgabe |
|
||||
|---|---|
|
||||
| offen | Pro Familien-Konto Benutzernamen und Start-Passwort persoenlich uebergeben (Vaultwarden Familien-Organisation als Uebergabeweg) |
|
||||
| offen | 2FA-App-Empfehlung pro Person festlegen (zum Beispiel Bitwarden Authenticator, Aegis, 2FAS) |
|
||||
| offen | Vaultwarden Familien-Organisation einrichten und Mitglieder einladen |
|
||||
| offen | Immich Mobile Backup mit jedem Familien-Geraet einmal gemeinsam ausprobieren |
|
||||
| offen | Scan-/Inbox-Anleitung fuer Paperless ergaenzen, sobald der Workflow final ist |
|
||||
| offen | Einladungstermin Wochenende mit konkretem Datum festlegen |
|
||||
|
||||
## Bewusst nicht versprochen
|
||||
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
# Family-View Dashboard - Spezifikation
|
||||
|
||||
Status: **Spezifikation (Doku-only)**, kein Grafana-JSON in diesem Schritt.
|
||||
Audit-Bezug: `docs/AUDIT_2026-05-25.md` Finding **F-08** (Alerts/Sichtbarkeit) und das Sprint-3-TODO "Family-View Dashboard definieren" aus `docs/AUDIT_2026-05-25_TODO.md`.
|
||||
|
||||
## Zweck
|
||||
|
||||
Ein Grafana-Dashboard, das beim Morgen-Check in unter 30 Sekunden zeigt, ob das Homelab gesund ist. Zielgruppe ist primaer der Operator. Wenn die Familie es zufaellig anschaut, soll niemand erschrecken: ueberall gruene Felder bedeuten "alles in Ordnung", ohne dass man die Technik dahinter verstehen muss.
|
||||
|
||||
Das Dashboard ist die Konsolidierung des morgendlichen Pruefablaufs:
|
||||
|
||||
- Sind die wichtigsten Apps erreichbar?
|
||||
- Hat das Backup gestern Nacht funktioniert?
|
||||
- Wann laufen die Zertifikate aus?
|
||||
- Sind die Disks ausreichend frei?
|
||||
- Laufen die kritischen Container?
|
||||
|
||||
## Abgrenzung
|
||||
|
||||
Diese Datei beschreibt nur Layout, Datenquellen und PromQL-Queries. Die JSON-Datei `monitoring/grafana/dashboards/family-view.json` wird **bewusst noch nicht** angelegt, weil:
|
||||
|
||||
- Es noch keine Live-Pruefung gegen die echte Grafana-Instanz gab.
|
||||
- Die Alert-Regeln (Borg-Stale, Cert-Expiry, Container-Down) sind laut `docs/AUDIT_2026-05-25_TODO.md` Sprint 3 selbst noch im "in Arbeit (Regeln vorbereitet)"-Status.
|
||||
- Bei einem halbgaren Dashboard-JSON entstehen mehr Wartungsfragen als Klarheit.
|
||||
|
||||
Die JSON-Datei wird angelegt, sobald (a) die genannten Metriken stabil verfuegbar sind und (b) ein erster manueller Build im Grafana-UI das Layout bestaetigt hat.
|
||||
|
||||
## Datenquellen
|
||||
|
||||
Authoritativ ist `monitoring/grafana/provisioning/datasources/datasources.yml`. Das Dashboard nutzt nur die schon provisionierten Datasources:
|
||||
|
||||
- `Prometheus` - Blackbox, node-exporter, cAdvisor, Traefik-Metrics
|
||||
- optional `Loki` - Log-Volume-Spike als Zusatz-Panel
|
||||
- bewusst nicht: `InfluxDB 3 Core` (das ist Home-Assistant-/Ecowitt-Sicht, nicht Homelab-Health)
|
||||
|
||||
## Layout (4x4 Grid, mobile-vertraeglich)
|
||||
|
||||
| Zeile | Panel | Breite (Grafana w) | Hoehe (Grafana h) |
|
||||
|---|---|---:|---:|
|
||||
| 1 | Endpoints up (Stat, gross gruen/rot) | 12 | 5 |
|
||||
| 1 | Backup heute Nacht (Stat) | 6 | 5 |
|
||||
| 1 | Naechster Cert-Ablauf (Stat, Tage) | 6 | 5 |
|
||||
| 2 | Kritische Container running (Stat-Liste) | 12 | 6 |
|
||||
| 2 | Disk-Fuellung (Bargraph, je Mountpoint) | 12 | 6 |
|
||||
| 3 | Endpoint-Tabelle (Table: Host, Status, Latenz) | 24 | 8 |
|
||||
| 4 | Cert-Tage-Tabelle (Table: Host, Tage bis Ablauf) | 12 | 6 |
|
||||
| 4 | Container-Status-Tabelle (Table: kritischer Container, Running, letztes Restart) | 12 | 6 |
|
||||
|
||||
Dashboard-Metadaten:
|
||||
|
||||
- UID: `homelab-family-view`
|
||||
- Title: `Homelab / Family View`
|
||||
- Tags: `homelab`, `family-view`, `morning-check`
|
||||
- Refresh: `30s`
|
||||
- Default-Zeitfenster: `now-24h` bis `now`
|
||||
- Folder: `Homelab`
|
||||
|
||||
## Panel-Spezifikation
|
||||
|
||||
### Panel 1: Endpoints up
|
||||
|
||||
- Type: `stat`
|
||||
- Title: `Apps online`
|
||||
- Query: `sum(probe_success{job="blackbox-http"})`
|
||||
- Anzeige: gruene Zahl bei Gesamtzahl, Wechsel auf rot wenn `< Soll-Anzahl`.
|
||||
- Threshold: Soll-Anzahl wird aus `monitoring/blackbox/blackbox.yml` und Prometheus-Scrape-Liste abgeleitet (zum Doku-Zeitpunkt 19 HTTPS-Ziele laut `docs/MIGRATION_LOG.md` 2026-05-25-Monitoring-Konsolidierung).
|
||||
- Subtitel im Panel: `von <N> erreichbar`. (Soll-Wert wird beim Bau aus dem aktuellen Target-Count gesetzt; nicht hartcoden.)
|
||||
|
||||
### Panel 2: Backup heute Nacht
|
||||
|
||||
- Type: `stat`
|
||||
- Title: `Borg-Lauf`
|
||||
- Query (sobald Borg-Stale-Metrik im Textfile-Collector live ist):
|
||||
```promql
|
||||
(time() - homelab_borg_last_completed_timestamp_seconds) / 3600
|
||||
```
|
||||
- Einheit: `h`
|
||||
- Threshold:
|
||||
- 0-26 h gruen
|
||||
- 26-30 h gelb
|
||||
- >30 h rot
|
||||
- Subtitel im Panel: `Stunden seit letztem completed-Lauf`.
|
||||
- Fallback bis Metrik live: Panel zeigt `n/a`, Doku-Hinweis in der Beschreibung.
|
||||
|
||||
### Panel 3: Naechster Cert-Ablauf
|
||||
|
||||
- Type: `stat`
|
||||
- Title: `Cert laeuft in`
|
||||
- Query:
|
||||
```promql
|
||||
min((probe_ssl_earliest_cert_expiry{job="blackbox-http"} - time()) / 86400)
|
||||
```
|
||||
- Einheit: `d` (Tage)
|
||||
- Threshold:
|
||||
- >14 gruen
|
||||
- 7-14 gelb
|
||||
- <7 rot
|
||||
- Subtitel: `Tage bis kleinste Restlaufzeit aller geprueften Hosts`.
|
||||
|
||||
### Panel 4: Kritische Container running
|
||||
|
||||
- Type: `stat`
|
||||
- Title: `Kritische Container`
|
||||
- Query (sobald Container-Up-Metrik live ist):
|
||||
```promql
|
||||
sum(homelab_critical_container_running)
|
||||
```
|
||||
- Threshold: erwartete Anzahl gruen, jeder fehlende Container rot.
|
||||
- Subtitel: `von <N> erwartet`. Erwartete Liste pflegen wir in `services/posture-check` / Textfile-Exporter (siehe `docs/AUDIT_2026-05-25_TODO.md` Sprint 3 "Container-Down-Alert").
|
||||
- Fallback: cAdvisor-Query als Naeherung, solange Textfile-Metrik noch nicht produktiv ist:
|
||||
```promql
|
||||
count(rate(container_last_seen{name=~"traefik|authelia|postgresql17|Redis|gitea|komodo-core|komodo-mongo|komodo-periphery|monitoring-prometheus|monitoring-grafana|monitoring-loki|monitoring-alertmanager"}[5m]) > 0)
|
||||
```
|
||||
|
||||
### Panel 5: Disk-Fuellung
|
||||
|
||||
- Type: `bargauge`
|
||||
- Title: `Disk-Fuellung`
|
||||
- Query:
|
||||
```promql
|
||||
100 * (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"})
|
||||
```
|
||||
- Anzeige: pro Mountpoint, sortiert absteigend.
|
||||
- Threshold:
|
||||
- <70 gruen
|
||||
- 70-85 gelb
|
||||
- >85 rot
|
||||
- Subtitel: `Prozent belegt`.
|
||||
|
||||
### Panel 6: Endpoint-Tabelle
|
||||
|
||||
- Type: `table`
|
||||
- Title: `Endpoint-Status`
|
||||
- Spalten:
|
||||
- Host (Instance)
|
||||
- Status (`UP` / `DOWN`)
|
||||
- Antwortzeit (probe_duration_seconds)
|
||||
- Queries:
|
||||
- `probe_success{job="blackbox-http"}` -> Mapping: `1` -> `UP` (gruen), `0` -> `DOWN` (rot)
|
||||
- `probe_duration_seconds{job="blackbox-http"}` -> Sekunden
|
||||
- Sortierung: DOWN oben, dann nach Antwortzeit absteigend.
|
||||
|
||||
### Panel 7: Cert-Tage-Tabelle
|
||||
|
||||
- Type: `table`
|
||||
- Title: `Cert-Tage bis Ablauf`
|
||||
- Spalten: Host, Tage
|
||||
- Query:
|
||||
```promql
|
||||
(probe_ssl_earliest_cert_expiry{job="blackbox-http"} - time()) / 86400
|
||||
```
|
||||
- Sortierung: aufsteigend (am ehesten ablaufende oben).
|
||||
- Color-Mapping wie Panel 3.
|
||||
|
||||
### Panel 8: Container-Status-Tabelle
|
||||
|
||||
- Type: `table`
|
||||
- Title: `Kritische Container`
|
||||
- Spalten: Container, Running (1/0), letztes Restart (Sekunden seit Start)
|
||||
- Queries:
|
||||
- sobald Textfile-Metrik live: `homelab_critical_container_running` (Label `name`)
|
||||
- Fallback aus cAdvisor: `container_start_time_seconds{name=~"<Whitelist>"}`
|
||||
- Sortierung: nicht-running zuerst.
|
||||
|
||||
## Spaeter ergaenzbar (nicht Teil der ersten Version)
|
||||
|
||||
- Loki-Log-Volume-Spike-Panel
|
||||
- node_exporter Memory-Saturation-Panel
|
||||
- Plex-Sessions (nur wenn Plex-Exporter eingerichtet ist; aktuell nicht geplant)
|
||||
- Immich Asset-Wachstum (eigenes Dashboard, nicht Family-View)
|
||||
|
||||
## Build-Reihenfolge fuer den spaeteren JSON
|
||||
|
||||
Wenn das JSON gebaut wird, bitte in dieser Reihenfolge:
|
||||
|
||||
1. Sicherstellen, dass alle Metriken aus den Queries oben in Prometheus auffindbar sind (`/graph` Smoke-Test).
|
||||
2. Dashboard in Grafana-UI manuell zusammenklicken; Layout an dieser Spezifikation entlang.
|
||||
3. JSON exportieren, in `monitoring/grafana/dashboards/family-view.json` ablegen.
|
||||
4. Provisioning-Provider laesst die Datei automatisch laden (siehe `monitoring/grafana/provisioning/dashboards/dashboards.yml`).
|
||||
5. Bei jeder Schema-Aenderung Doku hier nachziehen, damit Spec und JSON nicht driften.
|
||||
|
||||
## Smoke-Test nach Aktivierung
|
||||
|
||||
- Dashboard laedt unter `https://monitoring.kaleschke.info/d/homelab-family-view/`.
|
||||
- Alle 8 Panels rendern ohne `No data`.
|
||||
- Im Normalbetrieb erscheinen Panel 1-5 vollstaendig gruen.
|
||||
- Ein bewusster Test-Stale-Borg oder ein Container-Stop laesst die zugehoerigen Panels auf gelb/rot wechseln.
|
||||
|
||||
## Was das Dashboard NICHT ersetzt
|
||||
|
||||
- ntfy-Alerts: das Dashboard ist passiv (Pull), ntfy ist aktiv (Push). Beide sind notwendig.
|
||||
- DR-Doku: `docs/DISASTER_RECOVERY.md` bleibt die Recovery-Quelle.
|
||||
- Restore-Tests: `docs/RESTORE_DRILL_ROUTINE.md` ist die Kadenz, die das Dashboard nicht ersetzt.
|
||||
- Familien-Onboarding: `docs/FAMILY_ONBOARDING.md` ist die Doku fuer die Familie, dieses Dashboard ist Operator-Tool.
|
||||
@@ -0,0 +1,104 @@
|
||||
# FRITZ!Box Portfreigaben - Korrektur-Vorbereitung
|
||||
|
||||
Status: **umgesetzt 2026-05-28**, Doku bleibt als Historie und Begruendungs-Anker.
|
||||
Audit-Bezug: `docs/AUDIT_2026-05-25_TODO.md` Sprint 4 ("FRITZ!Box-Portfreigaben gegen Repo-Soll abgleichen") und `docs/NETWORK_INVENTORY.md`.
|
||||
|
||||
## Umsetzungs-Befund 2026-05-28
|
||||
|
||||
| Punkt | Entscheidung | Validierung |
|
||||
|---|---|---|
|
||||
| 1. `80/tcp` entfernen | **umgesetzt** | Mobilfunk-Test: `http://vault.kaleschke.info` Timeout, `https://...` weiter erreichbar. Lokal via LAN: HTTP->HTTPS-Redirect funktioniert weiter durch Traefik. |
|
||||
| 2. `222/tcp` ergaenzen | **bewusst NICHT umgesetzt** | Tailscale bleibt Operator-Pfad; GitHub-Mirror deckt DR-Bootstrap ab; SSH-Brute-Force-Vektor vermieden. Repo-Soll in `NETWORK_INVENTORY.md` und `MASTER_V2.md` Sektion 10 entsprechend angepasst. |
|
||||
| 3. UPnP-Selbstfreigabe `PC-192-168-178-71` | **umgesetzt** | "Selbstständige Portfreigaben fuer dieses Geraet erlauben" deaktiviert. Identifiziert als VONETS-WiFi-Bridge (Hostname `VONETS.COM`, MAC `00:17:13:2F:61:96`) — vermutlich Bridge zum SolarEdge-Wechselrichter. SolarEdge-Cloud-Sync ist outbound und benoetigt keine UPnP. |
|
||||
|
||||
Aktiver Endstand: ausschliesslich `443/tcp -> 192.168.178.58:443` (Traefik HTTPS) ist von WAN aus erreichbar.
|
||||
|
||||
## Aktueller FRITZ!Box-Befund (2026-05-27)
|
||||
|
||||
Aus dem Operator-Live-Check der FRITZ!Box-UI:
|
||||
|
||||
- aktiv: `80/tcp` -> `192.168.178.58`
|
||||
- aktiv: `443/tcp` -> `192.168.178.58`
|
||||
- fehlt: `222/tcp` -> `192.168.178.58` (Gitea-SSH)
|
||||
- zusaetzlich gemeldet: eine Portfreigabe durch das Geraet `PC-192-168-178-71` (Selbst-Freigabe per UPnP)
|
||||
|
||||
## Soll-Stand laut Repo
|
||||
|
||||
`docs/NETWORK_INVENTORY.md` definiert genau zwei aktive Portfreigaben:
|
||||
|
||||
| Erwartete Freigabe | Ziel | Begruendung |
|
||||
|---|---|---|
|
||||
| `443/tcp` -> `192.168.178.58:443` | Traefik HTTPS | einziger Public-HTTPS-Einstieg, Wildcard-Zert ueber Cloudflare-DNS-Challenge |
|
||||
| `222/tcp` -> `192.168.178.58:222` | Gitea SSH | Git-SSH-Push/Pull; dokumentierte Ausnahme |
|
||||
|
||||
Port `80/tcp` ist im Cloudflare-DNS-Challenge-Modell **nicht** notwendig.
|
||||
|
||||
## Drei Korrektur-Punkte
|
||||
|
||||
### 1. `80/tcp` entfernen
|
||||
|
||||
Begruendung:
|
||||
|
||||
- ACME laeuft als Cloudflare-DNS-Challenge (`traefik/docker-compose.yml`), nicht als HTTP-01.
|
||||
- Traefik leitet intern jeden HTTP-Request auf `https://` weiter; ein WAN-`80`-Listener bietet keinen Mehrwert, oeffnet aber einen zusaetzlichen Angriffsvektor (Header-/Method-Scanning, Open-Redirect-Versuche bevor TLS terminiert).
|
||||
- Innerhalb des LAN funktioniert die Browser-Auto-HTTPS-Umleitung weiter ueber AdGuard-DNS.
|
||||
|
||||
Empfehlung: WAN-Eintrag `80/tcp` in FRITZ!Box-UI **entfernen** nach Operator-Go.
|
||||
|
||||
Validierung nach Aenderung:
|
||||
|
||||
```bash
|
||||
# WAN-seitiger Test, idealerweise von einem Geraet im Mobilfunknetz oder Tailscale-Exit-Node
|
||||
curl -sI http://kaleschke.info/ # erwartet: Connection refused / Timeout
|
||||
curl -sI https://vault.kaleschke.info/ # erwartet: HTTP/2 200 oder Authelia-Redirect
|
||||
```
|
||||
|
||||
### 2. `222/tcp` ergaenzen (nur wenn externes Git-SSH wirklich gewuenscht)
|
||||
|
||||
Frage an Operator: Wird `git@git.kaleschke.info -p 222` von extern gebraucht? Hinweise:
|
||||
|
||||
| Pro `222/tcp` extern | Contra `222/tcp` extern |
|
||||
|---|---|
|
||||
| Push/Pull vom unterwegs-Laptop ohne Tailscale | Tailscale ist schon der Operator-Pfad, deckt das voll ab |
|
||||
| GitHub-Mirror-Bootstrap funktioniert dann auch ohne Tailscale | GitHub-Push-Mirror laeuft automatisch von Gitea aus, braucht kein WAN-SSH |
|
||||
| Externe Webhooks gegen Git push (nicht in Nutzung) | weniger Angriffsflaeche fuer SSH-Brute-Force |
|
||||
|
||||
Empfehlung: `222/tcp` **nicht** ergaenzen, solange Tailscale stabil verfuegbar ist. Stattdessen `docs/NETWORK_INVENTORY.md` und `HOMELAB_ARCHITECTURE_MASTER_V2.md` darauf abgleichen, dass Gitea-SSH bewusst LAN/Tailscale-only ist.
|
||||
|
||||
Wenn Operator entscheidet, `222/tcp` doch extern zu oeffnen: zusaetzlich SSH-Login auf Key-only setzen, Brute-Force-Limits in Gitea pruefen, `docs/NETWORK_INVENTORY.md` "Erwartete Freigabe"-Tabelle aktualisieren.
|
||||
|
||||
### 3. UPnP-Selbstfreigabe von `PC-192-168-178-71` deaktivieren
|
||||
|
||||
Begruendung:
|
||||
|
||||
- Geraete-initiierte Portfreigaben (UPnP) sind ausserhalb der Repo-Sollkonfiguration.
|
||||
- Welcher Port von welchem Programm geoeffnet wurde, ist aus der FRITZ!Box-UI heraus nicht versionierbar.
|
||||
- Wenn der Port gebraucht wird, gehoert er als bewusste Operator-Freigabe in `docs/NETWORK_INVENTORY.md`.
|
||||
|
||||
Empfehlung in zwei Stufen:
|
||||
|
||||
1. FRITZ!Box-UI: in den Geraete-Details fuer `PC-192-168-178-71` die aktuelle Selbstfreigabe-Liste pruefen und mit dem Operator besprechen.
|
||||
2. Wenn der Port nicht gebraucht wird: Selbstfreigabe deaktivieren. Optional: UPnP global pro Geraet abschalten ("Selbststaendige Portfreigaben fuer dieses Geraet erlauben" abwaehlen).
|
||||
|
||||
## Schutzregeln
|
||||
|
||||
- Keine Router-Aenderung ohne ausdrueckliches Operator-Go.
|
||||
- Nach jeder Aenderung: `docs/NETWORK_INVENTORY.md` Abschnitt "FRITZ!Box (WAN -> Host)" gegen den neuen UI-Stand abgleichen.
|
||||
- Aenderung in `docs/MIGRATION_LOG.md` als kurzer Eintrag dokumentieren (was/warum/Validierung).
|
||||
- Bei `80/tcp`-Entfernung kurz prufen, ob irgendein externer Dienst noch HTTP-01 nutzen wollte (sollte nicht der Fall sein).
|
||||
|
||||
## Nicht Teil dieser Vorbereitung
|
||||
|
||||
- FRITZ!OS-Update 8.21 -> aktuell. Das ist eigenes Service-Fenster und braucht WAN/Tailscale-Aufbau-Beobachtung.
|
||||
- IPv6-Exposure. Wenn Telekom IPv6 zustellt und Apps via Cloudflare-AAAA erreichbar sind, kann WAN-Filter pro Port noetig werden. Separater Doku-Punkt in `docs/NETWORK_INVENTORY.md` Offene Entscheidungen.
|
||||
- Mobilfunk-Failover-Stick. Bewusst nicht eingerichtet.
|
||||
|
||||
## Offene Punkte
|
||||
|
||||
| Status | Punkt | Naechster Schritt |
|
||||
|---|---|---|
|
||||
| erledigt 2026-05-28 | `80/tcp` entfernen | umgesetzt, Mobilfunk-validiert |
|
||||
| erledigt 2026-05-28 (bewusst nicht) | `222/tcp` Entscheidung | bleibt Tailscale-only; Repo-Soll entsprechend angepasst |
|
||||
| erledigt 2026-05-28 | UPnP-Freigabe `PC-192-168-178-71` | UPnP-Selbstfreigabe-Recht fuer VONETS-Bridge deaktiviert |
|
||||
| offen | FRITZ!OS 8.21 Update | Service-Fenster, separat geplant |
|
||||
| offen | IPv6-Exposure pruefen | bei naechstem WAN-Touch mit erfassen |
|
||||
@@ -1,117 +0,0 @@
|
||||
# Guest / IoT Network Runbook
|
||||
|
||||
Stand: 2026-06-06
|
||||
|
||||
Dieses Runbook beschreibt den sicheren Weg, das FRITZ!Box-Gastnetz zu aktivieren,
|
||||
ohne versehentlich Homelab-Admin-Ports aus dem Gastsegment erreichbar zu machen.
|
||||
|
||||
## Zielbild
|
||||
|
||||
- Normales LAN bleibt `192.168.178.0/24`.
|
||||
- Kallilabcore bleibt im normalen LAN unter `192.168.178.58`.
|
||||
- FRITZ!Box-Gast-WLAN darf Internetzugang haben, aber keinen Zugriff auf
|
||||
`192.168.178.0/24`.
|
||||
- Homelab-Admin-Pfade bleiben Operator-only:
|
||||
- Tailscale fuer Admin-Zugriff
|
||||
- Authelia/2FA fuer geschuetzte Web-UIs
|
||||
- keine LAN-Admin-Ports aus dem Gastnetz
|
||||
|
||||
## Vorbedingungen
|
||||
|
||||
Vor dem Einschalten des Gast-WLANs muessen diese Preflights gruen sein:
|
||||
|
||||
```powershell
|
||||
G:\Gitea_Clone\homelab-infra\ops\maintenance\check-guest-iot-isolation.ps1 -Mode LanPreflight
|
||||
```
|
||||
|
||||
Erwartung im normalen LAN:
|
||||
|
||||
- `192.168.178.58:8082` ist blockiert (AdGuard Admin nur Tailscale).
|
||||
- `192.168.178.58:8181` ist blockiert (InfluxDB nicht LAN-exponiert).
|
||||
- `192.168.178.58:80`, `443`, `222` koennen im normalen LAN erreichbar sein.
|
||||
|
||||
Auf Unraid zusaetzlich:
|
||||
|
||||
```bash
|
||||
/mnt/user/services/homelab-infra/ops/maintenance/check-guest-iot-preflight.sh
|
||||
```
|
||||
|
||||
Validierung 2026-06-06: Host-Preflight erfolgreich, Report
|
||||
`/mnt/user/backups/restore-reports/guest-iot-preflight-2026-06-06-131316.md`.
|
||||
Ergebnis: FRITZ!Box 7590 per TR-064 erreichbar, `192.168.178.58:8082`
|
||||
blockiert, `100.80.98.33:8082` erreichbar, `192.168.178.58:8181` blockiert.
|
||||
|
||||
Gast-WLAN-Smoke 2026-06-06: Operator hat ein iPhone mit `Fritzi Gastzugang`
|
||||
verbunden und folgende Ziele getestet; alle waren aus dem Gast-WLAN nicht
|
||||
erreichbar:
|
||||
|
||||
- `http://192.168.178.58:8082`
|
||||
- `http://192.168.178.58:8181`
|
||||
- `http://192.168.178.58:222`
|
||||
- `https://192.168.178.58`
|
||||
- `http://192.168.178.1`
|
||||
|
||||
Damit ist die Gastnetz-Isolation fuer die getesteten Homelab-/Router-Adminpfade
|
||||
validiert.
|
||||
|
||||
## FRITZ!Box Schritte
|
||||
|
||||
In der FRITZ!Box UI:
|
||||
|
||||
1. `WLAN -> Gastzugang` oeffnen.
|
||||
2. `Gastzugang aktiv` einschalten.
|
||||
3. WPA2/WPA3-Verschluesselung aktiv lassen.
|
||||
4. Eigenen Gast-SSID-Namen setzen, z. B. `Fritzi-Gast`.
|
||||
5. Starkes Passwort setzen und in Vaultwarden ablegen.
|
||||
6. Option `Geraete im Gastnetz duerfen miteinander kommunizieren` deaktiviert
|
||||
lassen, sofern nicht bewusst gebraucht.
|
||||
7. Option fuer Zugriff auf das Heimnetz / private Netzwerk deaktiviert lassen.
|
||||
8. Gastzugang speichern.
|
||||
|
||||
Wichtig: Die genaue FRITZ!OS-8.25-UI-Beschriftung kann leicht variieren. Der
|
||||
entscheidende Punkt ist: Gastgeraete duerfen keinen Zugriff auf das Heimnetz
|
||||
haben.
|
||||
|
||||
## Verifikation
|
||||
|
||||
Ein Handy oder Laptop mit dem Gast-WLAN verbinden, dann auf diesem Geraet testen:
|
||||
|
||||
```powershell
|
||||
G:\Gitea_Clone\homelab-infra\ops\maintenance\check-guest-iot-isolation.ps1 -Mode Guest
|
||||
```
|
||||
|
||||
Erwartung aus dem Gast-WLAN:
|
||||
|
||||
- `192.168.178.58:80` blockiert
|
||||
- `192.168.178.58:443` blockiert
|
||||
- `192.168.178.58:222` blockiert
|
||||
- `192.168.178.58:8082` blockiert
|
||||
- `192.168.178.58:8181` blockiert
|
||||
- `192.168.178.1:80` blockiert oder nur Gast-Gateway-Ansicht
|
||||
|
||||
Wenn der Test `Risk count: 0` meldet, ist die Isolation fuer die getesteten
|
||||
Homelab-Admin-Pfade ausreichend.
|
||||
|
||||
## Betrieb
|
||||
|
||||
- Familien-/Gaestegeraete kommen ins Gast-WLAN, wenn sie keinen direkten Zugriff
|
||||
auf LAN-Geraete brauchen.
|
||||
- Homelab-Apps fuer Familie laufen perspektivisch ueber HTTPS/OIDC, nicht ueber
|
||||
direkten LAN-Zugriff.
|
||||
- Geraete, die lokale Discovery brauchen (z. B. manche Smart-TV/Plex-Szenarien),
|
||||
bleiben im normalen LAN oder bekommen eine separate bewusste Entscheidung.
|
||||
|
||||
## Rollback
|
||||
|
||||
Wenn nach Aktivierung etwas Unerwartetes passiert:
|
||||
|
||||
1. FRITZ!Box: `WLAN -> Gastzugang` oeffnen.
|
||||
2. Gastzugang deaktivieren.
|
||||
3. Speichern.
|
||||
4. Normalen LAN-Zugriff pruefen:
|
||||
```powershell
|
||||
G:\Gitea_Clone\homelab-infra\ops\maintenance\check-guest-iot-isolation.ps1 -Mode LanPreflight
|
||||
```
|
||||
|
||||
Es werden durch dieses Runbook keine Docker-Stacks, Secrets oder produktiven
|
||||
Appdaten veraendert.
|
||||
@@ -3,20 +3,8 @@
|
||||
Status: Hardware-Baseline erfasst; USV/Power-Loss ist als bewusst akzeptiertes Betreiber-Risiko dokumentiert.
|
||||
Host: `Kallilabcore`
|
||||
Letzte Pruefung: 2026-05-26
|
||||
Doku-Stand Betreiberentscheidungen: 2026-06-05
|
||||
Naechster Review: 2026-08-26
|
||||
|
||||
## Betreiber-Entscheidungen (Stand 2026-06-05)
|
||||
|
||||
Diese drei Punkte waren bisher diffuse TBDs und sind jetzt als bewusste
|
||||
Entscheidungen festgehalten. Details in den jeweiligen Abschnitten unten.
|
||||
|
||||
| Thema | Entscheidung | Review-Trigger |
|
||||
|---|---|---|
|
||||
| USV / Power Loss | **Bewusst auf Q3/2026 geparkt.** Keine Anschaffung dieses Quartal; Power-Loss bleibt akzeptiertes Risiko. | Naechstes Hardware-Upgrade, erneuter realer Stromausfall mit Datenfolge, oder Q3-Review (ab 2026-07-01) |
|
||||
| Cold-Backup-Rotation | **Bewusst Hetzner-only.** Off-site bleibt allein das Hetzner-Borg-Repo; keine zweite rotierende Cold-Kopie. | Stark wachsender Datenwert, wiederholte Hetzner-Probleme, oder geaenderte Betreiber-Praeferenz |
|
||||
| Stromverbrauch messen | **Bewusst ohne Messung (Entscheidung 2026-06-06).** Kein Messgeraet; Werte bleiben dauerhaft offen, kein Beschaffungs-Todo. | Nur falls spaeter doch ein Messgeraet angeschafft wird oder Strom-/Kostenfrage relevant wird |
|
||||
|
||||
## Zweck
|
||||
|
||||
Dieses Dokument beschreibt die physische Basis des Homelabs. Es ist die Grundlage fuer Capacity Planning, Restore-Zeit, Ersatzteilplanung, USV-Verhalten und Entscheidungen wie Immich-ML, Plex-Transcoding oder Storage-Erweiterung.
|
||||
@@ -31,7 +19,7 @@ Dieses Dokument beschreibt die physische Basis des Homelabs. Es ist die Grundlag
|
||||
| Unraid-Version | 7.2.4 |
|
||||
| Rolle | Single-Host Homelab, Docker Compose via Komodo |
|
||||
| Boot-Medium | Samsung Flash Drive, 59.8G, FAT32 |
|
||||
| Flash-Backup | In Borg-Scope aufgenommen, siehe `docs/RESTORE_MATRIX.md` |
|
||||
| Flash-Backup | In Borg-Scope aufgenommen, siehe `docs/MIGRATION_LOG.md` |
|
||||
|
||||
## CPU
|
||||
|
||||
@@ -108,7 +96,7 @@ tailscale ip -4
|
||||
| Disk1 | `md1p1` / physisch `sdc` | WDC WD60EFAX-68JH4N1 | `WD-WX32D90PC0V0` | 5.5T | XFS auf md1p1 | Array-Daten | SMART passed |
|
||||
| Parity | physisch `sdb` | TOSHIBA HDWG480 | `2460A03VFA3H` | 7.3T | n/a | Parity | SMART passed |
|
||||
| Boot | `sda1` | Samsung Flash Drive | `0375125090000587` | 59.8G | FAT32 | Unraid Boot | aktiv |
|
||||
| Cold Backup | bewusst keiner | n/a | n/a | n/a | n/a | Externe Rotation | **bewusst Hetzner-only** (Entscheidung 2026-06-05); off-site allein via Hetzner-Borg |
|
||||
| Cold Backup | TBD | TBD | TBD | TBD | TBD | Externe Rotation | offen |
|
||||
|
||||
Pruefkommando:
|
||||
|
||||
@@ -150,27 +138,18 @@ Bewertung:
|
||||
|
||||
- Aktueller Befund 2026-05-26: keine funktionierende USV-Absicherung nachgewiesen.
|
||||
- `apcupsd` ist zwar auf dem System vorhanden, aber nicht aktiv.
|
||||
- **Operator-Entscheidung 2026-06-05: USV-Anschaffung bewusst auf Q3/2026 geparkt.** Keine Beschaffung in diesem Quartal.
|
||||
- Operator-Entscheidung 2026-05-26: aktuell keine USV-Anschaffung.
|
||||
- Power-Loss bleibt damit ein bewusst akzeptiertes Risiko fuer Docker-/DB-State und laufende Writes.
|
||||
- Review-Trigger (einer reicht): naechstes Hardware-Upgrade, ein erneuter realer Stromausfall mit Datenfolge, oder der Q3-Review ab 2026-07-01.
|
||||
- Wenn die Entscheidung in Q3 zugunsten einer USV kippt, ist das Mindestkriterium ein USB-HID-faehiges Geraet (~600-900 VA), das von `apcupsd` erkannt wird, damit der bereits vorkonfigurierte Shutdown-Pfad ohne Zusatzsoftware greift.
|
||||
- Review-Ausloeser: Hardware-Erweiterung, wiederholte Stromausfaelle, Datenkorruption oder Veraenderung der Betreiber-Prioritaet.
|
||||
|
||||
## Stromverbrauch
|
||||
|
||||
**Bewusst ohne Messung (Operator-Entscheidung 2026-06-06).** Es wird kein
|
||||
Messgeraet beschafft; Idle/Normal/Backup/Last bleiben dauerhaft offen. Kein
|
||||
offener Todo. Falls spaeter doch eine Mess-Steckdose angeschafft wird, reicht
|
||||
ein einziger Messdurchlauf, um die Tabelle zu fuellen.
|
||||
|
||||
| Zustand | Verbrauch | Messmethode | Datum |
|
||||
|---|---:|---|---|
|
||||
| Idle | offen | schaltbare Mess-Steckdose, 10 min Mittelwert ohne aktive Jobs | nach Beschaffung |
|
||||
| Normalbetrieb | offen | Mess-Steckdose, typischer Tagbetrieb mit laufenden Apps | nach Beschaffung |
|
||||
| Backup-Lauf | offen | Mess-Steckdose, waehrend naechtlichem Borg-Lauf | nach Beschaffung |
|
||||
| Last | offen | Mess-Steckdose, unter CPU-Last (z. B. Immich-ML/Parity-Check) | nach Beschaffung |
|
||||
|
||||
Beschaffungs-Trigger: einfache schaltbare Energiemess-Steckdose; danach ein
|
||||
einziger Messdurchlauf reicht, um diese Tabelle dauerhaft zu fuellen.
|
||||
| Idle | TBD | externes Messgeraet erforderlich | TBD |
|
||||
| Normalbetrieb | TBD | externes Messgeraet erforderlich | TBD |
|
||||
| Backup-Lauf | TBD | externes Messgeraet erforderlich | TBD |
|
||||
| Last | TBD | externes Messgeraet erforderlich | TBD |
|
||||
|
||||
## Ersatzteil- und Lifecycle-Plan
|
||||
|
||||
@@ -181,7 +160,7 @@ einziger Messdurchlauf reicht, um diese Tabelle dauerhaft zu fuellen.
|
||||
| Parity | Kleiner als neue groesste Datenplatte | Parity-Upgrade vor Datenplatten-Upgrade |
|
||||
| Boot-USB | Lesefehler oder Alter TBD | Flash-Backup verifizieren, Ersatzstick vorbereiten |
|
||||
| RAM | Swap/OOM oder Immich/Nextcloud-Druck | Ausbau planen |
|
||||
| USV | keine funktionierende USV-Abschaltung | Anschaffung 2026-06-05 bewusst auf Q3/2026 geparkt; Trigger: Hardware-Upgrade, realer Stromausfall mit Datenfolge, oder Q3-Review |
|
||||
| USV | keine funktionierende USV-Abschaltung | Risiko am 2026-05-26 bewusst akzeptiert; bei Review erneut bewerten |
|
||||
|
||||
## Audit-Kommandos
|
||||
|
||||
|
||||
+1
-8
@@ -1,15 +1,8 @@
|
||||
# Home Assistant -> InfluxDB 3 -> Grafana
|
||||
|
||||
**Status 2026-06-06: archiviert / nicht aktiv.** Home Assistant existiert seit
|
||||
dem Crash aktuell nicht mehr. Dieses Dokument ist nur noch ein historischer
|
||||
Zielbild-Entwurf fuer einen spaeteren Neuaufbau. Das fruehere TODO
|
||||
`influxdb3_homeassistant_token` wurde aus der aktiven Master-Liste gestrichen;
|
||||
vor Token-, InfluxDB-Writer- oder Ecowitt-Arbeiten muss Home Assistant zuerst
|
||||
neu aufgesetzt und neu inventarisiert werden.
|
||||
|
||||
Ziel: Home Assistant schreibt ausgewaehlte Ecowitt- und Energiesensoren nach InfluxDB 3 Core. Grafana bleibt das Langzeit-Dashboard, Home Assistant bleibt die Automationszentrale.
|
||||
|
||||
## Historischer Live-Stand 2026-05-04
|
||||
## Live-Stand 2026-05-04
|
||||
|
||||
- Home Assistant ist per SSH unter `192.168.178.50:22222` erreichbar.
|
||||
- `ha core check` ist erfolgreich.
|
||||
@@ -0,0 +1,123 @@
|
||||
# H:/ Nearline Pull
|
||||
|
||||
Status: **produktiv** (2026-05-28). Erster echter Lauf 2026-05-27 20:45 erfolgreich. Windows Scheduled Task `KalliLab H Drive Nearline Pull` taeglich 05:30 ist seit 2026-05-28 aktiv.
|
||||
|
||||
## Erstlauf-Befund 2026-05-27
|
||||
|
||||
- Erster `-WhatIf`-loser Lauf: 18 Borg-Dump-Files erfolgreich gepullt, 4 unraid-flash-config-Files und 10 Gitea-Bundle-Files blockiert (`Zugriff verweigert`).
|
||||
- Ursache: Bundles wurden mit `chmod 600` geschrieben, Flash-Config bewusst `0600 root:root`, Filebrowser-Dump erbte 0640. Der SMB-Read-Share auf dem Operator-PC liest mit unprivilegierten Rechten, kein root.
|
||||
- Fixes im selben Sprint:
|
||||
- `ops/borg-ui/scripts/gitea-bundle-mirror.sh` schreibt Bundles und Sidecars jetzt 0644 (Bundle-Inhalt = Git-Historie, ohne Secrets durch `.gitignore`).
|
||||
- `ops/borg-ui/scripts/pre-backup-dumps.sh` setzt alle Dumps via `atomic_write` per Default auf 0644; `unraid-flash-config.*` bleibt explizit 0600.
|
||||
- `ops/h-drive-nearline/pull-critical-backups.ps1` excluded die `unraid-flash-config.*`-Familie ueber `/XF`, damit Flash-Config bewusst nicht in den Nearline-Scope kommt.
|
||||
- Zweiter Lauf (nach Fixes): beide Robocopy-Jobs Exit-Code 1, **19 Borg-Dumps + 10 Gitea-Bundle-Files** auf H:/.
|
||||
|
||||
## Zweck
|
||||
|
||||
`H:/` ist eine zweite lokale Nearline-Kopie fuer die wichtigsten Restore-Artefakte. Es ersetzt weder Hetzner/Borg noch ein echtes Off-site-/Airgap-Ziel, reduziert aber das Risiko, dass ein lokaler Restore nur vom Unraid-Array abhaengt.
|
||||
|
||||
## Quelle und Ziel
|
||||
|
||||
| Zweck | Quelle | Ziel |
|
||||
|---|---|---|
|
||||
| Aktuelle Dumps inklusive Flash-Backup | `\\192.168.178.58\backups\borg\dumps\latest` | `H:\kallilab-nearline-backups\borg-dumps\latest` |
|
||||
| Gitea-Bundles | `\\192.168.178.58\backups\git-bundles\gitea` | `H:\kallilab-nearline-backups\git-bundles\gitea` |
|
||||
|
||||
Das Skript kopiert bewusst **nicht** mit `/MIR` und loescht keine Dateien auf `H:/`. Alte Artefakte duerfen dort erst nach manueller Sichtpruefung geloescht werden.
|
||||
|
||||
## Skript
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File G:\Gitea_Clone\homelab-infra\ops\h-drive-nearline\pull-critical-backups.ps1 -WhatIf
|
||||
```
|
||||
|
||||
Echter Lauf:
|
||||
|
||||
```powershell
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File G:\Gitea_Clone\homelab-infra\ops\h-drive-nearline\pull-critical-backups.ps1
|
||||
```
|
||||
|
||||
Reports landen unter:
|
||||
|
||||
```text
|
||||
H:\kallilab-nearline-backups\_reports
|
||||
```
|
||||
|
||||
Robocopy-Logs landen unter:
|
||||
|
||||
```text
|
||||
H:\kallilab-nearline-backups\_logs
|
||||
```
|
||||
|
||||
## Geplanter Schedule
|
||||
|
||||
Empfohlen: taeglich 05:30 Uhr, nach dem Borg-Dump-Fenster um ca. 04:00 Uhr.
|
||||
|
||||
Aktiv seit 2026-05-28. Tatsaechlicher Register-Befehl (RunLevel-Enum-Wert ist `Limited`, nicht `LeastPrivilege`):
|
||||
|
||||
```powershell
|
||||
$Action = New-ScheduledTaskAction `
|
||||
-Execute "powershell.exe" `
|
||||
-Argument "-NoProfile -ExecutionPolicy Bypass -File `"G:\Gitea_Clone\homelab-infra\ops\h-drive-nearline\pull-critical-backups.ps1`""
|
||||
|
||||
$Trigger = New-ScheduledTaskTrigger -Daily -At 05:30
|
||||
|
||||
$Settings = New-ScheduledTaskSettingsSet `
|
||||
-AllowStartIfOnBatteries `
|
||||
-DontStopIfGoingOnBatteries `
|
||||
-StartWhenAvailable `
|
||||
-ExecutionTimeLimit (New-TimeSpan -Hours 2)
|
||||
|
||||
Register-ScheduledTask `
|
||||
-TaskName "KalliLab H Drive Nearline Pull" `
|
||||
-Action $Action `
|
||||
-Trigger $Trigger `
|
||||
-Settings $Settings `
|
||||
-Description "Copies critical KalliLab restore artifacts from Unraid SMB backup share to H:/ nearline disk." `
|
||||
-RunLevel Limited
|
||||
```
|
||||
|
||||
Status pruefen:
|
||||
|
||||
```powershell
|
||||
Get-ScheduledTask -TaskName "KalliLab H Drive Nearline Pull" | Format-List TaskName, State
|
||||
Get-ScheduledTaskInfo -TaskName "KalliLab H Drive Nearline Pull" | Format-List LastRunTime, LastTaskResult, NextRunTime, NumberOfMissedRuns
|
||||
```
|
||||
|
||||
Manueller Trigger zum Testen:
|
||||
|
||||
```powershell
|
||||
Start-ScheduledTask -TaskName "KalliLab H Drive Nearline Pull"
|
||||
```
|
||||
|
||||
Verhalten:
|
||||
|
||||
- Laeuft als angemeldeter User (`RunLevel Limited`); wenn der PC abgemeldet ist, wartet der Task bis zur naechsten Anmeldung (`StartWhenAvailable`).
|
||||
- Akku-Modus blockiert nicht (`AllowStartIfOnBatteries`).
|
||||
- Maximale Laufzeit 2 h, danach wird der Task abgebrochen.
|
||||
|
||||
## Erfolgscheck
|
||||
|
||||
Nach einem echten Lauf muessen mindestens diese Artefakte unter `H:\kallilab-nearline-backups` liegen:
|
||||
|
||||
- `borg-dumps\latest\immich.dump`
|
||||
- `borg-dumps\latest\komodo-mongo.archive.gz`
|
||||
- `borg-dumps\latest\postgresql17-paperless.dump`
|
||||
- `borg-dumps\latest\postgresql17-mailarchiver.dump`
|
||||
- `borg-dumps\latest\nextcloud.dump`
|
||||
- `borg-dumps\latest\mealie.dump`
|
||||
- `borg-dumps\latest\gitea.sqlite.dump`
|
||||
- `borg-dumps\latest\vaultwarden.sqlite.dump`
|
||||
- `git-bundles\gitea\latest-report.md`
|
||||
- `git-bundles\gitea\micha\*.bundle`
|
||||
|
||||
Bewusst **nicht** im Nearline-Scope:
|
||||
|
||||
- `unraid-flash-config.tar.gz` (hostseitig 0600 root:root; Restore-Quelle bleibt das Hetzner-Borg-Repo, siehe `docs/RESTORE_MATRIX.md` Tier 1 Unraid OS Flash).
|
||||
|
||||
## Schutzregeln
|
||||
|
||||
- Kein CIFS-/SMB-Hard-Mount von `H:/` auf Unraid.
|
||||
- Kein Borg-Repo direkt auf `H:/` ueber SMB.
|
||||
- Kein `/MIR` und kein automatisches Loeschen auf `H:/`.
|
||||
- Flash-Backup wie Secret behandeln; `H:/` bleibt lokaler Operator-Datentraeger.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Immich Restore Test
|
||||
|
||||
Status: **erfolgreich live verifiziert** (2026-05-27)
|
||||
Audit-Bezug: `docs/AUDIT_2026-05-25.md` Finding **F-11**
|
||||
|
||||
## Zweck
|
||||
|
||||
Schliesst die Audit-Luecke aus F-11: Immich ist der groesste Datentopf (Familien-Fotos), und bisher gibt es im Gegensatz zu Vaultwarden, Gitea und Paperless **keinen** verifizierten Mini-Restore-Test. Dieses Dokument verlinkt die Repo-Artefakte und beschreibt den Ablauf aus Operator-Sicht.
|
||||
|
||||
## Repo-Artefakte
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `ops/restore-tests/immich-compose.test.yml` | isoliertes Test-Compose: pgvecto-rs Postgres + Redis + Immich-Server, ML weggelassen, `127.0.0.1:12283` |
|
||||
| `ops/restore-tests/immich-restore-test.sh` | Host-Bash-Skript fuer den Lauf, mit `--what-if` und `--keep-data` Flags |
|
||||
| `ops/restore-tests/immich-restore-test.ps1` | Plan-Scaffold fuer Windows-Operator-Sicht (kein Live-Run) |
|
||||
| `ops/restore-tests/immich-plan.md` | Fachlicher Plan: Quellen, Schutzregeln, Smoke-Test-Kriterien, bekannte Risiken |
|
||||
| `ops/restore-tests/immich-runbook.md` | Konkreter Operator-Ablauf, Fehlerfaelle, Schedule-Vorschlag |
|
||||
|
||||
## Was der Test abdeckt
|
||||
|
||||
- Extraktion von `local/borg-dumps/latest/immich.dump` aus dem aktuellsten Borg-Archiv
|
||||
- Import in eine isolierte `tensorchord/pgvecto-rs:pg14-v0.2.0` Postgres-Instanz mit demselben Digest wie Produktion
|
||||
- Start eines isolierten Immich-Server-Containers mit demselben Digest wie Produktion, **ohne** ML-Container und **ohne** Traefik
|
||||
- Smoke-Test: Login-Seite erreichbar, `asset`- und `"user"`-Tabelle lesbar
|
||||
- Markdown-Report unter `/mnt/user/backups/restore-reports/immich-YYYY-MM-DD.md`
|
||||
- Bereinigung von Test-Container und Restore-Lab-Daten nach Erfolg
|
||||
|
||||
## Was der Test bewusst NICHT abdeckt
|
||||
|
||||
- Wiederherstellung produktiver Foto-Dateien (`/mnt/user/photos/immich`, `/mnt/user/photos/family_archive`). Diese Pfade werden vom Test nicht angefasst und nicht in den Test-Container gemountet.
|
||||
- Machine-Learning-Container. Spart Image-Pull-Zeit und RAM; ML-Features sind im Smoke-Test irrelevant.
|
||||
- Echte Login-Flow per API. Smoke-Test prueft nur, dass Login-Seite ausgeliefert wird.
|
||||
- Asset-Rendering / Thumbnail-Generierung. Ohne Foto-Files erwartet.
|
||||
- Produktive Domain `immich.kaleschke.info`. Test laeuft ausschliesslich auf `127.0.0.1:12283`.
|
||||
|
||||
## Restore-Stufe
|
||||
|
||||
Der Test deckt **Stufe 4 (kritische Anwendungen)** aus `docs/DISASTER_RECOVERY.md` Phase 4 fuer Immich ab, allerdings nur DB-Ebene und UI-Smoke. Voll-Restore inklusive Foto-Dateien aus Borg ist eigener Folgeschritt; das Skript bereitet die Restore-Lab-Struktur dafuer vor.
|
||||
|
||||
## Erster Lauf und Preflight
|
||||
|
||||
| Pruefung | Verantwortlich | Wo |
|
||||
|---|---|---|
|
||||
| Dump-Groesse von `immich.dump` bestimmen | erledigt 2026-05-27 | 66M unter `/mnt/user/backups/borg/dumps/latest/immich.dump` |
|
||||
| Freier Platz unter `/mnt/user/backups/restore-lab/` | erledigt 2026-05-27 | ca. 3.7T frei auf `/mnt/user/backups` |
|
||||
| Borg-UI-Container laeuft | Operator | `docker ps | grep borg-ui` |
|
||||
| Trockenlauf mit `--what-if` | erledigt 2026-05-27 | Host-Clone auf `c5d231a`, `bash ops/restore-tests/run-restore-checks.sh immich --what-if` erfolgreich |
|
||||
| Erster echter Lauf | erledigt 2026-05-27 | Report `/mnt/user/backups/restore-reports/immich-2026-05-27.md`; Archiv `Tägliche-Sicherung-2026-05-27T04:30:06.778`; HTTP `200`; Assets `11977`; User `1` |
|
||||
|
||||
## Nach dem ersten erfolgreichen Lauf
|
||||
|
||||
1. Report unter `/mnt/user/backups/restore-reports/immich-2026-05-27.md` liegt vor und ist erfolgreich.
|
||||
2. `docs/RESTORE_MATRIX.md`, `ops/restore-tests/schedule.md`, `docs/AUDIT_2026-05-25_TODO.md` und `docs/MIGRATION_LOG.md` wurden nachgezogen.
|
||||
3. Quartalsweise Wiederholung einplanen; erster Live-Lauf bleibt bewusst manuell/Operator-kontrolliert, bis mehrere Laeufe stabil waren.
|
||||
|
||||
## Schutzregeln
|
||||
|
||||
- Skript greift ausschliesslich auf den Restore-Lab-Pfad und den Borg-Extract-Cache zu.
|
||||
- Produktive Pfade unter `/mnt/user/photos/*` und `/mnt/user/appdata/immich_postgres/` werden nicht angefasst.
|
||||
- Produktive Container `immich_server`, `immich_postgres`, `immich_redis`, `immich_machine_learning` werden nicht gestoppt, nicht beruehrt.
|
||||
- Borg-Passphrase wird aus `/mnt/user/appdata/secrets/borg_repo_passphrase.txt` gelesen und nicht in Reports, Logs oder Doku geschrieben.
|
||||
- Test-Container publishen nur auf `127.0.0.1:12283`, nicht auf LAN- oder Tailscale-Interface.
|
||||
- Keine Traefik-Labels, keine Public-URL fuer Testcontainer.
|
||||
|
||||
## Risiken (aus `ops/restore-tests/immich-plan.md`)
|
||||
|
||||
- Dump-Groesse und erster `pg_restore`-Lauf sind gemessen: `immich.dump` 66M, echter Smoke-Test erfolgreich am 2026-05-27.
|
||||
- pgvecto-rs Extension-Mismatch bei Image-Drift moeglich; Compose pinnt denselben Digest wie Produktion.
|
||||
- Immich v2 meldet pgvecto-rs als deprecated; VectorChord-Migration ist ein kuenftiger Immich-Upgrade-Punkt, nicht Teil dieses Restore-Tests.
|
||||
- Immich-Server-Migrations koennen Startup nach Restore verzoegern; Skript pollt 120 s.
|
||||
- Bei Schema-Drift (z. B. nach Major-Update) koennen einzelne DB-Queries abweichen; das Skript versucht Immich-v2-Singular-Tabellen und aeltere Plural-Fallbacks.
|
||||
|
||||
## Naechste Operator-Schritte
|
||||
|
||||
1. Quartalsweise Wiederholung nach `ops/restore-tests/schedule.md` einplanen.
|
||||
2. Bei zukuenftigem Immich-Major-Upgrade den Restore-Test unmittelbar danach einmal manuell ausfuehren.
|
||||
3. Voll-Restore inklusive Foto-Dateien bleibt ein eigener, deutlich groesserer DR-Drill.
|
||||
@@ -1,87 +0,0 @@
|
||||
# Master To-do - KalliLab CORE
|
||||
|
||||
Typ: Status/To-do · Stand: 2026-06-12 · Status: aktiv
|
||||
|
||||
Diese Liste ist die **einzige** Arbeitsliste fuer offene operative Punkte im
|
||||
Homelab. Detailablaeufe stehen in den verlinkten Runbooks; Entscheidungen mit
|
||||
Begruendung stehen in `docs/DECISIONS.md`; Belege fuer Erledigtes liegen in
|
||||
Host-Reports (`/mnt/user/backups/restore-reports/`) und in der Git-Historie.
|
||||
|
||||
## Status-Kategorien
|
||||
|
||||
- **Aktiv** - soll vorankommen; konkreter naechster Schritt steht.
|
||||
- **Operator-Entscheidung** - wartet auf eine bewusste Entscheidung (ja/nein/Option).
|
||||
- **Geparkt** - bewusst nicht jetzt, mit klarem Review-Trigger.
|
||||
- **Extern blockiert** - wartet auf ein externes Ereignis oder eine Abhaengigkeit.
|
||||
|
||||
---
|
||||
|
||||
## Aktiv
|
||||
|
||||
| Thema | Owner | Naechster konkreter Schritt | Quelle |
|
||||
|---|---|---|---|
|
||||
| Family-Onboarding erster Termin | Operator | Checkliste ist fertig (`docs/FAMILY_ONBOARDING.md` Abschnitt "Erster Onboarding-Termin"). Personen/Geraete festlegen, Reihenfolge Vaultwarden -> Immich -> Mealie pro Person abarbeiten | `docs/FAMILY_ONBOARDING.md` |
|
||||
| Restore-Test Unraid OS Flash (Stick-Boot) | Operator | Artefakt-Validierung 2026-06-05 erledigt (`ops/maintenance/check-unraid-flash-backup.sh`). **Verbleibt:** physischer Ersatzstick-Boot-Test, wenn ein Wegwerf-Stick bereitliegt | `ops/restore-tests/unraid-flash-runbook.md` |
|
||||
| Restore-Test Tailscale | Operator | State-Validierung + Reconnect nur auf Wegwerf-Host/VM, danach Geraet in Tailscale-Admin entfernen | `ops/restore-tests/tailscale-runbook.md` |
|
||||
| Authelia OIDC fuer Apps | Operator/Claude | Live: Grafana + Mealie (verifiziert), Paperless deployed (Login-Test offen). Immich + Nextcloud bewusst geparkt bis Family-Onboarding (siehe `docs/DECISIONS.md` 2026-06-06) | `docs/AUTHELIA_OIDC_PLAN.md` |
|
||||
| Glance-v2-Widgets: Tokens setzen | Operator | In Komodo Stack-ENV fuer `ops-glance` setzen: `GLANCE_KOMODO_API_KEY`/`_SECRET` (Komodo read-only API-Key), `GLANCE_GITEA_TOKEN` (read-only, scope `read:repository`), `GLANCE_PAPERLESS_TOKEN`, `GLANCE_MEALIE_TOKEN`; bis dahin zeigen die neuen Widgets Fehler/leer. Speedtest-Widget: falls weiter 0.0, API-Response pruefen | `ops/glance/config/` |
|
||||
| Home Assistant Foundation-Abnahme | Operator/Codex | Sofort: Owner-Onboarding abschliessen. Danach temporaere Authelia-Middleware von der HA-Route entfernen, Komodo-Stack-Eintrag + Webhook sauber anlegen/verifizieren, HA-MQTT-Smoke-Test und HA-native `backup.create` testen, Restore-Probe fuer HA/Mosquitto dokumentieren | `docs/runbooks/smart-home-bootstrap.md`, `docs/RESTORE_MATRIX.md` |
|
||||
| Audit-PDF aus `docs/` entfernen | Operator | `docs/KalliLab_CORE_Audit_2026-06-06.pdf` (untracked) extern ablegen (H:/ oder Documents-Share) und lokal loeschen; Binaerdateien gehoeren nicht ins GitOps-Repo | Doku-Regeln `docs/REPO_MAP.md` |
|
||||
|
||||
---
|
||||
|
||||
## Operator-Entscheidung
|
||||
|
||||
**Stand 2026-06-11: keine offenen Operator-Entscheidungen.**
|
||||
Getroffene Entscheidungen mit Begruendung und Review-Trigger: `docs/DECISIONS.md`.
|
||||
|
||||
---
|
||||
|
||||
## Geparkt
|
||||
|
||||
Bewusst nicht jetzt - Begruendungen in `docs/DECISIONS.md`, hier nur Thema und Trigger.
|
||||
|
||||
| Thema | Review-Trigger | Quelle |
|
||||
|---|---|---|
|
||||
| USV-Anschaffung | Q3-Review ab 2026-07-01, Hardware-Upgrade oder realer Stromausfall mit Datenfolge | `docs/DECISIONS.md` |
|
||||
| Cold-Backup-Rotation (zweites Off-site-Ziel) | Hetzner-Probleme, stark wachsender Datenwert oder geaenderte Praeferenz | `docs/DECISIONS.md` |
|
||||
| WAN-Ausfallschutz | haeufigere/laengere DSL-Ausfaelle oder kritischer Remote-Zugang | `docs/NETWORK_INVENTORY.md` |
|
||||
| Borg `append-only` auf Hetzner | robusterer Hetzner-Mechanismus oder geaendertes Ransomware-Risikoprofil | `docs/DECISIONS.md` |
|
||||
| CrowdSec vor Traefik | breitere Attack Surface als nur `443/tcp` | `docs/DECISIONS.md` |
|
||||
| Nextcloud 2FA (Operator-TOTP) | OIDC-/SSO-Block erreicht die App-Login-Ebene | `docs/DECISIONS.md` |
|
||||
| Hermes-Agent | Review-Deadline 2026-07-25; NAS-Stack bleibt deaktiviert | `docs/SERVICE_CATALOG.md` |
|
||||
| Tailnet-Konsole aufraeumen (Rest) | trivial, bei Gelegenheit: tote Node-Eintraege (`kallilab-core`, alter `baerchen`) in der Tailscale-Admin-Konsole entfernen; optional State-Pfad `/mnt/user/appdata/tailscale` nach `_archive/` | `docs/NETWORK_INVENTORY.md` |
|
||||
| Dedizierter SMB-User `veeam-baerchen` | nur wenn Unraid-User-/Share-Rechte bewusst angefasst werden | `ops/windows-reinstall/docs/windows-image-backup-baseline.md` |
|
||||
| Filebrowser-Mount-Scope | naechster Hardening-Sprint | `docs/SERVICE_CATALOG.md` |
|
||||
| Scrutiny Privileged-Ausnahme | nur mit klarer Begruendung aendern | `docs/SERVICE_CATALOG.md` |
|
||||
| Immich Redis named volume | passende Wartung am Immich-Stack | `docs/SERVICE_CATALOG.md` |
|
||||
| Storage-Wachstum (zweite NVMe, zweite Array-Disk, ZFS/BTRFS) | Trigger aus Capacity-Doku | `docs/STORAGE_LAYOUT.md`, `docs/CAPACITY_AND_LIFECYCLE.md` |
|
||||
| Wiederkehrende Restore-Drills | laufend nach Kadenz, inkl. quartalsweisem Frische-Negativtest (`run-restore-checks.sh freshness-negative`) | `docs/RESTORE_MATRIX.md`, `ops/restore-tests/schedule.md` |
|
||||
| Doku-Quartals-Gaertnern (~15 min) | quartalsweise, erster Lauf mit Q3-Review ab 2026-07-01: Datiertes archivieren, Done-/Review-Logs kuerzen, tote Links pruefen | `docs/REPO_MAP.md` Doku-Regeln |
|
||||
|
||||
---
|
||||
|
||||
## Extern blockiert
|
||||
|
||||
| Thema | Blockiert durch | Naechster Schritt sobald entblockt | Quelle |
|
||||
|---|---|---|---|
|
||||
| End-to-end-DR-Drill | Keine zweite Wegwerf-Hardware verfuegbar | Komplett-Bootstrap Phase 1-5 fahren | `docs/DISASTER_RECOVERY.md` |
|
||||
|
||||
---
|
||||
|
||||
## Zuletzt erledigt (Kurzlog, max. 5 Eintraege)
|
||||
|
||||
- **2026-06-12** Komodo-Stack-Hygiene-Check aktiv: `services/posture-check/komodo-stack-hygiene.sh` + Unraid User Script `komodo-stack-hygiene-weekly` (Sonntag 05:00). Faengt die `immich_new`-Klasse (Stack ohne Repo, `project_missing`, Compose ohne Stack, Hash-Drift). Erster Lauf: 6 Warnings, 0 Critical.
|
||||
- **2026-06-12** Immich Komodo-Stack bereinigt: `immich_new` auf `immich` korrigiert, Gitea-Account `Micha` gesetzt, per Komodo aus `apps/immich/docker-compose.yml` neu deployed. Verifiziert: `deployed_hash == latest_hash`, `immich_new_count=0`, alle vier Container healthy, HTTP 200, DB-Smoke `11983` Assets, Drift-Alert resolved.
|
||||
- **2026-06-11** Host-DNS-Fallback aktiv: `eth0` DNS2 = `192.168.178.1` (FRITZ!Box) zusaetzlich zu AdGuard. AdGuard-SPOF fuer Image-Pulls entschaerft; der dokumentierte Bulk-Deploy-Vorfall kann strukturell nicht wiederkommen.
|
||||
- **2026-06-11** Hetzner Storage Box: automatische Snapshots aktiv (taeglich 05:30 UTC, 7 Tage Retention). Schliesst das Ransomware-/Fehlbedienungs-Risiko gegen das Off-site-Backup. Siehe `docs/DECISIONS.md`.
|
||||
- **2026-06-11** Immich Image-Tags von `release` auf `v2.7.5` gepinnt (Server + ML, Digests unveraendert): Renovate-PRs zeigen ab jetzt sichtbare Versionsspruenge statt stiller Digest-Bumps.
|
||||
|
||||
---
|
||||
|
||||
## Pflege-Regel
|
||||
|
||||
- Neue operative To-dos zuerst hier eintragen, immer mit Status-Kategorie.
|
||||
- Erledigt: Beleg liegt im Host-Report bzw. Commit; hier nur ein Kurzlog-Eintrag (max. 3 Zeilen), aelteste Eintraege fliegen raus, sobald mehr als 5.
|
||||
- Entscheidungen (auch "bewusst nein") gehoeren mit Begruendung nach `docs/DECISIONS.md`, hier nur Thema + Trigger.
|
||||
- Keine vagen "pruefen"-Eintraege ohne Kommando oder Entscheidung.
|
||||
@@ -0,0 +1,572 @@
|
||||
# Migration Log - Homelab GitOps
|
||||
|
||||
Dieses Dokument ist nur noch ein historischer Verlauf. Der aktuelle operative Ablauf steht in `docs/WORKFLOW.md`, das Zielbild in `HOMELAB_ARCHITECTURE_MASTER_V2.md`.
|
||||
|
||||
## Aktueller Endstand
|
||||
|
||||
- Gitea Online ist der verbindliche Sollzustand.
|
||||
- Komodo ist der einzige produktive Stack-Manager.
|
||||
- Portainer CE ist entfernt.
|
||||
- Firefly, Firefly-Fints und Semaphore sind entfernt.
|
||||
- `monitoring/` ist der einzige aktive Observability-Stack; alte Repo-Pfade `ops/grafana-influxdb` und `ops/loki` sind entfernt.
|
||||
- Borg UI ist produktiv, Dump-Automatisierung laeuft host-seitig und ein Restore-Smoke-Test wurde erfolgreich durchgefuehrt.
|
||||
- GitHub Desktop ist der bevorzugte lokale Workflow fuer `Fetch`, `Pull`, `Commit` und `Push`.
|
||||
- Mutable Image-Tags sind auf die aktuell laufenden Digests eingefroren.
|
||||
|
||||
---
|
||||
|
||||
## Historische Meilensteine
|
||||
|
||||
### 2026-05-29 - Stack-Hygiene Sprint: Healthchecks, Monitoring-Digests, Komodo-Bootstrap-Skript, Renovate-Vorbereitung
|
||||
|
||||
Vier Audit-Punkte am Stueck abgearbeitet. Pro Block: Live-Verifikation am Host, Doku im Repo.
|
||||
|
||||
**F-15 Tier-1 Healthchecks**
|
||||
|
||||
- 6 Tier-1-Stacks bekommen Healthchecks: postgresql17 (`pg_isready`), Redis (`redis-cli ping` mit Auth aus dem mount), Vaultwarden (`curl /alive`), Gitea (`wget /api/healthz`), Traefik (`traefik healthcheck --ping`, vorher `--ping=true` in CLI aktiviert), Authelia (`wget /api/health` - Authelia v4.39 hat `helper health-check` entfernt, daher direkter Endpoint).
|
||||
- Erste Iteration in Vaultwarden + Authelia schlug fehl: Vaultwarden hat kein `wget`, Authelia kennt das `helper`-Subcommand nicht mehr. Probe per `docker exec` zeigte: Vaultwarden hat `curl`, Authelia hat `wget`. Compose entsprechend nachgezogen, zweiter Lauf gruen.
|
||||
- Komodo-Stack-Workspaces fuer `postgresql17` (124 commits behind) und `gitea` (52 commits behind) wurden Komodo-seitig nicht automatisch gepullt. Manuell ueber `git pull --ff-only` plus `cp` der aktuellen Compose-Datei aus dem Host-Repo-Clone in den Stack-Workspace synchronisiert, dann `docker compose up -d`. Gitea-Workspace hatte zusaetzlich untracked Doku-Files; nur die im aktuellen Master tracked-en Files entfernt, nicht via `git clean -fd`. Workspace-Drift selbst ist nicht heute Auftrag, aber als Folge-Befund notiert.
|
||||
- Endstand Live: alle 6 Healthchecks `healthy`.
|
||||
|
||||
**F-07 Monitoring-Stack Digest-Pinning**
|
||||
|
||||
- 9 Container in `monitoring/docker-compose.yml` per Tag@sha256 gepinnt (prometheus, alertmanager, alertmanager-ntfy-bridge, blackbox-exporter, loki, promtail, grafana, node-exporter, cadvisor; plus zweiter python:3.13-alpine im Bootstrap-Dashboard-Importer). InfluxDB war bereits gepinnt.
|
||||
- Digests aus den laufenden Containern per `docker inspect ... .Config.Image` + `docker image inspect ... .RepoDigests` ausgelesen, damit die Pins exakt dem Live-Stand entsprechen.
|
||||
- Kein Recreate ausgeloest, weil die Images identisch sind; nur die Compose-Datei ist jetzt reproduzierbar wie die Tier-1-Stateful-Stacks.
|
||||
|
||||
**F-09 Rest - Komodo-Bootstrap-Trockenlauf-Skript**
|
||||
|
||||
- `ops/restore-tests/komodo-bootstrap-{compose.test.yml,test.sh,plan.md,runbook.md}` analog zum Immich-Restore-Test-Muster angelegt.
|
||||
- Test-Compose nutzt dieselben Image-Digests wie Produktion (mongo:7.0.32, komodo-core:2, komodo-periphery:2), isoliert unter Compose-Project `restoretest-komodo`, Test-Port nur `127.0.0.1:19120`, **Test-Periphery ohne docker.sock-Mount und ohne `/mnt/user/services`-Mount** - kann produktive Container nicht managen.
|
||||
- Wegwerf-Secrets sind im Compose hardcodiert, produktive `KOMODO_*`-Werte werden nicht beruehrt.
|
||||
- Smoke-Test-Kriterien: docker compose config valid, Mongo healthy, Mongo Auth-Ping ok, Core HTTP 200/302/303/401, Periphery container `running`.
|
||||
- Erster Lauf bleibt manueller Operator-Schritt.
|
||||
|
||||
**F-12 Renovate-Bot (vorbereitet)**
|
||||
|
||||
- `renovate.json` im Repo-Root mit Homelab-tauglichen Group-Rules: Major-Updates getrennt, Minor/Patch/Digest fuer Docker-Compose und Dockerfile gruppiert, Tier-1-Datenhalter (Postgres, Mongo, Redis, pgvecto-rs) einzeln ohne Group, Komodo-Major-Updates explizit deaktiviert.
|
||||
- `ops/renovate/run-renovate.sh` als One-Shot-Container-Wrapper: liest Gitea-PAT aus Host-Secret-Datei, startet `renovate/renovate:41` einmalig, schreibt Log unter `/mnt/user/services/renovate/logs/`.
|
||||
- `docs/RENOVATE.md` mit kompletter Operator-Setup-Anleitung (5 Schritte): Gitea-Service-Account `renovate`, Access-Token, Token-Datei, Erstlauf, User-Script `renovate-six-hourly` (`20 */6 * * *`).
|
||||
- Bewusst KEIN Auto-Merge: jede PR braucht Operator-Sichtpruefung.
|
||||
- Setup-Schritte (Gitea-User, PAT, Token-Datei, User-Script-Aktivierung) bleiben Operator-Aufgabe; Repo-seitig alles vorbereitet.
|
||||
|
||||
### 2026-05-29 - Borg-Source `/local/appdata/homepage` verspaetet entfernt + Removal-Checkliste in WORKFLOW
|
||||
|
||||
- Befund aus den ersten Tagen scharfer Alert-Pipeline: `HomelabBorgLastJobCompletedWithWarnings` firing fuer die letzten vier Borg-Laeufe (26.05.-29.05.), jeweils Exit-Code 107.
|
||||
- Ursache im Borg-UI-Logfile `backup_job_39_*.log`: `"/local/appdata/homepage: stat: [Errno 2] No such file or directory"`. Borg-UI-Source-Liste enthielt seit der Homepage-Entfernung am 25.05. weiterhin den Eintrag `/local/appdata/homepage`; der Appdata-Pfad war aber bereits nach `_archive/homepage-removed-2026-05-25/` verschoben.
|
||||
- Operator hat den Eintrag in der Borg-UI manuell entfernt; Source-Liste jetzt 23 statt 24 Eintraege, `homepage` nicht mehr drin. Naechster Borg-Lauf 2026-05-30 04:30 sollte wieder `completed` ohne Warning sein.
|
||||
- Backups waren nicht gefaehrdet: trotz Exit-Code 107 wurden alle anderen 23 Quellen sauber archiviert (Stats Job 39: 100.895 Dateien, 26.72 GB Original, 317 MB deduplicated).
|
||||
- Erkenntnis: bei Stack-Removal wurde die Borg-Source-Liste damals nicht mit-aufgeraeumt. **`docs/WORKFLOW.md`** um neuen Abschnitt "Service-Removal-Checkliste" erweitert, der die Borg-UI-Source-Bereinigung explizit als Pflichtschritt 8 nennt (zusammen mit allen anderen Schritten wie Komodo-Destroy, Gitea-Webhook, Authelia-ACL, Blackbox-Target, Doku).
|
||||
- Positiv-Befund: die ntfy-Push-Pipeline (Cron `*/5` Textfile-Export -> node-exporter -> Prometheus -> Alertmanager -> ntfy-Bridge), die am 2026-05-27 scharfgeschaltet wurde, hat den Drift binnen 24 h sichtbar gemacht. Das ist der intendierte Mechanismus.
|
||||
|
||||
### 2026-05-28 - H:/-Pull als Windows Scheduled Task aktiviert
|
||||
|
||||
- Task `KalliLab H Drive Nearline Pull` registriert auf dem Operator-Windows-PC: taeglich 05:30 (nach dem Borg-Dump-Fenster um ca. 04:00), `RunLevel Limited`, `AllowStartIfOnBatteries`, `DontStopIfGoingOnBatteries`, `StartWhenAvailable`, `ExecutionTimeLimit 2 h`. Naechster Lauf 2026-05-29 05:30.
|
||||
- Repo-Doku `docs/H_DRIVE_NEARLINE_PULL.md` Status auf "produktiv" gesetzt, Register-Snippet auf den tatsaechlich ausgefuehrten Befehl korrigiert (PowerShell-Enum `LeastPrivilege` -> `Limited`; alter Snippet haette beim ersten Aufruf einen Parameter-Binding-Fehler geworfen).
|
||||
- Verifikation am Windows-PC: `Get-ScheduledTask` zeigt State `Ready`, Trigger-Start 2026-05-28T05:30, RunLevel `Limited`.
|
||||
- Kein Eingriff am Host noetig; SMB-Quelle und H:/-Ziel waren bereits vorbereitet.
|
||||
|
||||
### 2026-05-28 - Zweites Off-site bewusst nicht umgesetzt
|
||||
|
||||
- Operator-Bewertung: 3-2-1-Regel ist mit aktueller Topologie erfuellt (Live + lokales Borg-Repo + Hetzner-Borg + H:/-Nearline = 4 Kopien / 3 Medien / 1 Off-site).
|
||||
- Ein zweites Off-site wuerde **ausschliesslich** das Szenario "Hetzner-Account verloren" zusaetzlich abdecken. Eintrittswahrscheinlichkeit niedrig (etablierter deutscher Anbieter, dokumentierter Zahlungsweg). Aufwand und Kosten unverhaeltnismaessig fuer Familien-Homelab.
|
||||
- Beschluss in `docs/OFFSITE_BACKUP_OPTIONS.md` mit Review-Triggern dokumentiert; F-03 in `docs/AUDIT_2026-05-25_TODO.md` von "offen" auf "erledigt (bewusst nicht umgesetzt)".
|
||||
- Stattdessen drei Folge-TODOs zur Haertung der bestehenden Topologie:
|
||||
- Hetzner-Account-Hygiene: starkes Passwort + Backup-Zahlungsweg + Login-Benachrichtigungen. **Bewusst keine 2FA** (Operator-Entscheidung analog USV-Risiko-Akzeptanz).
|
||||
- Borg `--append-only` auf Hetzner pruefen. Befund: Repo `appdata-critical` laeuft aktuell im Mode `full`, `custom_flags` leer. Setup waere server-seitig in Hetzner-`authorized_keys`.
|
||||
- H:/-Pull als Windows Scheduled Task aktivieren (Skript und Doku ready, Erstlauf 2026-05-27 erfolgreich, Task selbst noch nicht angelegt).
|
||||
- Bewusst NICHT angefasst: laufende Backup-Pipeline (kein Test-Restore, kein Modus-Wechsel ohne Folge-Sprint).
|
||||
|
||||
### 2026-05-28 - paperless-gpt und BentoPDF bewusst behalten
|
||||
|
||||
- Befund: Beide Container laufen Up 3 days, aber **0 Traefik-Zugriffe in den letzten 7 Tagen** und kein User-LLM-Event in den paperless-gpt-Logs. BentoPDF-Logs zeigen ausschliesslich Docker-Healthchecks.
|
||||
- Resource-Footprint vernachlaessigbar: `paperless-gpt` 34 MB RAM, `bentopdf` 4 MB RAM, beide 0 % CPU.
|
||||
- Operator-Entscheidung 2026-05-28 (gegen die Nicht-Nutzung): **beide behalten**.
|
||||
- `paperless-gpt`: bleibt aktiv bis Paperless-NGX 3.0 verfuegbar ist. Paperless 3.0 wird native KI-Features mitbringen; danach neu entscheiden, ob `paperless-gpt` noch noetig ist oder abgeloest werden kann.
|
||||
- `bentopdf`: bleibt aktiv als situatives PDF-Werkzeug; Footprint zu klein, um eine harte Entfernung zu rechtfertigen.
|
||||
- Doku-Anker in `docs/SERVICE_CATALOG.md` ergaenzt, damit die Frage in 6 Monaten nicht erneut als "warum laeuft das?" auftaucht.
|
||||
|
||||
### 2026-05-28 - Plex Server Reclaim und Remote Access deaktiviert
|
||||
|
||||
- Befund beim Versuch, Remote Access in der Plex-UI zu deaktivieren: Plex-Server war seit 18.05.2026 13:18 nicht mehr mit einem Plex.tv-Account geclaimt. `Preferences.xml` 391 Bytes, ohne `PlexOnlineMail`/`PlexOnlineUsername`/`PlexOnlineToken`. Login als `Xeridos` lieferte "Keine Berechtigung" auf den lokalen Server. Zusaetzlich waren die `library_sections` leer (Backups vom 19./22./28.05. ebenfalls ~370 KB statt MBs); die Bibliotheks-Konfiguration war seit dem 18.05. weg. Filmdateien unter `/mnt/user/media/*` blieben unangetastet (833 Verzeichnisse, ~1.7 TB).
|
||||
- Reclaim als `Xeridos` durchgefuehrt: Operator-Token via `plex.tv/claim` erzeugt, am Host als Shell-Inline-ENV beim `docker compose up -d --force-recreate plex` mitgegeben. Token wurde **nicht** in `.env`, **nicht** in Compose, **nicht** in Komodo-Stack-ENV geschrieben. Nach Erfolg sauberer zweiter Recreate ohne Token, damit `docker inspect`-Snapshot keinen Token mehr enthaelt. Bash-History defensiv geleert.
|
||||
- Endstand laut `Preferences.xml`: `PlexOnlineUsername="Xeridos"`, `PlexOnlineMail="michideheld@gmx.de"`, `PlexOnlineHome="1"`, `PublishServerOnPlexOnlineKey="0"` (Remote Access aus).
|
||||
- Operator hat im Anschluss die Bibliotheken neu angelegt (`/data/movies`, `/data/Heimatfilme`) und Remote Access in der Plex-UI auf "deaktiviert" gesetzt; Metadata-Cache wuchs in den ersten 18 Minuten auf 630 MB.
|
||||
- Plex bleibt damit strikt LAN/Tailscale-only, konsistent zur FRITZ!Box-Bereinigung vom selben Tag. Smart-TVs (Schlaf-/Wohnzimmer) finden den Server ueber WLAN-LAN per mDNS/Plex-GDM unveraendert.
|
||||
- `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 13 enthaelt die ausfuehrliche Recovery-Geschichte. `docs/SERVICE_CATALOG.md` und Sektion 7.4 auf "LAN/Tailscale-only, Remote Access aus" praezisiert.
|
||||
|
||||
### 2026-05-28 - FRITZ!Box-Portfreigaben bereinigt
|
||||
|
||||
- WAN-Soll auf eine einzige Freigabe reduziert: `443/tcp -> 192.168.178.58:443` (Traefik HTTPS).
|
||||
- `80/tcp` aus FRITZ!Box-UI entfernt. Validierung: Mobilfunk-Test ergibt Timeout auf `http://vault.kaleschke.info`, `https://vault.kaleschke.info` weiter erreichbar; lokal greift Traefik-Redirect 80->443 nach wie vor. Cloudflare-DNS-Challenge braucht kein Port 80.
|
||||
- `222/tcp` bleibt bewusst nicht eingerichtet. Begruendung: Tailscale ist Operator-Pfad, GitHub-Push-Mirror `michaelkaleschke-spec/homelab-infra` deckt Repo-Bootstrap-Pfad ab, Gitea-Bundles unter `/mnt/user/backups/git-bundles/gitea` decken Offline-Restore ab. `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 10 entsprechend mit "Tailscale-only, bewusst nicht WAN-freigegeben" praezisiert.
|
||||
- UPnP-Selbstfreigabe-Recht fuer `PC-192-168-178-71` (Hostname `VONETS.COM`, MAC `00:17:13:2F:61:96`) deaktiviert. Identifiziert als VONETS-WiFi-Bridge, vermutlich Bridge-Anbindung zum SolarEdge-Wechselrichter. SolarEdge-Cloud-Sync ist outbound und benoetigt keine UPnP. Aktuell waren 0 Selbstfreigaben aktiv; die Aenderung ist praeventiv gegen kuenftige Anforderungen.
|
||||
- `docs/NETWORK_INVENTORY.md`, `docs/FRITZBOX_PORT_CORRECTION_PLAN.md` und `docs/AUDIT_2026-05-25_TODO.md` Sprint 4 entsprechend nachgezogen.
|
||||
- Bewusst NICHT angefasst: FRITZ!OS 8.21 Update (Service-Fenster), IPv6-Exposure (separater Folgeschritt), WAN-Ausfallschutz (bewusst aus).
|
||||
|
||||
### 2026-05-27 - Monitoring-Alerts live, Gitea-Bundle-Cron live, H:/-Pull live
|
||||
|
||||
Drei Audit-TODOs gleichzeitig auf "erledigt" gezogen; alle Aenderungen mit Host-Smoke verifiziert.
|
||||
|
||||
**Monitoring-Alerts (Borg-Stale / Cert-Expiry / Container-Down)**
|
||||
|
||||
- Auf dem Host neuer User-Script `export-prometheus-textfile-5min` mit Cron `*/5 * * * *` angelegt. Schreibt `/mnt/user/services/posture-check/textfile/homelab.prom`.
|
||||
- Repo: `services/posture-check/export-prometheus-textfile.sh` setzt jetzt vor dem `mv` per `chmod 644`, damit node-exporter (`nobody:65534`) lesen kann. Vorher `0600 root:root` → `node_textfile_scrape_error 1`.
|
||||
- `monitoring-prometheus` wurde einzeln per `docker restart` neu gestartet, um den `stale file handle` auf der gebundenen `alerts.yml` zu loesen. Kein Stack-Down. `promtool check rules` SUCCESS 14 rules, `lastConfigTime 2026-05-27T18:33:06Z`. Aktive Alerts: 1 firing (`HomelabTraefik5xx` aus dem 2026-05-20-Befund), 1 pending (`HomelabBorgLastJobCompletedWithWarnings` durch `completed_with_warnings`-Status des letzten Borg-Laufs).
|
||||
- Pipeline end-to-end: Textfile-Skript ⇒ node-exporter Textfile-Collector ⇒ Prometheus ⇒ alerts.yml-Regeln.
|
||||
|
||||
**Gitea-Bundle-Schedule**
|
||||
|
||||
- User-Script `gitea-bundle-mirror-6h` mit Cron `10 */6 * * *` (00:10/06:10/12:10/18:10).
|
||||
- Repo: `ops/borg-ui/scripts/gitea-bundle-mirror.sh` schreibt Bundles und Sidecars jetzt `chmod 644` statt `600`. Begruendung: Bundle-Inhalt ist Git-Historie ohne Secrets (durch `.gitignore` abgedeckt), nicht sensibler als die uebrigen 0644-Dumps. Damit funktioniert der Nearline-Pull ueber SMB.
|
||||
- Existierende Bundles wurden manuell auf 0644 angehoben. Erster Cron-Lauf 2026-05-27 18:41 UTC erfolgreich: 4 Bundles, Checksums OK.
|
||||
|
||||
**H:/ Nearline-Pull**
|
||||
|
||||
- Erster scharfer Lauf 2026-05-27 20:25 zeigte vier Permission-Befunde: `unraid-flash-config.*` (4 Files, by-design 0600), `filebrowser.bolt.dump` (0640, Source erbt), und alle 10 Gitea-Bundle-Files (0600).
|
||||
- Repo: `ops/h-drive-nearline/pull-critical-backups.ps1` excluded jetzt die `unraid-flash-config.*`-Familie ueber `/XF` (Restore-Quelle bleibt Hetzner-Borg). `ops/borg-ui/scripts/pre-backup-dumps.sh` setzt alle Dumps via `atomic_write` per Default auf 0644, Flash-Config-Familie explizit mit `atomic_write target tmp 600`.
|
||||
- Existierende Files am Host nachtraeglich auf 0644 angehoben.
|
||||
- Zweiter Lauf 2026-05-27 20:45: beide Robocopy-Jobs Exit 1, **19 Borg-Dumps + 10 Gitea-Bundle-Files** unter `H:\kallilab-nearline-backups`. Report-Tabellen-Quirk in PowerShell durch `& robocopy @args | Out-Null` behoben (Live-Output landete vorher in `$results`).
|
||||
- `docs/H_DRIVE_NEARLINE_PULL.md` mit Erstlauf-Befund, gefixter Erwartungs-Liste und expliziter Out-of-Scope-Anmerkung fuer Flash-Config aktualisiert.
|
||||
- Windows Scheduled Task taeglich 05:30 bleibt **bewusst** offen bis zur Operator-Bestaetigung.
|
||||
|
||||
**Was bewusst NICHT angefasst wurde**
|
||||
|
||||
- Authelia/OIDC/CrowdSec/Nextcloud-Haertung (geparkt).
|
||||
- Hermes (Review 2026-07-25).
|
||||
- USV (Risiko bewusst akzeptiert).
|
||||
- FRITZ!Box-/Plex-/UI-Punkte (Punkt 5 fuer morgen frueh).
|
||||
- `unraid-flash-config.tar.gz` bleibt bewusst 0600 und ausserhalb des Nearline-Scopes.
|
||||
|
||||
### 2026-05-27 - Vorbereitungsdokumente FRITZ!Box-Korrektur und Off-site-Optionen
|
||||
|
||||
- Reine Doku-Aenderung; kein Router-, Provider- oder Host-Eingriff.
|
||||
- `docs/FRITZBOX_PORT_CORRECTION_PLAN.md` neu angelegt: Korrektur-Plan fuer drei Punkte (`80/tcp` entfernen, `222/tcp` nicht ergaenzen solange Tailscale stabil, UPnP-Selbstfreigabe `PC-192-168-178-71` deaktivieren). Operator-Go ausstehend; jede UI-Aenderung wird gesondert dokumentiert.
|
||||
- `docs/OFFSITE_BACKUP_OPTIONS.md` neu angelegt: Entscheidungsvorlage fuer zweites Off-site-Ziel mit drei Optionen (rsync.net Borg-Plan, BorgBase EU2, rotierende Cold-Platte). Bewertung gegen Provider-Trennung, Standort, Preis und Konto-Risiko; Empfehlung rsync.net oder Cold-Platte; BorgBase EU2 explizit nicht empfohlen wegen gleichem Anbieter. Kein Provider gebucht, keine Kosten ausgeloest.
|
||||
- `docs/REPO_MAP.md` um beide neuen Dokumente ergaenzt.
|
||||
- `docs/AUDIT_2026-05-25_TODO.md` Sprint 4 (FRITZ!Box) und Sprint 7 (Off-site) mit Verweis auf die neuen Vorbereitungsdokumente nachgezogen.
|
||||
|
||||
### 2026-05-27 - Doku-Sprint Bootstrap / Family-View / Onboarding / Drill-Routine
|
||||
|
||||
- Reine Doku-Aenderung; kein Compose-, Secret-, Host- oder Router-Eingriff.
|
||||
- `docs/SERVICES_RECOVERY.md` "Komodo Bootstrap" auf linearen Stufenpfad A-F ausgebaut: Recovery-Anker bleibt `ops/komodo/docker-compose.yml`, Self-Stack ist explizit kein Anker, Secret-Restore-Reihenfolge verweist auf `docs/SECRETS_MAP.md` Stack-ENV-only-Sektion, Validierungs-Kommandos ergaenzt. Trockenlauf-Idee als Folgeaufgabe eingetragen, kein Repo-Skript dafuer.
|
||||
- `docs/DISASTER_RECOVERY.md` Phase 4 Stufe 3 verweist explizit auf den Bootstrap-Pfad in `docs/SERVICES_RECOVERY.md` und auf die Stack-ENV-only-Sektion in `docs/SECRETS_MAP.md`.
|
||||
- `docs/FAMILY_VIEW_DASHBOARD.md` neu angelegt: Spezifikation fuer `homelab-family-view`-Dashboard, 8 Panels (Endpoints up, Borg-Frische, Cert-Tage, Kritische Container, Disk-Fuellung, Endpoint-Tabelle, Cert-Tabelle, Container-Tabelle), PromQL-Queries, Thresholds, Build-Reihenfolge. Bewusst noch **kein** `monitoring/grafana/dashboards/family-view.json` angelegt, weil Borg-Stale-/Cert-Expiry-/Container-Down-Metriken laut Sprint 3 noch "in Arbeit" sind.
|
||||
- `docs/FAMILY_ONBOARDING.md` final redigiert: Status auf "Final-Stand vor Wochenend-Einladung", 2FA-Beschreibung auf App-eigene 2FA praezisiert (kein SSO-Versprechen, weil Authelia-OIDC weiter geparkt ist), neuer "Bewusst nicht versprochen"-Block (kein Einheits-Login, kein 24/7-SLA, kein Hotline-Support, keine Datenweitergabe).
|
||||
- `docs/RESTORE_DRILL_ROUTINE.md` neu angelegt: Drei-Stufen-Modell (Freshness woechentlich / Mini-Restore monatlich-bimonatlich / DR-Sanity quartalsweise), Quartals-Kadenz Q1-Q4 mit Dienst-Rotation, bestaetigte Mini-Restores (Vaultwarden, Gitea, Paperless 2026-05-07; Immich 2026-05-27), 10-Punkte-Sanity-Check, Abbruch-Regel mit Verweis auf `docs/GITOPS_DRIFT_RUNBOOK.md`. Kein Host-Schedule angelegt, nur Doku.
|
||||
- `ops/restore-tests/schedule.md` verweist jetzt auf `docs/RESTORE_DRILL_ROUTINE.md` als Quelle der Quartals-Belegung.
|
||||
- `docs/REPO_MAP.md` um `docs/FAMILY_VIEW_DASHBOARD.md`, `docs/RESTORE_DRILL_ROUTINE.md` und `docs/IMMICH_RESTORE_TEST.md` ergaenzt.
|
||||
- `docs/AUDIT_2026-05-25_TODO.md` aktualisiert: Sprint 2 "Komodo-Bootstrap-Pfad beschreiben", Sprint 3 "Family-View Dashboard definieren", Sprint 4 "Familien-Onboarding schreiben" und Sprint 7 "Restore-Lab-Drill quartalsweise dokumentieren" jeweils auf "erledigt".
|
||||
- Geparkte Punkte bleiben unveraendert: Authelia-2FA/OIDC/CrowdSec, Nextcloud-Haertung, Hermes (Review 2026-07-25), USV-Anschaffung.
|
||||
|
||||
### 2026-05-27 - Immich Restore-Smoke-Test praktisch verifiziert (F-11)
|
||||
|
||||
- Erster echter Immich-Restore-Smoke-Test gegen das produktive Borg-Archiv erfolgreich: `Tägliche-Sicherung-2026-05-27T04:30:06.778`, Report `/mnt/user/backups/restore-reports/immich-2026-05-27.md`.
|
||||
- Validiert wurden Borg-Extract von `local/borg-dumps/latest/immich.dump`, Import in isolierten `tensorchord/pgvecto-rs:pg14-v0.2.0` Test-Postgres, Start des Immich-Servers ohne ML und ohne Traefik, HTTP `200` auf `127.0.0.1:12283`, Login-Marker, `11977` Assets und `1` User im Test-DB-Check.
|
||||
- Produktive Container und produktive Foto-Pfade wurden nicht angefasst; Testdaten und Testcontainer wurden nach Erfolg bereinigt.
|
||||
- Im Lauf wurden Restore-Test-Haertungen umgesetzt: Borg-`known_hosts` aus `/data/known_hosts` wird fuer SSH-Trust genutzt, `completed_with_warnings`-Archive gelten als verwendbare Restore-Quelle, Postgres-Startfenster werden retry-faehig behandelt, Immich-v2-Upload-Marker werden im leeren Test-Mount erzeugt und Smoke-Checks schlagen bei HTTP-/Marker-Fehlern hart fehl.
|
||||
- `docs/IMMICH_RESTORE_TEST.md`, `docs/RESTORE_MATRIX.md`, `ops/restore-tests/schedule.md` und `docs/AUDIT_2026-05-25_TODO.md` nachgezogen; F-11 ist damit abgeschlossen. Voll-Restore inklusive Foto-Dateien bleibt ein separater DR-Drill.
|
||||
|
||||
### 2026-05-27 - FRITZ!Box-Portfreigaben gegen Repo-Soll abgeglichen
|
||||
|
||||
- FRITZ!Box-UI `Internet -> Freigaben -> Kallilabcore` geprueft: aktiv sind `HTTP-Server` TCP `80/tcp` und `HTTPS-Server` TCP `443/tcp` auf `192.168.178.58`.
|
||||
- Repo-Soll aus `docs/NETWORK_INVENTORY.md` ist nur `443/tcp` plus optional gewolltes Gitea-SSH `222/tcp`. Der aktuelle Zustand weicht ab: `80/tcp` ist offen, `222/tcp` fehlt.
|
||||
- Kallilabcore ist nicht als Exposed Host markiert und erlaubt keine selbststaendige Portfreigabe. `PC-192-168-178-71` erlaubt selbststaendige Portfreigabe, hat aber `0 aktiv`.
|
||||
- Keine FRITZ!Box-Aenderung vorgenommen. Router-Korrektur bleibt ein produktiver Operator-Schritt nach ausdruecklicher Freigabe.
|
||||
|
||||
### 2026-05-26 - Immich Restore-Smoke-Test vorbereitet (F-11)
|
||||
|
||||
- `docs/IMMICH_RESTORE_TEST.md` und `ops/restore-tests/immich-plan.md`/`immich-runbook.md` beschreiben den geplanten Immich-Mini-Restore: `immich.dump` aus Borg, isolierter pgvecto-rs-Test-Postgres, Test-Redis, Immich-Server ohne ML, lokaler Port `127.0.0.1:12283`, keine produktiven Foto-Mounts.
|
||||
- `ops/restore-tests/immich-restore-test.sh`, `immich-restore-test.ps1` und `immich-compose.test.yml` wurden vorbereitet; der Dispatcher kennt `immich --what-if`.
|
||||
- Lokal verifiziert: Bash-Syntax, `run-restore-checks.sh immich --what-if`, PowerShell-Dispatcher `-Mode immich -WhatIf`, Docker-Compose-Render und Policy-Check. Kein echter Host-Restore, kein Borg-Extract, kein Produktiv-Container-Eingriff.
|
||||
- Host-Preflight 2026-05-27: Host-Clone per Fast-forward auf `c5d231a`, `immich.dump` 66M, `/mnt/user/backups` ca. 3.7T frei, `run-restore-checks.sh immich --what-if` erfolgreich. Kein echter Restore-Lauf.
|
||||
- F-11 bleibt fachlich offen bis zum ersten Host-Lauf mit Report unter `/mnt/user/backups/restore-reports/immich-YYYY-MM-DD.md`.
|
||||
|
||||
### 2026-05-27 - H:/ Nearline-Pull vorbereitet
|
||||
|
||||
- `docs/H_DRIVE_NEARLINE_PULL.md` und `ops/h-drive-nearline/pull-critical-backups.ps1` definieren den Windows-seitigen Pull von `\\192.168.178.58\backups\borg\dumps\latest` und `\\192.168.178.58\backups\git-bundles\gitea` nach `H:\kallilab-nearline-backups`.
|
||||
- SMB-Quelle `\\192.168.178.58\backups` und H:/ sind erreichbar; `-WhatIf` prueft den Plan ohne Kopie.
|
||||
- Kein Scheduled Task angelegt und kein echter Kopierlauf gestartet. Empfohlen ist taeglich 05:30 nach dem Borg-Dump-Fenster, Aktivierung erst nach Operator-Sichtpruefung.
|
||||
|
||||
### 2026-05-27 - Storage Layout als Active v1.4 gefuehrt
|
||||
|
||||
- `docs/STORAGE_LAYOUT.draft.md` wurde zu `docs/STORAGE_LAYOUT.md` umbenannt. Das Dokument war inhaltlich bereits als Active markiert; Version 1.4 entfernt den formalen Draft-Blocker.
|
||||
- Physikalische Disk-Werte aus `docs/HARDWARE_INVENTORY.md` und Host-Readout uebernommen: Cache Samsung 970 EVO Plus 1.8T XFS, Disk1 WDC WD60EFAX 5.5T XFS auf `md1p1`, Parity TOSHIBA HDWG480 7.3T, Boot Samsung Flash Drive 59.8G FAT32, H:/ als Nearline-Ziel.
|
||||
- `docs/AUDIT_2026-05-25_TODO.md` Sprint 2 fuer Storage-Layout und Disk-/Share-Baseline auf erledigt gesetzt. Retention-Kalibrierung, Monitoring-Schwellen und RESTORE_MATRIX-Detailklassifikation bleiben normale Folgeaufgaben.
|
||||
|
||||
### 2026-05-27 - F-08 Alert-Regeln vorbereitet
|
||||
|
||||
- `services/posture-check/export-prometheus-textfile.sh` erzeugt Textfile-Metriken fuer Borg-Backup-Frische und kritische Container unter `/mnt/user/services/posture-check/textfile/homelab.prom`.
|
||||
- `monitoring/docker-compose.yml` aktiviert den Node-Exporter-Textfile-Collector. `monitoring/prometheus/alerts.yml` enthaelt vorbereitete Alerts fuer Borg-Stale, Borg-Fehlerstatus, Borg-Warnstatus, Textfile-Stale, Critical-Container-Down und TLS-Cert-Expiry 21/7 Tage.
|
||||
- Host-Smoke 2026-05-27: Skript erzeugt `homelab.prom`, alle gelisteten kritischen Container melden `1`, Borg-Status ist `completed_with_warnings` und wird als Warning statt Critical modelliert.
|
||||
- Kein Monitoring-Redeploy und kein Scheduled Task in diesem Schritt. Abschluss erfolgt nach Host-Schedule, Prometheus-Reload und Testalert.
|
||||
|
||||
### 2026-05-26 - Audit F-16 und F-20 abgeschlossen (Doku-only)
|
||||
|
||||
- F-16: `infra/redis`-Etikett auf die Realitaet abgeglichen. `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md`, `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 13 und `docs/DISASTER_RECOVERY.md` Bootstrap-Stufe 2 beschreiben Redis jetzt als "primaer Paperless-Redis (App-Cache); historisch als shared angelegt, faktisch nur von Paperless genutzt". Immich, Nextcloud, Mealie eigene Redis-Instanzen; Authelia bewusst ohne Redis. Keine Compose-Aenderung.
|
||||
- F-20: Restore-Wege fuer Stack-ENV-only Secrets explizit gemacht. Neuer Abschnitt `6.2.1 Restore-Quellen fuer Stack-ENV-Werte` in `docs/DISASTER_RECOVERY.md` (Reihenfolge Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz, Komodo-Sonderfall, Paperless als Hauptanwendung). Neuer Abschnitt `Stack-ENV-only Secrets - Restore-Wege` in `docs/SECRETS_MAP.md` mit Tabelle je Stack (Paperless, Immich, Mail-Archiver, Speedtest, Komodo, Hermes, Glance). Glance-Widget-Tokens explizit als rebuildbar markiert. Konkrete Werte werden nirgendwo dokumentiert.
|
||||
- `docs/AUDIT_2026-05-25_TODO.md` Sprint 6 entsprechend auf "erledigt" gestellt.
|
||||
- Kein Eingriff in `ops/borg-ui/scripts/gitea-bundle-mirror.sh`, kein Gitea-Bundle-Trockenlauf, keine SSH-/Host-Pruefung.
|
||||
|
||||
### 2026-05-26 - FRITZ!Box-/H:/-/Family-Onboarding-Doku-Update
|
||||
|
||||
- `docs/NETWORK_INVENTORY.md` mit FRITZ!Box-Baseline gefuellt: FRITZ!Box 7590, FRITZ!OS 8.21 (Update gemeldet, nicht eingespielt), Telekom DSL ~87/36 Mbit/s, 36 aktive Heimnetz-Geraete, LAN 1-4 verbunden, WLAN `Fritzi`, Gast-WLAN inaktiv, Telefonie/DECT aktiv, Ausfallschutz nicht eingerichtet, USB nicht verbunden, 2 Portfreigaben aktiv. Soll fuer Portfreigaben: nur `443/tcp` und `222/tcp` auf `192.168.178.58`.
|
||||
- `docs/EXTERNAL_DEPENDENCIES.md` um Telekom-DSL und FRITZ!Box 7590 als WAN-/Router-Abhaengigkeit erweitert; Ausfall-Szenario "Telekom-DSL / FRITZ!Box gestoert" ergaenzt.
|
||||
- `docs/CAPACITY_AND_LIFECYCLE.md` um Abschnitt "H:/ als zusaetzliches lokales Backup-Ziel" ergaenzt. Bewertung: H:/ ist als zweite lokale Nearline-Kopie und Freeze-Sicherung sinnvoll, aber bewusst **kein** Offsite-Ersatz und **kein** CIFS-Hard-Mount am Unraid (STORAGE_LAYOUT §12.6). Pull-Modell vom Windows-PC bleibt der getestete Weg (vgl. Disk1 Phase 2 Freeze 2026-05-25).
|
||||
- `docs/FAMILY_ONBOARDING.md` von Tabellen-Entwurf auf familienverstaendlichen Begruessungstext umgestellt: kurze App-Erklaerungen, konkrete Was-tun-Wenn-Anleitungen (Webseite weg, Passwort vergessen, 2FA verloren, Foto-Backup haengt, Browser-Warnung), "Was du nicht musst"-Block, Hinweis fuer geplante Wochenend-Einladung.
|
||||
- `docs/AUDIT_2026-05-25_TODO.md` Leitplanken aktualisiert: Authelia 2FA/OIDC/CrowdSec und Nextcloud-2FA-Haertung werden in diesem Zyklus nicht angefasst (Operator-Vorgabe). Hermes-Agent geparkt mit Review-Deadline 2026-07-25. USV-Risiko bewusst akzeptiert. Sprint 4 um H:/-Bewertung und FRITZ!Box-Portfreigaben-Abgleich erweitert. Neue Sprints 6 (geparkte Apps) und 7 (Off-site) ergaenzt.
|
||||
- Keine Live-/Compose-Aenderung in diesem Commit; nur Doku.
|
||||
|
||||
### 2026-05-26 - USV-Risiko bewusst akzeptiert
|
||||
|
||||
- Operator-Entscheidung: aktuell wird keine USV angeschafft.
|
||||
- Der Befund bleibt technisch unveraendert: keine funktionierende USV-Abschaltung nachgewiesen. Power-Loss-Risiko fuer Docker-/DB-State und laufende Writes wird bewusst akzeptiert und bei spaeteren Reviews neu bewertet.
|
||||
|
||||
### 2026-05-26 - Borg-Passphrase offline gesichert
|
||||
|
||||
- Operator bestaetigt: Die Borg-Passphrase ist offline/off-system gesichert und kann ohne Host oder Vaultwarden wiederhergestellt werden.
|
||||
- Doku aktualisiert nur den Sicherungsstatus; Secret-Wert und Ablageort bleiben bewusst ausserhalb des Repos.
|
||||
|
||||
### 2026-05-26 - Gitea-Bundle-Mechanik definiert
|
||||
|
||||
- `ops/borg-ui/scripts/gitea-bundle-mirror.sh` ergaenzt: erstellt verifizierte `git bundle`-Artefakte fuer alle bare Gitea-Repositories, schreibt Checksums und einen Markdown-Report.
|
||||
- Zielpfad ist `/mnt/user/backups/git-bundles/gitea`; dieser Pfad muss in den Borg/off-site Scope aufgenommen und hostseitig geplant werden.
|
||||
- `docs/SERVICES_RECOVERY.md` und `docs/RESTORE_MATRIX.md` dokumentieren Bundles jetzt als zweite Repo-Bootstrap-Schicht neben dem GitHub-Mirror.
|
||||
- Host-Erstlauf nach Skript-Fix erfolgreich: 4 Bundles erzeugt (`homelab-infra`, `homelab`, `homepage`, `smart-home-kalli`), Checksums OK, `homelab-infra.bundle` in Restore-Lab geklont und `git fsck` sauber. Offen bleibt die dauerhafte Schedule-Einbindung.
|
||||
|
||||
### 2026-05-26 - Audit-Baseline-Tag gesetzt
|
||||
|
||||
- Der Stand nach Hardware-/Capacity-Baseline, Policy-Triage und Recovery-Doku wurde als `audit-2026-05-25-baseline` markiert und nach Gitea gepusht.
|
||||
|
||||
### 2026-05-26 - Externe Abhaengigkeiten und Services-Recovery baseline dokumentiert
|
||||
|
||||
- `docs/EXTERNAL_DEPENDENCIES.md` von Template auf Betreiber-Baseline angehoben: Domain, Cloudflare, Hetzner, GitHub-Mirror, Tailscale, GMX, Let's Encrypt, Registries, Plex und mobile Push-Pfade sind mit Ausfallwirkung und Notfallplan dokumentiert.
|
||||
- `docs/SERVICES_RECOVERY.md` finalisiert den Komodo-Bootstrap-Anker: `ops/komodo/docker-compose.yml` bleibt verbindlich; der `komodo`-Self-Stack hat keinen aktiven Gitea-Webhook und ist nicht der Recovery-Anker.
|
||||
- Offene Off-Repo-Betreiberchecks bleiben Account-Besitz, 2FA-Recovery-Codes, Zahlungswege, Borg-Passphrase-Hinterlegung und Gitea-Bundle-/Mirror-Mechanik.
|
||||
|
||||
### 2026-05-26 - Policy-Warnings triagiert
|
||||
|
||||
- Plex `network_mode: host` wurde in den Policy-Ausnahmen als dokumentierte Discovery-Ausnahme erfasst.
|
||||
- Mutable Tags bei `ddns-updater`, `glances` und `scrutiny` bleiben wegen vorhandener SHA256-Digests reproduzierbar gepinnt und werden im Policy-Report als Info-Ausnahmen sichtbar gehalten.
|
||||
- `monitoring-influxdb3-core` bleibt als dokumentierte `user: "0"`-Ausnahme bewusst eine Warning, damit der Hardening-Punkt nicht aus dem Blick faellt.
|
||||
|
||||
### 2026-05-26 - Hardware-/Capacity-Baseline abgeschlossen
|
||||
|
||||
- Hardware-Inventar auf Host-Befund aktualisiert: BIOS AMI F21 vom 2025-06-19, Intel Raptor Lake SATA AHCI, Samsung NVMe Controller und Realtek RTL8125 2.5GbE mit aktuellem 1G-Link.
|
||||
- RAM-Baseline dokumentiert: 4x 8 GB DDR4 ohne ECC, gemischte Module, aktuell 2133 MT/s konfiguriert.
|
||||
- Capacity-Baseline dokumentiert: Cache 1.9T mit 97G genutzt (6 %), Disk1/User-Shares 5.5T mit 1.8T genutzt (33 %), lokale Backups 2.2G unter `/mnt/user/backups`.
|
||||
- USV-Befund dokumentiert: `apcupsd` ist vorhanden und auf USB vorkonfiguriert, laeuft aber nicht; `apcaccess status` liefert Connection refused und `lsusb` zeigt keine erkannte USV. Power-Loss bleibt damit eine offene Betreiberentscheidung.
|
||||
|
||||
### 2026-05-26 - Komodo/Gitea-Restdrift bereinigt
|
||||
|
||||
- Der alte Komodo-Stack `grafana` wurde als historischer Altstand inert gemacht: keine Repo-Dateipfade, kein Webhook, keine alte Stack-ENV, keine `missing_files`/`remote_errors`. Rollback bleibt Git-Historie, nicht der alte Komodo-Stack.
|
||||
- Der Gitea-Hook `35` fuer den alten `grafana`-Stack bleibt inaktiv. Der nicht sinnvolle `komodo`-Self-Hook `11` wurde deaktiviert, weil Komodo selbst nicht per Gitea-Webhook auf `master` deployed wird.
|
||||
- Ein kurz sichtbarer Komodo-DB-Typfehler durch `updated_at` als Float wurde im selben Kontrollfenster auf nativen Mongo `Long` korrigiert; danach traten keine neuen `invalid type`-Fehler mehr auf.
|
||||
- Nach der Bereinigung: aktive Gitea-Komodo-Hooks haben `0` Fehlstatus; `komodo-core`, `komodo-periphery`, `komodo-mongo`, `nextcloud` und die aktuellen `monitoring-*` Container laufen weiter.
|
||||
|
||||
### 2026-05-26 - Monitoring-Altstaende aus aktivem Repo entfernt
|
||||
|
||||
- Die abgeloesten Pfade `ops/grafana-influxdb` und `ops/loki` wurden per `git rm` aus dem aktiven Repo entfernt. `monitoring/` bleibt der einzige Observability-Zielstack.
|
||||
- Live-Check vor dem Cleanup: nur `monitoring-grafana`, `monitoring-promtail`, `monitoring-influxdb3-core` und `monitoring-loki` laufen; alte Container `grafana`, `influxdb3-core`, `loki` und `alloy` sind nicht vorhanden.
|
||||
- Rollback erfolgt bei Bedarf ueber Git-Historie, nicht ueber parallel gepflegte Compose-Verzeichnisse.
|
||||
- Im selben GitOps-Kontrollfenster wurde Gitea-Webhook `35` fuer den alten `grafana`-Rollback-Stack als inaktiv bestaetigt. Der aktive Nextcloud-Hook `36` hatte einen Signaturfehler; sein Secret wurde ohne Ausgabe des Werts aus der Komodo-Stack-Konfiguration zurueck nach Gitea synchronisiert.
|
||||
|
||||
### 2026-05-26 - AdGuard Admin-Port auf Tailscale-Soll begrenzt
|
||||
|
||||
- Host-Audit per SSH gegen `Kallilabcore` durchgefuehrt: Tailscale IPv4 ist `100.80.98.33`, LAN-IP ist `192.168.178.58/24`, Gateway `192.168.178.1`.
|
||||
- Repo-Soll fuer `host-services/Adguard/docker-compose.yml` geaendert: DNS `53/tcp+udp` bleibt unveraendert, die Admin-UI bindet nun auf `100.80.98.33:8082:80`.
|
||||
- Architektur, Service-Katalog, Repo-Map, Netzwerk-Inventar und AI-Kontext wurden an das neue Modell angepasst: keine Traefik-/Authelia-2FA-Umstellung, aber keine LAN-weite Admin-Bindung mehr.
|
||||
- Live-Deploy wurde nach Fast-Forward des AdGuard-Workspaces auf `5cb4017` mit `docker compose -p adguard ... up -d` ausgefuehrt. Validierung erfolgreich: `ss -ltnp` zeigt `100.80.98.33:8082`, DNS via `@127.0.0.1` und `@192.168.178.58` funktioniert, `http://100.80.98.33:8082/` liefert HTTP 302, `http://192.168.178.58:8082/` ist nicht mehr erreichbar.
|
||||
- Nachpruefung des GitOps-Pfads: Gitea-Hook `1` zeigt auf Komodo-Stack `69c7b9e26b77cd827811b9d0` und lieferte HTTP 200. Komodo-Deploys fuer AdGuard scheiterten zunaechst im `Git pull` einmal an `.git/index.lock` und danach an `fatal: Cannot rebase onto multiple branches`; der Workspace wurde aufgeraeumt und steht sauber auf `origin/master`.
|
||||
|
||||
### 2026-05-26 - Audit-Umsetzung vorbereitet
|
||||
|
||||
- Aus `docs/AUDIT_2026-05-25.md` wurde `docs/AUDIT_2026-05-25_TODO.md` als operative Arbeitsliste abgeleitet. Authelia-2FA/OIDC bleibt bewusst geparkt und wird erst nach finaler Policy-Entscheidung umgesetzt.
|
||||
- Neue Inventar- und Betriebsdokumente angelegt: `docs/HARDWARE_INVENTORY.md`, `docs/NETWORK_INVENTORY.md`, `docs/EXTERNAL_DEPENDENCIES.md`, `docs/CAPACITY_AND_LIFECYCLE.md` und `docs/FAMILY_ONBOARDING.md`.
|
||||
- `docs/SERVICES_RECOVERY.md` beschreibt initial die recovery-kritischen `/mnt/user/services`-Pfade, Gitea-Repo-Mirror-Optionen, Komodo-Bootstrap und Secret-Recovery-Reihenfolge.
|
||||
- Policy-Check lokal erneut ausgefuehrt: die alten SEC001-Warnings fuer `ddns-updater` und `scrutiny` sind nicht mehr aktuell; verbleibende Warnings betreffen Host-Netz-/User-/Image-Tag-Themen und Altstaende.
|
||||
|
||||
### 2026-05-25 - Unraid Flash-Backup in Borg-Scope aufgenommen
|
||||
|
||||
- `pre-backup-dumps.sh` erzeugt zusaetzlich zu den DB-Dumps ein sensibles `unraid-flash-config.tar.gz` aus `/boot/config` inklusive SHA256 und Manifest unter `/mnt/user/backups/borg/dumps/latest`.
|
||||
- Da `/local/borg-dumps` bereits Teil des Borg-Scopes ist, wird das Flash-Konfigurationsartefakt mit dem bestehenden Hetzner/Borg-Backup historisiert. Downloadbare Plugin-Paketarchive unter `/boot/config/plugins/*/` werden aus dem Artefakt ausgeschlossen; Restore-relevante Konfiguration bleibt enthalten.
|
||||
- Live-Erstlauf erfolgreich: `pre-borg.sh` lieferte `critical_count=0`, Freshness `Critical: 0`, `unraid-flash-config.tar.gz` ist 297 KiB gross, `0600 root:root`, SHA256-Pruefung `OK`, 356 Archiv-Eintraege, Manifest fuer Unraid `7.2.4`. Der Borg-UI-Job `Taegliche Sicherung` ist aktiv und umfasst `/local/borg-dumps`; der naechste planmaessige Hetzner-Lauf nimmt das neue Flash-Artefakt mit. Der Host-Repo-Clone unter `/mnt/user/services/homelab-infra` wurde wegen eines fehlgeschlagenen Fast-Forward-Checkouts frisch geklont; der vorherige Stand liegt archiviert unter `/mnt/user/services/_archive/homelab-infra-pre-refresh-20260525-194209`.
|
||||
|
||||
### 2026-05-25 - Monitoring-Zielstack finalisiert und Uptime Kuma entfernt
|
||||
|
||||
- `monitoring` und `glance` wurden auf Commit `b6bbca4` deployed; Komodo zeigt fuer beide `latest_hash` = `deployed_hash` = `b6bbca4` ohne `remote_errors`. Die zehn `monitoring-*` Container laufen, `monitoring.kaleschke.info` und `glance.kaleschke.info` leiten anonym zu Authelia, Prometheus ist ready und Loki `/ready` liefert `ready`.
|
||||
- Alte Monitoring-Altcontainer `grafana`, `influxdb3-core`, `loki` und `alloy` sind in Docker nicht vorhanden; `ops/grafana-influxdb` und `ops/loki` bleiben nur als Rollback-/Migrationsreferenz im Repo. Der noch aktive Gitea-Hook `35` des alten `grafana`-Rollback-Stacks wurde deaktiviert, damit zukuenftige Pushes den Altstand nicht reaktivieren.
|
||||
- Uptime Kuma wurde durch Blackbox/Prometheus/Grafana ersetzt: aktive Blackbox-Zielliste enthaelt 19 HTTPS-Ziele, `uptime.kaleschke.info` ist dort nicht mehr enthalten und liefert nach Stack-Removal 404. Der Komodo-Stack `uptime-kuma` wurde gestoppt/destroyed/geloescht, Gitea-Webhook `23` deaktiviert, Appdata nach `/mnt/user/appdata/_archive/uptime-kuma-removed-2026-05-25` und der alte Stack-Workspace nach `/mnt/user/services/stacks/_archive/uptime-kuma-removed-2026-05-25` verschoben.
|
||||
- Authelia-Hostconfig wurde mit Backup `configuration.yml.pre-uptime-removal-20260525-164343.bak` um den toten `uptime.kaleschke.info`-Eintrag bereinigt, validiert und neu gestartet. Prometheus wurde wegen eines `Stale NFS file handle` auf der gebundenen Konfigurationsdatei per Komodo-Restart neu gemountet.
|
||||
|
||||
### 2026-05-25 - AdGuard Admin-Port bewusst LAN-direkt belassen
|
||||
|
||||
- Strategische Option `adguard.kaleschke.info` hinter Traefik/Authelia-2FA wurde bewertet, aber vom Operator bewusst verworfen, weil der Betriebsweg einfach bleiben soll. AdGuard bleibt als dokumentierte Ausnahme mit DNS `53/tcp+udp` und Admin `8082:80` LAN-direkt; keine Live-Aenderung an AdGuard, Authelia oder Traefik wurde vorgenommen.
|
||||
|
||||
### 2026-05-25 - Borg-Passphrase Host-Secret verifiziert
|
||||
|
||||
- Erwartete Host-Secret-Datei `/mnt/user/appdata/secrets/borg_repo_passphrase.txt` aus der bestehenden Borg-UI-Repo-Konfiguration erzeugt, mit `root:root` und Modus `600` gesichert und per `borg info` gegen das Hetzner-Borg-Repo verifiziert. Analoge Offline-Hinterlegung bleibt bewusste Operator-Aufgabe; Secret-Wert wurde nicht ausgegeben oder dokumentiert.
|
||||
|
||||
### 2026-05-25 - Dashboard auf Glance konsolidiert
|
||||
|
||||
- Glance bleibt das einzige Homelab-Dashboard; Homepage wurde aus dem Zielbild entfernt. Authelia-Default-Redirect, Monitoring-Blackbox-Ziele, Cert-Check-Domains und Glance-Konfiguration zeigen nicht mehr auf `home.kaleschke.info`; Homepage wurde via Komodo-API gestoppt/destroyed, der Komodo-Stack geloescht, der alte Gitea-Webhook deaktiviert und Appdata nach `/mnt/user/appdata/_archive/homepage-removed-2026-05-25` verschoben.
|
||||
|
||||
### 2026-05-25 - Jellyfin aus Zielbild entfernt
|
||||
|
||||
- Plex-Smoke-Test erfolgreich (`/identity` HTTP 200, Container healthy, `/data/movies` und `/photos` sichtbar). Jellyfin wurde repo-seitig entfernt, aus Authelia-Baseline und Zielbild-Doku ausgetragen, via Komodo-API gestoppt/destroyed, der Komodo-Stack geloescht und Appdata nach `/mnt/user/appdata/_archive/jellyfin-removed-2026-05-25` verschoben; Plex bleibt einziger Medienserver.
|
||||
|
||||
### 2026-05-25 - Externer Repo-Mirror eingerichtet
|
||||
|
||||
- Gitea erlaubt fuer Repo-Migrationen und Mirror-Targets gezielt `github.com` und nutzt explizite externe DNS-Resolver. `Micha/homelab-infra` spiegelt nun als privater GitHub-Push-Mirror nach `michaelkaleschke-spec/homelab-infra`; erster manueller Sync erfolgreich, Gitea `push_mirror.last_error` leer. Token-Werte bleiben ausschliesslich in Gitea/GitHub und werden nicht dokumentiert.
|
||||
|
||||
### 2026-05-25 - Audit-Final nachgemessen
|
||||
|
||||
- Audit-Restliste erneut live geprueft: runtime-relevanter Stack-Inhalt fuer `gitea`, `borg-ui` und `monitoring` seit `66ee10c` unveraendert; abschliessende Audit-Doku-Commits liegen in Gitea; Monitoring inklusive Loki `/ready` gruen; Borg-Job und 15 kanonische Dump-Artefakte frisch; `docs/AUDIT_2026-05-23_FINAL.md` auf den Live-Stand aktualisiert.
|
||||
|
||||
### 2026-05-25 - Disk1 Phase 2 abgeschlossen
|
||||
|
||||
- Disk1 wurde nach H:-Freeze-Backup und finalem Service-Freeze von NTFS/`ntfs3` auf XFS migriert.
|
||||
- Restore verifiziert: `media` final 2722 Dateien und 1,800,782,188,226 Bytes mit 0 missing/extra/size mismatch; Tar-Shares und Disk1-Extras aus den H:-Freeze-Archiven wiederhergestellt.
|
||||
- Docker/Services nach XDG-Runtime-Fix wieder stabil: 49 Container laufend, 0 stopped, 0 unhealthy, 0 starting; Gitea, Komodo, Borg, Jellyfin und Monitoring per Smoke-Test erreichbar.
|
||||
- Borg-UI meldet den letzten Backup-Job `completed`; `pre-backup-dumps.sh` wurde nach Wiederanlauf erneut ausgefuehrt und 15 kanonische Dump-Artefakte sind juenger als 24 h.
|
||||
- `posture-check` erwartet Disk1 nun standardmaessig als XFS (`ALLOW_DISK1_NTFS=0`).
|
||||
|
||||
### 2026-05-23 - Audit-Endstufe verifiziert
|
||||
|
||||
- Lokalen Hardening-Commit `cd650b1` nach Gitea gepusht; Komodo-Workspaces fuer `gitea`, `borg-ui` und `monitoring` stehen auf `cd650b1`.
|
||||
- Live-Audit in `docs/AUDIT_2026-05-23_LIVE.md` dokumentiert: Gitea-Registration geschlossen, Borg-Dumps frisch, Monitoring-Stack aktiv, alte Grafana/Loki-Altcontainer nicht mehr vorhanden.
|
||||
- Jellyfin und Plex in Architektur, Service-Katalog und Repo-Map nachgetragen; Plex ist jetzt als Repo-Compose-Stack mit dokumentierter Host-Netz-Ausnahme gefuehrt.
|
||||
- Repo-Hygiene abgeschlossen: `.serena/` ignoriert, leere Verzeichnisse entfernt, Windows-Reinstall-Helfer unter `ops/windows-reinstall/` bewusst versioniert.
|
||||
|
||||
### 2026-05-20 - Gitea 5xx-Bursts untersucht und Signup geschlossen
|
||||
|
||||
- Live-Befund zu `HomelabTraefik5xx`: kurze externe `POST /`-Bursts auf `gitea@docker` von `103.153.183.69` und `103.153.183.73`, jeweils HTTP 500 in unter 10 ms; normale Gitea-Checks und Git-Reads liefen parallel mit HTTP 200.
|
||||
- Keine Hinweise auf erfolgreichen Zugriff: Gitea-Container ohne Restart/OOM, nur User `micha`, keine neuen User der letzten 30 Tage, keine neuen Repos, SSH-Keys oder Access-Tokens im Untersuchungsfenster.
|
||||
- Live-Prometheus lief noch mit der alten Regel `rate(...[5m]) > 0`; die bereits im Repo vorbereitete Regel `increase(...[5m]) >= 5` wurde auf den Live-Mount kopiert und per Prometheus-Reload aktiviert.
|
||||
- Gitea-Registrierung und OpenID-Signup wurden geschlossen: `DISABLE_REGISTRATION=true`, `REGISTER_EMAIL_CONFIRM=true`, `ENABLE_OPENID_SIGNIN=false`, `ENABLE_OPENID_SIGNUP=false`; Signup-Seite zeigt danach "Registration is disabled", OpenID-Login liefert 403.
|
||||
|
||||
### 2026-05-18 - Komodo Webhooks vollstaendig abgeglichen
|
||||
|
||||
- Live-Befund auf `Kallilabcore`: Komodo hatte fuer mehrere aktuelle Stacks `webhook_enabled: true`, aber Gitea enthielt noch nicht fuer alle aktuellen Stack-IDs aktive Webhooks.
|
||||
- In der Gitea-Datenbank wurden aktive Webhooks fuer `monitoring` (`6a08d5297707b0930ab95c72`), `glance` (`6a09d7347707b0930ab96eae`), `grafana` (`69f31ecdf65eb72b757c497d`) und `nextcloud` (`69e519085fd5e8bc51f121f0`) nach dem bestehenden Komodo-Hook-Muster angelegt.
|
||||
- Stale aktive Gitea-Hooks auf nicht mehr vorhandene bzw. alte Komodo-Stack-IDs wurden deaktiviert.
|
||||
- Abgleich danach: 30 aktive Gitea-Komodo-Hooks fuer 30 Komodo-Stacks mit aktiviertem Webhook; `hermes` bleibt in Komodo bewusst `webhook_enabled: false`.
|
||||
- Netzwerkpfad aus dem `gitea`-Container zu `komodo-core:9120` wurde erfolgreich verifiziert; `last_status=0` fuer neue Hooks bleibt bis zum ersten Push erwartbar.
|
||||
|
||||
### 2026-05-19 - Posture-Check Host-Version verifiziert
|
||||
|
||||
- Ursache fuer wiederholte ntfy-Warnings war nicht mehr die Repo-Logik allein, sondern dass auf dem Unraid-Host noch die alte Skriptversion unter `/mnt/user/services/homelab-infra/services/posture-check/posture-check.sh` ausgefuehrt wurde.
|
||||
- Host-Skript wurde mit Backup ersetzt und mit `SEND_NTFY=0` direkt auf dem Host verifiziert.
|
||||
- Ergebnis des echten Host-Laufs: `status: ok`, `critical_count: 0`, `warning_count: 0`.
|
||||
- Betriebsregel daraus: Bei Host-User-Scripts nach Repo-Aenderungen immer den tatsaechlich ausgefuehrten Host-Pfad und den Live-Output pruefen.
|
||||
|
||||
### 2026-05-19 - Borg-Scope fuer GitOps Host Automation erweitert
|
||||
|
||||
- Nach den Gitea-/Komodo-Webhook- und Posture-Check-Aenderungen wurde der Backup-Scope um Host-GitOps-Pfade erweitert.
|
||||
- Borg UI mountet kuenftig `/mnt/user/services` read-only als `/local/services`.
|
||||
- In `all-important-sources.txt` wurden `/local/services/homelab-infra`, `/local/services/stacks` und `/local/services/posture-check` aufgenommen.
|
||||
- `pre-backup-dumps.sh` wurde auf dem Host ausgefuehrt; frische Dumps fuer `gitea.sqlite.dump` und `komodo-mongo.archive.gz` liegen unter `/mnt/user/backups/borg/dumps/latest`.
|
||||
- Wirksam wird der neue `/local/services`-Mount nach Redeploy/Recreate des `borg-ui`-Stacks.
|
||||
|
||||
### 2026-05-19 - Traefik-5xx Alert entstoert
|
||||
|
||||
- `HomelabTraefik5xx` hatte auf einzelne 5xx-Antworten reagiert, weil die Regel `rate(...[5m]) > 0` nutzte.
|
||||
- Live-Befund fuer `gitea@docker`: zwei kurze `POST /` mit HTTP 500 von einer externen IP, danach durchgehend erfolgreiche Gitea-Checks; kein Container-Restart.
|
||||
- Prometheus-Regel auf `increase(...[5m]) >= 5` geaendert, damit einzelne externe Fehlrequests keinen ntfy-Alarm ausloesen.
|
||||
|
||||
### 2026-05-17 - Glance Homelab-Dashboard vorbereitet
|
||||
|
||||
- `ops/glance` als geschuetztes Homelab-Dashboard unter `glance.kaleschke.info` vorbereitet.
|
||||
- Glance zeigt HTTP-Monitore fuer Core, Apps und Ops, Docker-Containergruppen, Host-Snapshot und Bookmarks.
|
||||
- Docker-Status laeuft nicht ueber einen direkten Socket-Mount in Glance, sondern ueber `glance-docker-socket-proxy` auf einem internen `glance_socket_net`.
|
||||
- Die HTTP-Monitore nutzen oeffentliche URLs als Klickziel und interne `check-url`-Endpunkte auf `frontend_net`, damit Glance nicht vom externen Hairpin-/Auth-Pfad abhaengt.
|
||||
- Das Immich Community-Widget wurde ergaenzt. Der API-Zugriff nutzt eine interne Service-URL und ein Stack-ENV-Token. Paperless, Scrutiny und Speedtest bleiben Kandidaten fuer einen spaeteren Widget-Pass, sobald die konkrete API-Ausgabe im Glance-Kontext sauber verifiziert ist.
|
||||
- Das Dashboard-Layout wurde an `ginesjunior11/glance-dashboard-config` angelehnt: dunkleres blaues Theme, Zeitfortschrittsgruppe, farbige Dashboard-Icons, dichter `Homelab Status`, Server-Stats im Hauptbereich und eine zweite Seite `Infrastructure and Media`. Die rechte Home-Spalte zeigt WAN-Infos aus Speedtest Tracker, Speedtest-Livewerte, AdGuard-DNS-Stats, DNS/Ingress-Monitore und eine separate Netzwerk-Containergruppe.
|
||||
|
||||
### 2026-05-17 - Monitoring-Zielstack konsolidiert
|
||||
|
||||
- `monitoring/` als zentraler Observability-Zielstack fuer Prometheus, Loki, Promtail, Grafana, node-exporter, cAdvisor und InfluxDB 3 Core vorbereitet.
|
||||
- `monitoring-grafana` nutzt den Repo-Standard `authelia@file,secure-headers@file` und Secrets per Datei statt Klartext-Stack-ENV.
|
||||
- `monitoring-influxdb3-core` uebernimmt den LAN-only Writer-Endpunkt fuer Home Assistant (`8181` via `INFLUXDB_BIND_IP`).
|
||||
- `ops/loki` und `ops/grafana-influxdb` sind abgeloeste Altstaende und bleiben nur als Rollback-/Migrationsreferenz im Repo.
|
||||
|
||||
### 2026-05-07 - Vaultwarden Restore-Test praktisch verifiziert
|
||||
|
||||
- Erster echter Vaultwarden-Mini-Restore gegen das produktive Borg-Repo `hetzner_borg_appdata_critical` erfolgreich durchgefuehrt.
|
||||
- Restore lief isoliert nach `/mnt/user/backups/restore-lab/vaultwarden`, nicht gegen produktive Pfade.
|
||||
- Testinstanz `restoretest-vaultwarden` wurde lokal auf `127.0.0.1:18080` gestartet; HTTP 200 und Login-Seite wurden erfolgreich bestaetigt.
|
||||
- Report wurde unter `/mnt/user/backups/restore-reports/vaultwarden-2026-05-07.md` geschrieben.
|
||||
- Fuer den praktischen Restore-Pfad wurden zwei hostseitige Voraussetzungen sichtbar und umgesetzt:
|
||||
- `known_hosts` fuer das Hetzner-Ziel im `borg-ui`-Container
|
||||
- Host-Secret-Datei `/mnt/user/appdata/secrets/borg_repo_passphrase.txt` fuer kuenftige Restore-Tests
|
||||
- Testdaten unter `/mnt/user/backups/restore-lab/vaultwarden/data` wurden nach erfolgreichem Lauf wieder bereinigt.
|
||||
|
||||
### 2026-05-07 - Gitea Restore-Test praktisch verifiziert
|
||||
|
||||
- Erster echter Gitea-Mini-Restore gegen das produktive Borg-Repo `hetzner_borg_appdata_critical` erfolgreich durchgefuehrt.
|
||||
- Restore lief isoliert nach `/mnt/user/backups/restore-lab/gitea`, nicht gegen produktive Pfade.
|
||||
- Testinstanz `restoretest-gitea` wurde lokal auf `127.0.0.1:13000` und `127.0.0.1:12222` gestartet.
|
||||
- HTTP 200, HTML-Titel und lokaler SSH-Port wurden erfolgreich bestaetigt.
|
||||
- Report wurde unter `/mnt/user/backups/restore-reports/gitea-2026-05-07.md` geschrieben.
|
||||
- Testdaten unter `/mnt/user/backups/restore-lab/gitea/data` wurden nach erfolgreichem Lauf wieder bereinigt.
|
||||
|
||||
### 2026-05-07 - Paperless Restore-Test praktisch verifiziert
|
||||
|
||||
- Erster echter Paperless-Mini-Restore gegen das produktive Borg-Repo `hetzner_borg_appdata_critical` erfolgreich durchgefuehrt.
|
||||
- Restore umfasste sowohl die Dateipfade als auch `postgresql17-paperless.dump` aus dem Borg-Archiv.
|
||||
- Testinstanzen `restoretest-paperless`, `restoretest-paperless-postgres` und `restoretest-paperless-redis` liefen isoliert ohne Traefik.
|
||||
- Login-Seite war lokal auf `127.0.0.1:18120` erreichbar.
|
||||
- Der Dump-Import in Test-Postgres war erfolgreich; die Test-Datenbank enthielt `25` Dokumente.
|
||||
- Report wurde unter `/mnt/user/backups/restore-reports/paperless-2026-05-07.md` geschrieben.
|
||||
- Testdaten unter `/mnt/user/backups/restore-lab/paperless` wurden nach erfolgreichem Lauf wieder bereinigt.
|
||||
|
||||
### 2026-05-06 - Komodo Webhook Secret getrennt
|
||||
|
||||
- `KOMODO_WEBHOOK_SECRET` von `KOMODO_SECRET_KEY` getrennt und als eigene Stack-ENV-Variable dokumentiert.
|
||||
- Gitea-Komodo-Webhooks mit bisherigem Core-Secret wurden auf den neuen `KOMODO_WEBHOOK_SECRET` umgestellt; bereits individuelle per-Stack-Webhook-Secrets wurden beibehalten.
|
||||
- Host-`.env`, persistente Komodo-Compose und Gitea-Webhooks wurden als ein gemeinsamer Runtime-Schritt behandelt, damit Auto-Deploys nicht auseinanderlaufen.
|
||||
- Ein stale Gitea-Webhook auf eine nicht mehr vorhandene Komodo-Stack-ID wurde deaktiviert, nicht geloescht.
|
||||
|
||||
### 2026-05-06 - Authelia GMX SMTP Notifier
|
||||
|
||||
- Authelia-Notifier von Filesystem-Log auf GMX SMTP (`submission://mail.gmx.net:587`) umgestellt.
|
||||
- SMTP-Passwort bleibt ausserhalb des Repos unter `/mnt/user/appdata/secrets/authelia_smtp_password.txt`.
|
||||
- Authelia-Compose erhaelt explizite DNS-Server, weil der SMTP-Startup-Check externe Namen wie `mail.gmx.net` aufloesen muss.
|
||||
- Repo-Baseline und Host-Config muessen bei Auth-Aenderungen weiter bewusst gemerged und vor Restart validiert werden.
|
||||
|
||||
### 2026-05-06 - Hermes DR und Mail-Archiver Authelia
|
||||
|
||||
- Hermes Agent in `docs/RESTORE_MATRIX.md` und `docs/DISASTER_RECOVERY.md` mit Restore-Pfaden, Secret-/ENV-Hinweisen und Smoke-Test ergaenzt.
|
||||
- Mail-Archiver Web-UI hinter `authelia@file,secure-headers@file` gelegt; App-eigene Auth bleibt als zweite Schutzschicht bestehen.
|
||||
- M10/Komodo blieb unveraendert.
|
||||
|
||||
### 2026-05-05 - N-Aufraeum-Sprint
|
||||
|
||||
- Obsolete Compose-Top-Level-Felder `version: "3.9"` aus Immich, Mail Archiver und Paperless entfernt.
|
||||
- Leere `env/domains.env.example` und `env/global.env.example` mit nicht geheimen Beispielwerten gefuellt.
|
||||
- Veraltete `.keep`-Platzhalter aus Verzeichnissen mit echten Compose-/Repo-Inhalten sowie zwei reine Geister-Verzeichnisse (`host-services/plex`, `infra/dns`) entfernt.
|
||||
|
||||
### 2026-05-16 - Backup-Konsistenz und erster Hardening-Schnitt
|
||||
|
||||
- SQLite-Dumps fuer Gitea, Vaultwarden, Speedtest Tracker und Filebrowser werden containerseitig als `*.sqlite.dump` erzeugt und per Freshness-Check geprueft; Uptime Kuma wurde am 2026-05-25 aus dem aktiven Dump-Scope entfernt.
|
||||
- `nextcloud.dump` und die Nextcloud-Userdaten sind als Option A im Borg-Scope dokumentiert.
|
||||
- Filebrowser mountet keine breite `/mnt/user/appdata`-Flaeche mehr, sondern nur noch Documents, Photos, Projekte sowie eigenen App-State.
|
||||
- Authelia Argon2id-Parameter in der Repo-Baseline auf `iterations: 3`, `memory: 65536`, `parallelism: 4` gesetzt; produktive Host-Config muss kontrolliert gemerged und mit Test-User validiert werden.
|
||||
- Redis-Caches wurden auf `redis:7.4-alpine@sha256:...` vereinheitlicht; Nextcloud wurde mit Registry-validiertem Digest gepinnt.
|
||||
- Eindeutig aufloesbare `latest@sha256`-Images wurden auf konkrete Tags umgestellt: Homepage `v1.12.3`, code-server `4.116.0`, Filebrowser `v2.63.2`, Speedtest Tracker `1.13.12`.
|
||||
|
||||
### 2026-05-05 - M3b versionierte App-Images digest-gepinnt
|
||||
|
||||
- Versionierte Nicht-Komodo-Images fuer BentoPDF, Mealie, Paperless, Paperless-GPT, AdGuard Home, Grafana, InfluxDB 3 Core und Traefik auf die am Host laufenden, manifest-validierten Digests gepinnt.
|
||||
- `nextcloud:33.0.2-apache` wurde bewusst nicht in diesem Schritt gepinnt, weil der lokal gelistete Digest nicht als Registry-Manifest fuer `tag@sha256` validierbar war.
|
||||
- Redis-Caches und Komodo/M10 blieben unveraendert.
|
||||
|
||||
### 2026-05-05 - M6/M7/M8 Doku-Konsolidierung
|
||||
|
||||
- `hermes.kaleschke.info` als produktive Hermes-Dashboard-Route hinter Traefik + Authelia in Architektur, Repo-Map und Service-Katalog ergaenzt.
|
||||
- `grafana` und `influxdb3-core` laufen weiterhin als `user: "0"`; das wurde als Host-Appdata-Permissions-Ausnahme dokumentiert und nicht nebenbei geaendert.
|
||||
- Tailscale-Ausnahme um `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` ergaenzt.
|
||||
- Komodo-Secret-/Webhook-Themen wurden bewusst nicht geaendert; Komodo-Aenderungen erfolgen nur gemeinsam mit dem Betreiber.
|
||||
|
||||
### 2026-05-05 - M3a stateful Digest-Pinning
|
||||
|
||||
- PostgreSQL 17 Datenhalter auf `postgres:17.9@sha256:5b96f1a16bd9768b060dd2ffe55cb6225c4d9ef4d214a8b21eb08134869a97e4` gepinnt (`postgresql17`, `mealie-postgres`, `nextcloud-postgres`).
|
||||
- Immich pgvector-Postgres auf `tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52` gepinnt.
|
||||
- Komodo Mongo auf `mongo:7.0.32@sha256:32979a1189dfdc44da3f5ed40d910495f5ad8f6f7f77556646f890a30b2d3f56` sowie Komodo Core/Periphery und Gitea auf die am Host laufenden Digests gepinnt.
|
||||
- Redis-Caches wurden am 2026-05-16 auf `redis:7.4-alpine@sha256:...` vereinheitlicht; Redeploys erfolgen stackweise mit Smoke-Test, nicht parallel.
|
||||
|
||||
### 2026-05-04 - Komodo Self-Stack Drift auf persistenten Pfad zurueckgefuehrt
|
||||
|
||||
- Drift-Befund: `komodo-core` und `komodo-periphery` liefen aus `/tmp/komodo-core-repair.yml` bzw. `/tmp/komodo-periphery-repair.yml`; `komodo-mongo` verwies auf `/mnt/user/services/stacks/komodo/compose.yaml`, obwohl dieser Pfad fehlte.
|
||||
- Vor Eingriff wurden die Repair-Dateien und zugehoerigen `/tmp/*.env`-Dateien unter `/mnt/user/appdata/komodo/_drift_backup_2026-05-04/` gesichert.
|
||||
- Zusaetzlich wurde eine geschuetzte Recovery-ENV unter `/mnt/user/appdata/secrets/_komodo_stack_env_recovery_2026-05-04.env` abgelegt; diese Datei enthaelt Tier-1-Secret-Material und ist kein Dauerzustand.
|
||||
- Vor dem Reconcile wurde das host-seitige Dump-Skript ausgefuehrt; `komodo-mongo.archive.gz` wurde frisch unter `/mnt/user/backups/borg/dumps/latest/` erzeugt.
|
||||
- Persistenter Self-Stack wurde unter `/mnt/user/services/stacks/komodo/compose.yaml` aus `ops/komodo/docker-compose.yml` wiederhergestellt; `.env` wurde hostseitig aus der bestehenden Runtime-ENV abgeleitet.
|
||||
- Der vollstaendige Dry-run haette auch `komodo-mongo` recreated und wurde daher nicht ausgefuehrt. Stattdessen wurden nur `komodo-core` und `komodo-periphery` gezielt mit `--no-deps --force-recreate` aus dem persistenten Pfad neu erstellt; `komodo-mongo` blieb unveraendert healthy.
|
||||
- Smoke-Tests: `docker compose ls` zeigt fuer `komodo` nur noch `/mnt/user/services/stacks/komodo/compose.yaml`, Mongo pingt `{ ok: 1 }`, `https://komodo.kaleschke.info` liefert HTTP 200, und Periphery meldet sich am Core an.
|
||||
- Die `/tmp/*repair.yml`-Dateien bleiben vorerst als Altlast erhalten und duerfen erst nach stabiler Laufzeit bewusst entfernt oder ins Drift-Backup verschoben werden.
|
||||
|
||||
### 2026-05-04 - Authelia ACL-Drift hostseitig gemerged
|
||||
|
||||
- Die produktive Authelia-Config ist groesser als die Repo-Datei, weil sie hostseitige OIDC-/Secret-Konfiguration enthaelt. Die Repo-Datei wurde daher als nicht geheime Baseline eingeordnet und nicht blind auf den Host kopiert.
|
||||
- Host-Backup vor Aenderung: `/mnt/user/appdata/authelia/config/configuration.yml.bak-20260504-acl-sync`.
|
||||
- Minimaler Host-Merge: `homepage.kaleschke.info` wurde aus der bypass-Liste entfernt, `komodo.kaleschke.info` aus der 2FA-Liste entfernt, und `default_redirection_url` wurde auf `https://home.kaleschke.info` gesetzt.
|
||||
- `authelia validate-config` war erfolgreich; Authelia wurde neu gestartet und war danach healthy.
|
||||
- Smoke-Tests: `home.kaleschke.info` liefert fuer anonyme Requests eine Authelia-Weiterleitung, `komodo.kaleschke.info` bleibt ueber native Komodo-Auth erreichbar.
|
||||
|
||||
### 2026-05-04 - Home Assistant InfluxDB LAN-Port und Drift-Runbook
|
||||
|
||||
- `influxdb3-core` fuer Home-Assistant-Writer auf LAN-Port `8181` vorbereitet und deployed.
|
||||
- InfluxDB bleibt ohne Traefik-/Public-Route und haengt nicht im `frontend_net`.
|
||||
- Fuer aktives Docker Host-Port-Publishing wurde zusaetzlich zum internen `grafana_influx_internal` das Compose-Netz `grafana_influx_lan` ergaenzt.
|
||||
- Komodo Periphery dauerhaft um `/mnt/user/services:/mnt/user/services` und `frontend_net` ergaenzt, damit Stack-Workspaces und Gitea-Zugriff reproduzierbar funktionieren.
|
||||
- `docs/GITOPS_DRIFT_RUNBOOK.md` angelegt, um lokale Git-Kopie, Gitea, Komodo Workspace, Docker Runtime und Host-Listener getrennt zu pruefen.
|
||||
|
||||
### 2026-03-28 - GitOps-Konsolidierung
|
||||
|
||||
- Komodo als primaeren Stack-Manager eingefuehrt.
|
||||
- Portainer aus dem Zielbild herausgenommen.
|
||||
- Traefik auf 100% Docker-Labels konsolidiert.
|
||||
- `diun` entfernt; Update-Monitoring wird ueber Komodo abgedeckt.
|
||||
|
||||
### 2026-03-29 - Portainer abgeschaltet
|
||||
|
||||
- Portainer CE aus dem produktiven Betrieb entfernt.
|
||||
- Komodo als alleinigen Stack-Manager festgezogen.
|
||||
|
||||
### 2026-04-13 bis 2026-04-15 - Borg-Rollout abgeschlossen
|
||||
|
||||
- `critical_infra` erfolgreich nach Borg gesichert.
|
||||
- Pre-Backup-Dumps host-seitig ueber Unraid User Scripts etabliert.
|
||||
- Dump-Zielpfad auf `/mnt/user/backups/borg/dumps` umgestellt.
|
||||
- Restore-Smoke-Test fuer `postgresql17-globals.sql` und `gitea.db` erfolgreich nachgewiesen.
|
||||
- Monitoring fuer Borg war historisch ueber `ntfy` und Uptime Kuma eingerichtet; seit 2026-05-25 ersetzt durch `ntfy`, Blackbox/Prometheus und Monitoring Grafana.
|
||||
|
||||
### 2026-04-15 - Repo- und Betriebsbereinigung
|
||||
|
||||
- Firefly, Firefly-Fints und Semaphore aus Repo und Homelab entfernt.
|
||||
- GitHub Desktop als Standard-Workflow fuer den lokalen Sync festgelegt.
|
||||
|
||||
### 2026-04-17 - Sicherheits- und Doku-Abgleich
|
||||
|
||||
- `code-server` hinter `authelia@file,secure-headers@file` abgesichert.
|
||||
- Traefik-Dashboard von `dashboard-auth@file` auf `authelia@file,secure-headers@file` umgestellt; BasicAuth-Hash aus dem Repo entfernt.
|
||||
- Redis von Klartext in der Compose auf Secret-Datei unter `/mnt/user/appdata/secrets/redis_password.txt` umgestellt.
|
||||
- Redis-Passwort bewusst **nicht** rotiert; Live-Passwort bleibt vorerst unveraendert.
|
||||
- `mail-archiver` in der Architektur-Doku an den realen Traefik-Betrieb angepasst.
|
||||
- `paperless-gpt` von `LOG_LEVEL=debug` auf `info` umgestellt.
|
||||
- `speedtest-tracker` von `APP_DEBUG=true` auf `false` umgestellt.
|
||||
- Mutable Image-Tags fuer produktive Stacks auf die aktuell laufenden Digests eingefroren, um Deployments reproduzierbar zu machen.
|
||||
- `paperless-ngx` bleibt fuer `PAPERLESS_DBPASS` und `PAPERLESS_REDIS` vorerst bewusst bei Stack Environment Variables; keine Live-Migration auf `_FILE`, solange der aktuelle Stand stabil laeuft.
|
||||
- Disaster-Recovery-Runbook und Restore-Matrix fuer den Totalausfall-/Wiederanlauf-Fall neu dokumentiert.
|
||||
|
||||
### 2026-04-19 - paperless-gpt Digest-Pin zurueckgenommen
|
||||
|
||||
- Der fuer `paperless-gpt` eingetragene Digest war syntaktisch ungueltig (63 statt 64 Hex-Zeichen) und wurde daher wieder auf `icereed/paperless-gpt:latest` zurueckgesetzt.
|
||||
- Diese Ruecknahme ist bewusst eng auf einen einzelnen defekten Pin begrenzt und aendert keine anderen Digest-Festschreibungen.
|
||||
- Die zwischenzeitlichen OCR-/Versions-Experimente fuer `paperless-gpt` wurden wieder auf den einfachen vorherigen Stand zurueckgenommen (`icereed/paperless-gpt:latest`, `VISION_LLM_MODEL=cnshenyang/qwen3-nothink:14b`), um den letzten bekannten Alltagszustand wiederherzustellen.
|
||||
|
||||
### 2026-04-19 - Nextcloud und Stirling-PDF vorbereitet
|
||||
|
||||
- `apps/nextcloud/docker-compose.yml` als offizieller Docker-Microservice-Stack mit `nextcloud:apache`, eigener PostgreSQL-Datenbank und eigenem Redis vorbereitet.
|
||||
- Nextcloud folgt dem Repo-Standard `frontend_net` + app-internes Netz, nutzt `_FILE`-Secrets fuer Admin- und DB-Passwort und ist bewusst **nicht** hinter zentraler ForwardAuth, damit WebDAV/CardDAV und native Clients sauber funktionieren.
|
||||
- `apps/stirling-pdf/docker-compose.yml` als geschuetzter Tool-Stack hinter `authelia@file,secure-headers@file` vorbereitet.
|
||||
- Stirling-PDF nutzt persistente Pfade fuer `/configs`, `/logs`, `/pipeline`, `/customFiles` und `/usr/share/tessdata`; interne Stirling-Login-Funktion bleibt zugunsten des zentralen Traefik-/Authelia-Zugangs deaktiviert.
|
||||
|
||||
### 2026-04-30 - BentoPDF und Grafana/InfluxDB vorbereitet
|
||||
|
||||
- `stirling-pdf` repo-seitig durch `bentopdf` ersetzt; Domain `pdf.kaleschke.info` bleibt erhalten.
|
||||
- BentoPDF laeuft als geschuetztes browserseitiges PDF-Tool hinter `authelia@file,secure-headers@file` und setzt zusaetzlich COOP/COEP-Header fuer SharedArrayBuffer-basierte Office-Konvertierung.
|
||||
- `ops/grafana-influxdb` als neuer Monitoring-Stack vorbereitet und spaeter in Betrieb genommen.
|
||||
- Grafana laeuft hinter Traefik + Authelia unter `grafana.kaleschke.info`.
|
||||
- InfluxDB 3 Core bleibt ohne Public Route und wird ueber eine provisionierte Grafana-Datenquelle angebunden.
|
||||
- Secrets fuer Grafana-Admin-Passwort, InfluxDB-Admin-Token und Grafana-Datasource-Token sind als Host-Dateien unter `/mnt/user/appdata/secrets/` dokumentiert.
|
||||
|
||||
---
|
||||
|
||||
## Dauerhafte Learnings
|
||||
|
||||
- Kein Live-Editing in Komodo; Git gewinnt immer gegen manuelle Drift.
|
||||
- Webhooks koennen nach einem Push sofort einen Deploy ausloesen.
|
||||
- Rollback soll bevorzugt ueber saubere Git-Commits und bekannte Good States erfolgen, nicht ueber History-Rewrites auf `master`.
|
||||
- Doku soll Endzustaende beschreiben, nicht veraltete Zwischenstaende konservieren.
|
||||
+30
-295
@@ -1,7 +1,7 @@
|
||||
# Network Inventory - KalliLab CORE
|
||||
|
||||
Status: Host-Audit erfasst; Router-Baseline und Portfreigaben-UI bereinigt; FRITZ!Box-Remote-Dienste aus; IPv6-Exposure technisch und per UI entschaerft; Tailscale-Inventar am 2026-06-05 real gemessen.
|
||||
Letzte Pruefung: 2026-06-05 (Tailscale-Inventar), 2026-06-01 (Router/Ports)
|
||||
Status: Host-Audit erfasst; Router-Baseline und Portfreigaben-UI geprueft; VLAN/IPv6-Details offen.
|
||||
Letzte Pruefung: 2026-05-27
|
||||
|
||||
## Zweck
|
||||
|
||||
@@ -14,13 +14,13 @@ Dieses Dokument beschreibt Router, DNS, Tailscale, Portfreigaben und Netztrennun
|
||||
| Anschluss / Provider | DSL, Telekom |
|
||||
| Bandbreite (FRITZ!Box-UI) | ca. 87,3 Mbit/s Download, ca. 36 Mbit/s Upload |
|
||||
| Router-Modell | FRITZ!Box 7590 |
|
||||
| Firmware | FRITZ!OS 8.25 (`154.08.25` per TR-064 am 2026-06-01) |
|
||||
| Firmware | FRITZ!OS 8.21 (Update gemeldet, nicht eingespielt) |
|
||||
| Router-IP | 192.168.178.1 |
|
||||
| DHCP-Server | FRITZ!Box (Standardannahme, Override durch Operator nicht dokumentiert) |
|
||||
| Lokales Subnetz | 192.168.178.0/24 |
|
||||
| IPv6 aktiv | Windows-Client hat Provider-IPv6; Host hat keine globale Provider-IPv6, nur Tailscale-ULA |
|
||||
| IPv6 aktiv | TBD (FRITZ!Box-UI separat pruefen) |
|
||||
| DynDNS / DDNS | Cloudflare via `ddns-updater` (kein FRITZ!Box-DynDNS in Nutzung) |
|
||||
| Heimnetz-Geraete (FRITZ!Box-UI) | 35 aktive Geraete |
|
||||
| Heimnetz-Geraete (FRITZ!Box-UI) | 36 aktive Geraete |
|
||||
| LAN-Ports belegt | LAN 1-4 verbunden |
|
||||
| Telefonie / DECT | aktiv |
|
||||
| USB an FRITZ!Box | nicht verbunden |
|
||||
@@ -30,8 +30,7 @@ Dieses Dokument beschreibt Router, DNS, Tailscale, Portfreigaben und Netztrennun
|
||||
|
||||
- Telekom-DSL ist Single-WAN; ohne Ausfallschutz ist Internet-Ausfall = kein DDNS-Update, keine ACME-Erneuerung, keine externen Push-Quellen.
|
||||
- Upload 36 Mbit/s ist die effektive Obergrenze fuer Off-site-Backup-Geschwindigkeit nach Hetzner und fuer Plex-Remote-Streaming.
|
||||
- FRITZ!OS ist am 2026-06-01 per TR-064 auf `154.08.25` beobachtet; FRITZ!Box-Konfig-Backup `Einstellungen_FRITZ.Box_7590_154.08.25_01.06.26_1318.export` wurde extern/off-system in Vaultwarden abgelegt.
|
||||
- `Internet -> Freigaben -> FRITZ!Box-Dienste` ist am 2026-06-01 geprueft: Internetzugriff auf die FRITZ!Box per HTTPS ist aus, FTP/FTPS-Zugriff auf Speichermedien ist aus.
|
||||
- FRITZ!OS 8.21 hat ein angezeigtes Update; Einspielung ist Betreiber-Aufgabe und nicht Teil des Repos.
|
||||
|
||||
## DNS
|
||||
|
||||
@@ -44,168 +43,28 @@ Dieses Dokument beschreibt Router, DNS, Tailscale, Portfreigaben und Netztrennun
|
||||
|
||||
## Tailscale
|
||||
|
||||
Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`,
|
||||
`tailscale status --json`, `tailscale ip -4/-6`).
|
||||
|
||||
| Feld | Wert / Status |
|
||||
| Feld | Wert |
|
||||
|---|---|
|
||||
| Node-Name | Kallilabcore |
|
||||
| Tailnet / MagicDNS | `taild9fcf2.ts.net`; DNSName `kallilabcore.taild9fcf2.ts.net` |
|
||||
| Tailscale IPv4 | `100.80.98.33` |
|
||||
| Tailscale IPv6 | `fd7a:115c:a1e0::2c01:62b2` (gemessen 2026-06-05) |
|
||||
| Exit Node | **Nein.** `Self.ExitNodeOption: false` und `Self.ExitNode: false` — Host bietet keinen Exit Node an und nutzt keinen. Entspricht dem Ziel (Operator-Zugang ist eingehend, nicht als Internet-Ausgang). |
|
||||
| Subnet Router | **Ja, aktiv.** Host advertised und ist Primary fuer `192.168.178.0/24` (`Self.PrimaryRoutes: ["192.168.178.0/24"]`, ebenfalls in `AllowedIPs`). Das LAN ist also fuer das gesamte Tailnet ueber diesen Subnet-Router erreichbar — bewusst gemessener Ist-Zustand, **kein** "keine Route" wie zuvor vermutet. |
|
||||
| ACL-Policy extern dokumentiert | **Angewendet 2026-06-06** — restriktive Tag-basierte `grants`-Policy live (`tag:server`/`tag:operator`, `tag:family` schlafend). Default-Allow entfernt, verifiziert. Details im Block unten. |
|
||||
| Tailscale IPv4 | 100.80.98.33 |
|
||||
| Tailscale IPv6 | TBD |
|
||||
| Exit Node | TBD |
|
||||
| Subnet Router | TBD |
|
||||
| ACL-Policy extern dokumentiert | TBD |
|
||||
|
||||
### Tailnet-Geraete (Snapshot 2026-06-05)
|
||||
|
||||
| Tailscale-IP | Node | OS | Status |
|
||||
|---|---|---|---|
|
||||
| `100.80.98.33` | kallilabcore | linux | aktiv (Host, Subnet-Router) |
|
||||
| `100.78.133.37` | baerchen-1 | windows | aktiv (aktuelle Operator-Workstation, direct) |
|
||||
| `100.105.203.21` | baerchen | windows | offline, zuletzt vor ~1 Tag gesehen (Alt-Node) |
|
||||
| `100.73.83.55` | iphone-14 | iOS | bekannt |
|
||||
| `100.112.0.90` | kallilab-core | linux | **am 2026-06-06 entfernt.** War der redundante userspace-only `Tailscale-Docker`-Stack (`host-services/tailscale/`). Komodo-Stack gestoppt+destroyed, Repo-Pfad per `git rm` entfernt, Container weg (read-only verifiziert). Node-Eintrag in der Admin-Konsole noch zu entfernen. |
|
||||
|
||||
> **Befund 2026-06-06 (read-only auf dem Host ermittelt):** Der Host hat **zwei**
|
||||
> `tailscaled`-Prozesse:
|
||||
>
|
||||
> 1. **Native Unraid-Plugin** = `kallilabcore` (100.80.98.33). Prozess
|
||||
> `/usr/local/sbin/tailscaled -statedir /boot/config/plugins/tailscale/state
|
||||
> -tun tailscale1`. **Echtes TUN-Interface `tailscale1`, ist der Subnet-Router
|
||||
> fuer `192.168.178.0/24`**, laeuft seit 24. Mai, installiert via
|
||||
> `tailscale.plg` + `unraid-tailscale-utils`. State unter
|
||||
> `/boot/config/plugins/tailscale/state` → ueber das **Flash-Backup** gesichert.
|
||||
> Im ACL-Rollout `tag:server`. **Das ist die funktionale, kanonische Instanz.**
|
||||
> 2. **Docker-Stack** = `kallilab-core` (100.112.0.90), `host-services/tailscale/`.
|
||||
> Prozess `tailscaled --tun=userspace-networking` → **nur Userspace, kann
|
||||
> technisch nicht routen / kein Subnet-Router/Exit-Node sein**, advertised
|
||||
> nichts, kein Container teilt seinen Namespace, seit 31. Mai. State unter
|
||||
> `/mnt/user/appdata/tailscale`. Im ACL-Rollout untagged → isoliert.
|
||||
> **Hochwahrscheinlich redundant.**
|
||||
>
|
||||
> **Umgesetzt 2026-06-06:** Der redundante Docker-Stack `host-services/tailscale/`
|
||||
> wurde sauber per GitOps abgebaut — Komodo-Stack `tailscale` gestoppt+destroyed
|
||||
> (Operator), `git rm host-services/tailscale/`, Glance-Widget entfernt, und
|
||||
> Architektur-/Service-Catalog-/DR-/CLAUDE-Doku auf "natives Plugin" nachgezogen.
|
||||
> Read-only verifiziert: Container weg, nur noch der native `tailscaled` mit
|
||||
> `tailscale1`, Subnet-Route + Operator-Zugriff intakt. Offen: Node-Eintraege
|
||||
> `kallilab-core` und alter `baerchen` in der Admin-Konsole entfernen; State-Pfad
|
||||
> `/mnt/user/appdata/tailscale` bei Gelegenheit nach `_archive/` (kein Sofort-Loeschen).
|
||||
>
|
||||
> **Doku-Korrektur erledigt:** `docs/RESTORE_MATRIX.md` zeigt jetzt auf den
|
||||
> funktionalen State `/boot/config/plugins/tailscale/state` (im Flash-Backup)
|
||||
> statt auf den entfernten userspace-Docker-Pfad.
|
||||
|
||||
### Subnet-Router-Konsequenz
|
||||
|
||||
Weil `Kallilabcore` das LAN `192.168.178.0/24` als Subnet-Route anbietet, kann
|
||||
**jedes** Tailnet-Geraet mit Zugriff auf diese Route potenziell LAN-Dienste auf
|
||||
`192.168.178.0/24` erreichen — auch die Admin-Ports, die im LAN bewusst nur auf
|
||||
die Tailscale-IP gebunden sind, sind ueber die Subnet-Route adressierbar. Genau
|
||||
deshalb ist die ACL-Policy (unten) der eigentliche Schutzmechanismus und nicht
|
||||
nur der LAN-Bind.
|
||||
|
||||
Pruefkommando (auf dem Unraid-Host, read-only):
|
||||
Pruefkommando:
|
||||
|
||||
```bash
|
||||
tailscale status
|
||||
tailscale status --json | jq '{exitNode: .Self.ExitNodeOption, primaryRoutes: .Self.PrimaryRoutes, allowedIPs: .Self.AllowedIPs}'
|
||||
tailscale ip -4
|
||||
tailscale ip -6
|
||||
```
|
||||
|
||||
### ACL-Policy — ANGEWENDET 2026-06-06 (restriktive Tag-basierte grants)
|
||||
|
||||
**Status: live und verifiziert.** Die restriktive Policy wurde am 2026-06-06
|
||||
gemeinsam mit dem Operator in der lockout-sicheren Reihenfolge ausgerollt und
|
||||
read-only verifiziert (siehe "Rollout-Protokoll" unten). Ausgangspunkt war die
|
||||
**unveraenderte Default-Policy** im **`grants`-Schema** (eine Allow-all-Regel,
|
||||
keine Groups/Tags/`autoApprovers`); es gab also keinen eigenen Bestand zu
|
||||
erhalten.
|
||||
|
||||
> **Schema-Hinweis:** Dieses Tailnet nutzt das `grants`-Modell
|
||||
> (`{"src","dst","ip"}`), nicht das aeltere `acls`/`action:accept`-Modell.
|
||||
> Normaler SSH-Zugriff (`ssh kallilabcore` ueber OpenSSH Port 22) wird ueber
|
||||
> `grants` geregelt, nicht ueber den `ssh`-Block; letzterer betrifft nur die
|
||||
> Tailscale-SSH-Funktion.
|
||||
|
||||
**Angewendete Policy (live, kein Secret):**
|
||||
|
||||
```json
|
||||
{
|
||||
"tagOwners": {
|
||||
"tag:server": ["autogroup:admin"],
|
||||
"tag:operator": ["autogroup:admin"],
|
||||
"tag:family": ["autogroup:admin"]
|
||||
},
|
||||
"autoApprovers": {
|
||||
"routes": { "192.168.178.0/24": ["tag:server"] }
|
||||
},
|
||||
"grants": [
|
||||
{"src": ["tag:operator"], "dst": ["*"], "ip": ["*"]},
|
||||
{"src": ["tag:server"], "dst": ["tag:operator"], "ip": ["*"]},
|
||||
{"src": ["tag:family"], "dst": ["tag:server"], "ip": ["tcp:443"]}
|
||||
],
|
||||
"ssh": [
|
||||
{"action": "check", "src": ["autogroup:member"], "dst": ["autogroup:self"],
|
||||
"users": ["autogroup:nonroot", "root"]}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Geraete-Tags (live):** `kallilabcore` = `tag:server`; `baerchen-1` + `iphone-14`
|
||||
= `tag:operator`; `kallilab-core` (Docker) + alter `baerchen` bewusst untagged ->
|
||||
isoliert.
|
||||
|
||||
**Rollout-Protokoll 2026-06-06 (lockout-sicher, je Schritt read-only verifiziert):**
|
||||
|
||||
1. Policy additiv erweitert (Tags/grants definiert, Allow-all noch drin) -> alle Peers unveraendert verbunden, Route approved.
|
||||
2. `baerchen-1` getaggt `tag:operator` -> online, verifiziert.
|
||||
3. `iphone-14` getaggt `tag:operator` -> verifiziert.
|
||||
4. `kallilab-core` faktisch geprueft (Docker-Sidecar, keine Abhaengigen) -> bewusst untagged gelassen.
|
||||
5. Host `kallilabcore` getaggt `tag:server` -> Route blieb via `autoApprovers` automatisch approved, SSH ok.
|
||||
6. Allow-all entfernt -> restriktiv. Smoke-Tests gruen: Operator-SSH ok, AdGuard-Admin ueber Tailnet `HTTP 302`, Ping 0% Verlust, Route weiter approved; Host sieht nur noch die zwei Operator-Peers (untagged Nodes isoliert). LAN-Rueckweg durchgehend verfuegbar.
|
||||
|
||||
**Schema-/Erhaltungs-Hinweis fuer spaeter:** Die LAN-Subnet-Route
|
||||
`192.168.178.0/24` wird jetzt ueber `autoApprovers`/`tag:server` approved
|
||||
(vorher manuell). Es gibt keinen eigenen Bestand zu erhalten; die Policy oben
|
||||
ist die vollstaendige Wahrheit.
|
||||
|
||||
**Hintergrund / Designentscheidungen (2026-06-05/06):**
|
||||
|
||||
- Single-User-Realitaet: alle Nodes gehoeren demselben User `michaelkaleschke@`.
|
||||
Eine Differenzierung Operator/Familie ist nur ueber **Tags** moeglich, deshalb
|
||||
der Tag-Ansatz statt user-/gruppenbasiert.
|
||||
- Erster Rollout bewusst klein: nur `tag:server` + `tag:operator`.
|
||||
- **`tag:family` ist vorbereitet, aber schlafend:** Tag und eine konservative
|
||||
Minimal-Regel (`dst: tag:server`, `ip: tcp:443`) sind definiert, aber **kein
|
||||
Geraet traegt den Tag**, daher null Wirkung. Sobald ein echtes Familiengeraet
|
||||
dazukommt, wird es einmal mit `tag:family` getaggt und die Regel greift sofort
|
||||
— ohne Policy-Umbau. Vor dem ersten realen Familiengeraet die Regel auf die
|
||||
dann benoetigten Dienste/Ports pruefen.
|
||||
- Der `ssh`-Block bleibt der Default (Tailscale-SSH Check-Modus); normaler
|
||||
OpenSSH-Zugriff laeuft ueber die `grants` (Port 22, fuer `tag:operator` ueber
|
||||
`ip: ["*"]` abgedeckt).
|
||||
|
||||
**Offene Folgepunkte (kein Risiko, Hygiene/spaeter):**
|
||||
|
||||
- Familien-Dienste/Ports konkretisieren — erst wenn ein reales Familiengeraet dazukommt.
|
||||
- **Zwei-Tailscale-Konsolidierung: ERLEDIGT 2026-06-06** — redundanter Docker-Stack
|
||||
abgebaut, nur noch die native Plugin-Instanz `kallilabcore` (Subnet-Router) aktiv.
|
||||
- **Tailnet-Konsole aufraeumen: ERLEDIGT 2026-06-06** — Node-Eintraege `kallilab-core`
|
||||
und alter Offline-`baerchen` aus der Admin-Konsole entfernt.
|
||||
- State-Pfad `/mnt/user/appdata/tailscale` (vom entfernten Docker-Stack) bei
|
||||
Gelegenheit nach `_archive/tailscale-removed-2026-06-06/` (kein Sofort-Loeschen).
|
||||
- Optionaler Off-LAN-Routentest: von einem Operator-Geraet im Mobilfunk
|
||||
(nicht im Heim-LAN) ein LAN-Ziel ueber `192.168.178.0/24` erreichen, um die
|
||||
Subnet-Route end-to-end zu bestaetigen (im Heim-LAN nicht sauber isolierbar).
|
||||
|
||||
## Portfreigaben und Exposure
|
||||
|
||||
### FRITZ!Box (WAN -> Host)
|
||||
|
||||
Aktiver Soll-Stand nach Operator-Bereinigung und UI-Gegencheck 2026-06-01:
|
||||
Aktiver Soll-Stand nach Operator-Bereinigung 2026-05-28:
|
||||
|
||||
| Aktive Freigabe | Ziel | Zweck | Bemerkung |
|
||||
|---|---|---|---|
|
||||
@@ -217,26 +76,25 @@ Bewusst **nicht** freigegeben:
|
||||
|---|---|
|
||||
| `80/tcp` | Cloudflare-DNS-Challenge ersetzt HTTP-01; Traefik macht HTTP->HTTPS-Redirect nur LAN-seitig; WAN-`80` waere zusaetzliche Angriffsflaeche ohne Funktionsnutzen. **2026-05-28 in FRITZ!Box-UI entfernt**, Validierung: Mobilfunk-Test ergibt Timeout auf `http://vault.kaleschke.info`, `https://...` weiter erreichbar. |
|
||||
| `222/tcp` (Gitea SSH) | bewusst Tailscale-only: Operator-Pfad ist Tailscale, GitHub-Mirror deckt DR-Bootstrap ab, Gitea-Bundles sind off-host. Externe SSH-Brute-Force-Vektoren vermeiden. |
|
||||
| `32400/tcp` (Plex) | Plex wird extern ausschliesslich ueber `https://plex.kaleschke.info` via Traefik/443 erreicht. Kein direkter WAN-Port fuer Plex, Plex Remote Access bleibt aus. |
|
||||
|
||||
### UPnP / Selbstständige Portfreigaben
|
||||
|
||||
| Geraet | UPnP-Selbstfreigabe-Recht | Begruendung |
|
||||
|---|---|---|
|
||||
| `Kallilabcore` (192.168.178.58) | nicht erlaubt | Repo-managed; alle benoetigten Public-Ports sind explizite Freigaben |
|
||||
| `PC-192-168-178-71` / VONETS-Adapter (192.168.178.71, MAC 00:17:13:2F:61:96) | **2026-06-01 erneut geprueft und deaktiviert** | wahrscheinlich VONETS-WiFi-Bridge fuer SolarEdge-Wechselrichter; SolarEdge-Cloud-Sync ist ausschliesslich outbound, eingehende Ports sind nicht erforderlich |
|
||||
| `PC-192-168-178-71` / VONETS-Adapter (192.168.178.71, MAC 00:17:13:2F:61:96) | **2026-05-28 deaktiviert** | wahrscheinlich VONETS-WiFi-Bridge fuer SolarEdge-Wechselrichter; SolarEdge-Cloud-Sync ist ausschliesslich outbound, eingehende Ports sind nicht erforderlich |
|
||||
|
||||
Sollten neue Geraete UPnP-Selbstfreigaben anfordern, wird das hier als bewusste Ausnahme dokumentiert oder pro Geraet wieder deaktiviert.
|
||||
Sollten neue Geraete UPnP-Selbstfreigaben anfordern, wird das in `docs/MIGRATION_LOG.md` und hier als bewusste Ausnahme dokumentiert oder pro Geraet wieder deaktiviert.
|
||||
|
||||
Historischer UI-Befund vor Bereinigung vom 2026-05-27 (`Internet -> Freigaben -> Kallilabcore`):
|
||||
Aktueller UI-Befund vom 2026-05-27 (`Internet -> Freigaben -> Kallilabcore`):
|
||||
|
||||
| Beobachtung | Bewertung |
|
||||
|---|---|
|
||||
| `HTTP-Server`, TCP, extern `80/tcp` auf `192.168.178.58` | war Abweichung; **2026-05-28 entfernt** |
|
||||
| `HTTP-Server`, TCP, extern `80/tcp` auf `192.168.178.58` | Abweichung: fuer ACME/DNS-Challenge nicht erforderlich; sollte nach Operator-Freigabe entfernt werden, falls keine bewusste HTTP-WAN-Nutzung besteht |
|
||||
| `HTTPS-Server`, TCP, extern `443/tcp` auf `192.168.178.58` | entspricht Repo-Soll |
|
||||
| Keine `222/tcp`-Freigabe sichtbar | entspricht seit 2026-05-28 dem Soll: Gitea-SSH bleibt Tailscale-only |
|
||||
| Keine `222/tcp`-Freigabe sichtbar | Abweichung: Gitea-SSH ist extern nicht gemaess Soll erreichbar; nur anlegen, wenn Git-SSH aus dem Internet weiterhin gewuenscht ist |
|
||||
| Kallilabcore: keine selbststaendige Portfreigabe, kein IPv4-/IPv6-Exposed-Host sichtbar | entspricht Sicherheitsziel |
|
||||
| `PC-192-168-178-71`: selbststaendige Portfreigabe erlaubt, `0 aktiv` | **2026-06-01 deaktiviert**; danach nur noch `Kallilabcore` in der Portfreigabenliste sichtbar |
|
||||
| `PC-192-168-178-71`: selbststaendige Portfreigabe erlaubt, `0 aktiv` | keine aktive Freigabe, aber UPnP/PCP-Erlaubnis sollte bei Gelegenheit deaktiviert werden |
|
||||
|
||||
### Host (lokal beobachtbar)
|
||||
|
||||
@@ -244,11 +102,10 @@ Historischer UI-Befund vor Bereinigung vom 2026-05-27 (`Internet -> Freigaben ->
|
||||
|---:|---|---|---|
|
||||
| 80/tcp | Traefik | HTTP->HTTPS / ACME | nur LAN, keine WAN-Freigabe noetig |
|
||||
| 443/tcp | Traefik | HTTPS | WAN-Freigabe in FRITZ!Box erwartet |
|
||||
| 222/tcp | Gitea SSH | Git SSH | nur LAN/Tailscale; keine WAN-Freigabe |
|
||||
| 222/tcp | Gitea SSH | Git SSH | WAN-Freigabe in FRITZ!Box erwartet, dokumentierte Ausnahme |
|
||||
| 53/tcp+udp | AdGuard | DNS | LAN-only, dokumentierte Ausnahme |
|
||||
| 32400/tcp | Plex | Medienserver / Plex Web lokal | LAN/Tailscale direkt; extern nur via Traefik `https://plex.kaleschke.info`, keine WAN-Freigabe fuer 32400 |
|
||||
| 8082/tcp | AdGuard Admin | Admin UI | Bind nur `100.80.98.33:8082` (Tailscale), nicht im LAN exponiert |
|
||||
| 8181/tcp | InfluxDB 3 Core | Home Assistant / Ecowitt Writer | 2026-05-31 effektiv nur `127.0.0.1:8181`, nicht LAN-exponiert |
|
||||
| 8181/tcp | InfluxDB 3 Core | LAN Writer fuer Home Assistant | LAN-only, Bind-IP pruefen |
|
||||
|
||||
Pruefkommando:
|
||||
|
||||
@@ -261,9 +118,9 @@ docker ps --format "{{.Names}}: {{.Ports}}" | sort
|
||||
|
||||
| Netz | Status | Bemerkung |
|
||||
|---|---|---|
|
||||
| LAN | 192.168.178.0/24 | Hauptnetz, Host `192.168.178.58`, FRITZ!Box meldet 35 aktive Geraete |
|
||||
| LAN | 192.168.178.0/24 | Hauptnetz, Host `192.168.178.58`, FRITZ!Box meldet 36 aktive Geraete |
|
||||
| WLAN 2,4 / 5 GHz | aktiv, SSID `Fritzi` | Standard-WLAN, im LAN-Adressbereich, kein eigener Adressraum |
|
||||
| Gast-WLAN | aktiv, SSID `Fritzi Gastzugang` | FRITZ!Box-Gastnetz ist vom Heimnetz getrennt; Smoke 2026-06-06 vom iPhone bestaetigt keine Erreichbarkeit der getesteten LAN-/Admin-Ziele |
|
||||
| Gast-WLAN | **inaktiv** (FRITZ!Box-UI) | Solange inaktiv: kein Gast-Pfad zu LAN-Diensten; AdGuard-Admin-Trennung primaer ueber Tailscale-Bind statt Netzsegmentierung |
|
||||
| IoT-Netz | nicht existent | Keine VLAN-Trennung dokumentiert |
|
||||
| Tailscale | aktiv | Operator-Zugang, Host-IP `100.80.98.33` |
|
||||
| VLANs | nicht in Nutzung | FRITZ!Box 7590 kann VLAN-Tagging an einzelnen LAN-Ports; aktuell nicht konfiguriert |
|
||||
@@ -288,136 +145,14 @@ docker network inspect frontend_net | jq '.[0].Containers | keys'
|
||||
docker network inspect backend_net | jq '.[0].Internal'
|
||||
```
|
||||
|
||||
## SSH-Konfiguration Host
|
||||
|
||||
Geprueft 2026-06-06 (read-only), **gehaertet 2026-06-07** via `ssh root@192.168.178.58`.
|
||||
|
||||
| Parameter | Ist-Wert (effektiv via `sshd -T`, Stand 2026-06-07) | Soll | Status |
|
||||
|---|---|---|---|
|
||||
| `Port` | `22` | 22 | ok |
|
||||
| `PermitRootLogin` | `prohibit-password` | `prohibit-password` | **gehaertet 2026-06-07** |
|
||||
| `PasswordAuthentication` | `no` | `no` | **gehaertet 2026-06-07** |
|
||||
| `KbdInteractiveAuthentication` | `no` | `no` | **gehaertet 2026-06-07** (noetig wegen `UsePAM yes`) |
|
||||
| `PubkeyAuthentication` | `yes` | `yes` | ok |
|
||||
| `PermitEmptyPasswords` | `no` | `no` | ok |
|
||||
| `AuthorizedKeysFile` | `.ssh/authorized_keys` | `.ssh/authorized_keys` | ok |
|
||||
|
||||
**Hinterlegte SSH-Keys (root):** 3 Keys vorhanden (persistiert unter `/boot/config/ssh/root/authorized_keys`):
|
||||
- `root@Kallilabcore` (Host-eigener Key)
|
||||
- `michi@Baerchen` (Operator-Workstation)
|
||||
- `hetzner-storagebox-maintenance-2026-06-01` (Hetzner-Maintenance-Key)
|
||||
|
||||
**Durchgefuehrte Haertung (2026-06-07):** Root-Login ist jetzt key-only,
|
||||
Passwort- und Keyboard-Interactive-Auth sind serverseitig abgeschaltet.
|
||||
Verifiziert: frischer Key-Login `OK`; `ssh -o PreferredAuthentications=none`
|
||||
meldet `Authentications that can continue: publickey`; reiner Passwort-Versuch
|
||||
`Permission denied (publickey)`.
|
||||
|
||||
**Wichtig — Unraid-Persistenz:** `/etc/ssh/sshd_config` wird beim Boot aus dem
|
||||
OS-Image regeneriert (`rc.sshd`: `cp -f /boot/config/ssh/* /etc/ssh/`, danach
|
||||
`sshd_build`, das nur `Port`/`ListenAddress`/`AddressFamily` setzt). Die
|
||||
Unraid-GUI (**Settings → Management Access → SSH**) bietet nur `Use SSH`/`SSH port`
|
||||
an — **`PermitRootLogin`/`PasswordAuthentication` sind dort nicht einstellbar.**
|
||||
Persistiert wird daher **upgrade-sicher** ueber einen idempotenten Hook:
|
||||
|
||||
- `/boot/config/ssh-harden.sh` — setzt die drei Direktiven idempotent (bestehende
|
||||
aktive Zeile entfernen, genau einmal global vor dem ersten `Match`-Block einfuegen),
|
||||
`sshd -t`-Validierung, Reload nur per `kill -HUP` des Host-`sshd` bei valider Config.
|
||||
Idempotenz belegt: nach mehreren Laeufen je Direktive exakt 1 aktive Zeile, alte
|
||||
`PermitRootLogin yes` entfernt.
|
||||
- `/boot/config/go` — ruft `/bin/bash /boot/config/ssh-harden.sh` bei jedem Boot auf.
|
||||
|
||||
**Selbst-Verifikation (Syslog, rein informativ, keine Reparatur):** Das Skript
|
||||
schreibt nach jedem Lauf die effektiven Auth-Werte (`sshd -T`) nach syslog, z. B.
|
||||
`ssh-harden: VERIFY permitrootlogin prohibit-password pubkeyauthentication yes
|
||||
passwordauthentication no kbdinteractiveauthentication no`. Damit ist nach jedem
|
||||
Boot/Upgrade nachweisbar, ob die Haertung gegriffen hat.
|
||||
|
||||
**Post-Upgrade-/Reboot-Check** (manuell, einmal nach jedem Unraid-Upgrade):
|
||||
|
||||
```bash
|
||||
# A) Effektive Werte direkt abfragen (Soll: prohibit-password / no / no / yes)
|
||||
ssh root@192.168.178.58 "sshd -T | grep -Ei 'permitroot|passwordauth|kbdinteractive|pubkey'"
|
||||
# B) Oder die automatische VERIFY-Zeile im Syslog lesen (Unraid nutzt rsyslog -> /var/log/syslog, nicht logread)
|
||||
ssh root@192.168.178.58 "grep 'ssh-harden' /var/log/syslog | tail -3"
|
||||
```
|
||||
|
||||
Dieser Weg editiert die **jeweils aktuelle** von Unraid generierte Config nach und
|
||||
ueberlebt damit Unraid-Upgrades; findet er die Stock-Zeile nicht (z. B. weil eine
|
||||
neue Version schon `prohibit-password` ausliefert), macht der `sed` nichts und
|
||||
bricht den Boot nicht (fail-safe Richtung offen, nicht ausgesperrt). Bewusst
|
||||
**nicht** der oft empfohlene Weg einer kompletten `/boot/config/ssh/sshd_config`
|
||||
auf Flash — der wuerde die Stock-Config einfrieren und beim Upgrade neue Defaults
|
||||
verschlucken.
|
||||
|
||||
**Rollback:** `go`-Block + `/boot/config/ssh-harden.sh` entfernen, dann
|
||||
`cp /boot/config/ssh-harden.sshd_config.bak-20260607 /etc/ssh/sshd_config` und
|
||||
`kill -HUP $(cat /var/run/sshd.pid)`. Notzugang ueber Unraid-Konsole/GUI bleibt.
|
||||
|
||||
**Abgrenzung:** Ein zweiter `sshd` (`-D -e`) laeuft in einem Docker-Container
|
||||
(s6-overlay, moby-Namespace) und bindet **nicht** den Host-`:22`; eigene Config
|
||||
im Container, von dieser Haertung unberuehrt.
|
||||
|
||||
---
|
||||
|
||||
## Post-Upgrade Posture-Recheck — Unraid 7.3.1 (2026-06-07)
|
||||
|
||||
Nach dem Major-Upgrade **7.2.4 → 7.3.1** read-only die Host-Listener-Landschaft
|
||||
(`ss -tlnp`) gegen die dokumentierten Annahmen geprueft.
|
||||
|
||||
**Dokumentierte Ausnahmen verifiziert (alle weiterhin gueltig):**
|
||||
|
||||
| Dienst | Soll | Ist nach 7.3.1 | Status |
|
||||
|---|---|---|---|
|
||||
| InfluxDB 3 | nur `127.0.0.1:8181` | `127.0.0.1:8181` | ✅ |
|
||||
| AdGuard-Admin | nur Tailscale `100.80.98.33:8082` | `100.80.98.33:8082` | ✅ |
|
||||
| Gitea-SSH `222` | LAN/Tailscale, keine WAN-Freigabe | `0.0.0.0:222` (LAN/TS), WAN am Router zu | ✅ |
|
||||
| Traefik `80/443` | einziger Owner | docker-proxy (Traefik) allein | ✅ |
|
||||
| libvirt `:53` | darf nicht existieren | **weg** (Fix vom 2026-06-07 haelt) | ✅ |
|
||||
|
||||
**Docker-Socket (`/var/run/docker.sock`) — C-3-Kontext:**
|
||||
|
||||
| Container | Mount | Bewertung |
|
||||
|---|---|---|
|
||||
| komodo-periphery | **RW** | dokumentierte Ausnahme (Periphery startet/stoppt Container) |
|
||||
| traefik | ro | C-3: Direkt-Mount (ro), nicht ueber Socket-Proxy — offener Audit-Punkt, kein Regress |
|
||||
| glances / monitoring-promtail / glance-docker-socket-proxy | ro | unkritisch |
|
||||
|
||||
Keine neue RW-Socket-Exposure durch das Upgrade.
|
||||
|
||||
**Vorfall-Notiz AdGuard/DNS (Boot-Race, behoben 2026-06-07):** Das Upgrade hatte das
|
||||
ungenutzte **libvirt-Default-Netz** auf Autostart gebracht; dessen `dnsmasq` belegte
|
||||
beim Boot Port `53` **vor** AdGuard → AdGuards erster Start scheiterte am Bind und
|
||||
liess den Container ohne Netz-Anbindung (`Networks={}`, keine Ports) zurueck. Fix:
|
||||
`virsh net-autostart default --disable` + `virsh net-destroy default` (kein VM
|
||||
betroffen, Liste leer) + AdGuard-Container aus der Compose `--force-recreate`
|
||||
(re-attach `dns_net`, `:53` neu veroeffentlicht). DNS danach verifiziert aufloesend.
|
||||
`libvirtd` laeuft weiter nur auf `127.0.0.1:16509`.
|
||||
|
||||
**Empfehlung (Dauerfix):** Da keine VMs genutzt werden, **Unraid VM Manager → Enable
|
||||
VMs = No** — dann startet `libvirtd` gar nicht und der `:53`-Konflikt kann prinzipiell
|
||||
nicht wiederkehren. Bis dahin verhindert der abgeschaltete Autostart die Wiederkehr.
|
||||
|
||||
**Beobachtungen (kein Regress, Inventar):** SMB (`:445/:139`) und Plex (`*:32400`)
|
||||
lauschen auch auf der Tailscale-IP; durch die seit 2026-06-06 tag-restriktive
|
||||
Tailnet-ACL akzeptabel.
|
||||
|
||||
**SSH-Haertung nach Upgrade:** key-only root unveraendert aktiv und verifiziert
|
||||
(`prohibit-password`/`password no`/`kbd no`), go-Hook genau 1× gefeuert — siehe
|
||||
Abschnitt „SSH-Konfiguration Host".
|
||||
|
||||
---
|
||||
|
||||
## Offene Entscheidungen
|
||||
|
||||
| Thema | Status | Naechster Schritt |
|
||||
|---|---|---|
|
||||
| AdGuard Admin nur via Tailscale | live validiert 2026-05-26 | Compose bindet Admin-Port auf `100.80.98.33:8082`; DNS auf Port 53 funktioniert, LAN-Zugriff auf `192.168.178.58:8082` schlaegt fehl |
|
||||
| FRITZ!Box-Portfreigaben mit Repo-Soll abgleichen | **erledigt 2026-06-01** | Bereinigt: `80/tcp` entfernt (Cloudflare-DNS-Challenge ersetzt HTTP-01; Mobilfunk-Test bestaetigt Timeout auf `http://`, `https://` weiter ok). `222/tcp` bleibt bewusst nicht eingerichtet (Tailscale-only-Linie). UPnP-Selbstfreigaben sind aus. Aktiver Soll-Stand: ausschliesslich `443/tcp -> 192.168.178.58`. |
|
||||
| FRITZ!Box-Dienste aus dem Internet | **erledigt 2026-06-01** | `Internet -> Freigaben -> FRITZ!Box-Dienste`: HTTPS-Zugriff auf die FRITZ!Box aus dem Internet aus; FTP/FTPS auf Speichermedien aus. |
|
||||
| FRITZ!OS Update und Konfig-Backup | **erledigt 2026-06-01** | TR-064 meldet `154.08.25`; Konfig-Export liegt extern/off-system in Vaultwarden, Kennwort und Datei bleiben ausserhalb des Repos. |
|
||||
| Gast-/IoT-Zugriff auf Admin-Ports | **validiert 2026-06-06** | Runbook `docs/GUEST_IOT_NETWORK.md` und Checks `ops/maintenance/check-guest-iot-isolation.ps1` sowie `ops/maintenance/check-guest-iot-preflight.sh` vorhanden. LAN-Preflight von `baerchen` gruen: `192.168.178.58:8082` und `:8181` blockiert. Host-Preflight auf Unraid gruen, Report `/mnt/user/backups/restore-reports/guest-iot-preflight-2026-06-06-131316.md`. Gast-WLAN-Smoke per iPhone: `192.168.178.58:8082`, `:8181`, `:222`, `https://192.168.178.58` und `192.168.178.1` nicht erreichbar. |
|
||||
| IPv6 Exposure | technisch und per UI entschaerft | Public DNS liefert keine AAAA-Records fuer `*.kaleschke.info`; Host hat keine globale Provider-IPv6. TR-064 meldet IPv6-Firewall aktiv und Pinholes grundsaetzlich erlaubt; FRITZ!Box-UI zeigt keine aktiven IPv6-Freigaben, keine Admin-/SSH-Freigaben. |
|
||||
| WAN-Ausfallschutz | **geparkt: spaeter evaluieren** (Operator-Entscheidung 2026-06-05) | Mobilfunk-Stick-Failover an FRITZ!Box bleibt vorerst inaktiv. Folgen sind bewusst akzeptiert: Internet-Ausfall = ACME/DDNS pausieren, lokale Apps laufen weiter. Review-Trigger: haeufigere oder laengere DSL-Ausfaelle, oder wenn externer Remote-Zugang (statt nur lokalem Betrieb) geschaeftskritisch wird. Erst dann Mobilfunk-Failover technisch bewerten. |
|
||||
| Home Assistant InfluxDB Bind | validiert 2026-05-31 | `docker-proxy` bindet `127.0.0.1:8181`; keine LAN-Exposure. Wenn Home Assistant nicht lokal auf dem Host schreibt, braucht das eine bewusste Bind-Aenderung. |
|
||||
| SSH-Haertung Host | **erledigt 2026-06-07** | Root-Login key-only: `PermitRootLogin prohibit-password`, `PasswordAuthentication no`, `KbdInteractiveAuthentication no`. Live gesetzt + verifiziert (Key-Login ok, Passwort-Auth abgelehnt). Persistenz upgrade-sicher ueber `/boot/config/ssh-harden.sh` (idempotent, `sshd -t` vor Reload) aufgerufen aus `/boot/config/go`. GUI bietet diese Optionen nicht. Details im Abschnitt „SSH-Konfiguration Host". |
|
||||
| FRITZ!Box-Portfreigaben mit Repo-Soll abgleichen | **erledigt 2026-05-28** | Bereinigt: `80/tcp` entfernt (Cloudflare-DNS-Challenge ersetzt HTTP-01; Mobilfunk-Test bestaetigt Timeout auf `http://`, `https://` weiter ok). `222/tcp` bleibt bewusst nicht eingerichtet (Tailscale-only-Linie). UPnP-Selbstfreigabe-Recht fuer VONETS-Bridge (SolarEdge) deaktiviert. Aktiver Soll-Stand: ausschliesslich `443/tcp -> 192.168.178.58`. |
|
||||
| FRITZ!OS 8.21 Update | gemeldet | Operator-Aufgabe; vor Update kurzes Service-Fenster planen, weil Reboot WAN/Tailscale-Aufbau unterbricht |
|
||||
| Gast-/IoT-Zugriff auf Admin-Ports | aktuell entschaerft | Gast-WLAN ist inaktiv; bei Aktivierung muessen `192.168.178.58:8082`, `192.168.178.58:8181` und ggf. weitere LAN-Ports per FRITZ!Box-Kindersicherung/Netzwerk-Filter abgesichert werden |
|
||||
| IPv6 Exposure | offen | Router und Traefik/Cloudflare pruefen; Telekom-DSL liefert in der Regel IPv6, FRITZ!Box-Standard-Verhalten klaeren |
|
||||
| WAN-Ausfallschutz | bewusst nicht eingerichtet | Mobilfunk-Stick-Failover an FRITZ!Box ist nicht aktiv; Internet-Ausfall = ACME/DDNS pausieren, lokale Apps laufen weiter |
|
||||
| Home Assistant InfluxDB Bind | offen | Effektive Listener-Adresse pruefen |
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Aktuelle Restliste - KalliLab CORE
|
||||
|
||||
Stand: 2026-05-17
|
||||
|
||||
Diese Datei ersetzt die alte Sprint-Liste vom 2026-05-16. Die damaligen Backup-, Posture-, Logging- und Hardening-Bloecke sind weitgehend erledigt oder dokumentiert. Sie bleibt nur als kurze Restliste fuer die naechsten bewussten Arbeitspakete bestehen.
|
||||
|
||||
## Erledigt / nicht mehr offen
|
||||
|
||||
- Filebrowser-Hardening: breiter Appdata-Mount ist entfernt; Filebrowser mountet nur noch Documents, Photos, Projekte und eigenen App-State.
|
||||
- Authelia Argon2id-Haertung: `iterations: 3`, `memory: 65536`, `parallelism: 4`, `key_length: 32`, `salt_length: 16` sind gesetzt.
|
||||
- Gitea Webhook-Allowlist: `GITEA__webhook__ALLOWED_HOST_LIST` ist auf `komodo-core,localhost,127.0.0.1,192.168.178.0/24` eingeschraenkt.
|
||||
- Backup-Konsistenz: SQLite-/Nextcloud-Dumps, Borg-Scope fuer Nextcloud-Daten, Restore-Matrix und Freshness-Checks sind umgesetzt.
|
||||
- Posture-/Cert-/Drift-Checks: Skripte und Unraid User Scripts sind vorhanden und geplant.
|
||||
- Monitoring-Zielstack: `monitoring/` buendelt Prometheus, Loki, Promtail, Grafana, node-exporter, cAdvisor und InfluxDB 3 Core im Repo-Zielzustand.
|
||||
- Docker-Log-Rotation: Unraid-native Rotation ist dokumentiert; keine separate `/etc/docker/daemon.json` setzen.
|
||||
- Disk1-NTFS-Migration Phase 2: am 2026-05-25 abgeschlossen; Disk1 ist XFS, `posture-check` akzeptiert NTFS nicht mehr als Standard.
|
||||
|
||||
## Morgen / bewusst spaeter
|
||||
|
||||
- Monitoring live finalisieren:
|
||||
- Secrets `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json` auf dem Host pruefen/anlegen
|
||||
- `monitoring` in Komodo deployen
|
||||
- alte Stacks `ops/loki` und `ops/grafana-influxdb` nach erfolgreichem Smoke-Test stoppen
|
||||
- `https://monitoring.kaleschke.info`, Prometheus Targets, Loki-Logs und InfluxDB-Datasource pruefen
|
||||
- Home Assistant -> InfluxDB finalisieren:
|
||||
- HA-Token/Writer final pruefen
|
||||
- erste Messwerte in InfluxDB verifizieren
|
||||
- Grafana-HA-/Wetter-Dashboard in `monitoring-grafana` aufbauen
|
||||
- Hermes VM-Seite:
|
||||
- Runner-VM, echte `.env`, SSH-Key und Dashboard/Gateway final zusammenfuehren
|
||||
- NAS-Stack erst starten, wenn VM-Seite bereit ist
|
||||
|
||||
## Verbleibende bekannte Warnings
|
||||
|
||||
- `ddns-updater`, `glances`, `scrutiny`: nutzen noch `latest...@sha256`; spaeter durch konkrete Versionstags ersetzen, sofern upstream sinnvoll versioniert.
|
||||
- `ops/grafana-influxdb` und `ops/loki`: bleiben nur noch als Rollback-/Migrationsreferenz im Repo, nach Live-Migration nicht parallel betreiben.
|
||||
- `scrutiny`: bleibt `privileged: true`; dokumentierte SMART-Ausnahme, spaeter erneut pruefen.
|
||||
|
||||
## Regel
|
||||
|
||||
Neue Arbeit erst starten, wenn klar ist, ob sie eines der drei Morgen-Themen betrifft oder eine der bekannten Warnings bewusst abbaut.
|
||||
@@ -0,0 +1,140 @@
|
||||
# Zweites Offsite-Backup-Ziel - Entscheidungsvorlage
|
||||
|
||||
Status: **Operator-Entscheidung 2026-05-28: bewusst KEIN zweites Off-site.** Doku bleibt als Begruendungs-Anker und fuer zukuenftige Reviews.
|
||||
Audit-Bezug: `docs/AUDIT_2026-05-25.md` Finding **F-03** und `docs/AUDIT_2026-05-25_TODO.md` Sprint 7.
|
||||
|
||||
## Beschluss 2026-05-28
|
||||
|
||||
Aktuelle Backup-Topologie:
|
||||
|
||||
| Kopie | Wo | Medium | Standort |
|
||||
|---|---|---|---|
|
||||
| 1 | Live-Daten Unraid (Cache + Disk1) | NVMe + HDD | Heim |
|
||||
| 2 | Borg-Repo lokal `/mnt/user/backups/borg/` | HDD (Disk1) | Heim |
|
||||
| 3 | Borg-Repo Hetzner Storagebox | Hetzner | Off-site (DE) |
|
||||
| 4 | H:/ Nearline-Pull am Windows-PC | externe HDD | Heim |
|
||||
|
||||
**3-2-1-Regel ist erfuellt:** 4 Kopien, 3 Medien, 1 Off-site (Hetzner).
|
||||
|
||||
Ein zweites Off-site wuerde **ausschliesslich** das Szenario "Hetzner-Account verloren" zusaetzlich abdecken. Operator-Bewertung: Wahrscheinlichkeit niedrig (etablierter deutscher Anbieter mit Zahlungsweg), Aufwand und laufende Kosten unverhaeltnismaessig zur Risikoreduktion fuer ein privates Familien-Homelab.
|
||||
|
||||
Statt zweitem Off-site werden drei Hetzner-Account-Haertungen als Folge-TODOs gefuehrt:
|
||||
|
||||
1. Hetzner-Account: starkes, einzigartiges Passwort in Vaultwarden + Backup-Zahlungsweg (zweite Karte/SEPA) + Login-Benachrichtigungen per E-Mail. **Bewusst keine 2FA** (Operator-Entscheidung 2026-05-28 analog zur USV-Risiko-Akzeptanz; 2FA-Aufwand ueberwiegt die fuer ein Familien-Homelab realistische Risiko-Reduktion).
|
||||
2. Borg `--append-only`-Mode pruefen (Repo `appdata-critical` laeuft aktuell im Mode `full`). Setup erfolgt server-seitig in Hetzner `~/.ssh/authorized_keys` mit `command="borg serve --append-only"` fuer den Backup-Key. Schuetzt gegen client-seitige Ransomware, die das Repo loeschen wuerde.
|
||||
3. H:/ Pull als Windows Scheduled Task aktivieren (Anker `docs/H_DRIVE_NEARLINE_PULL.md`).
|
||||
|
||||
Diese drei Massnahmen zusammen schliessen den gleichen Risikoraum wie ein zweites Off-site, ohne neue Provider/Hardware/laufende Kosten.
|
||||
|
||||
## Review-Trigger
|
||||
|
||||
Diese Entscheidung wird neu bewertet, wenn:
|
||||
|
||||
- Hetzner-Account-Probleme tatsaechlich auftreten (Payment-Issue, Login-Sperre)
|
||||
- Hetzner als Anbieter strukturelle Probleme zeigt (Insolvenz-Geruechte, AGB-Aenderungen)
|
||||
- Im Homelab Daten mit deutlich hoeherem Wiederbeschaffungs-Aufwand dazukommen (z. B. Firefly-III-Finanz-Daten, Smart-Home-Langzeitdaten)
|
||||
- Operator-Praeferenzen sich aendern
|
||||
|
||||
Wenn dieser Trigger eintritt, sind die drei Optionen rsync.net / BorgBase EU2 / Cold-Wechselplatte weiter unten dokumentiert.
|
||||
|
||||
---
|
||||
|
||||
## Zweck
|
||||
|
||||
Aktuell laeuft das Off-site-Backup bei genau einem Anbieter (**Hetzner Storage Box**). Diese Vorlage stellt drei realistische Optionen fuer ein **zweites** Off-site-Ziel gegenueber. Die Entscheidung trifft der Operator; dieses Dokument trifft sie nicht.
|
||||
|
||||
`H:/` am Windows-PC bleibt **kein** Offsite-Ersatz (siehe `docs/CAPACITY_AND_LIFECYCLE.md`). H:/ ist Nearline-Kopie am gleichen Standort.
|
||||
|
||||
## Anforderungen an das zweite Ziel
|
||||
|
||||
| Anforderung | Begruendung |
|
||||
|---|---|
|
||||
| **anderer Anbieter als Hetzner** | Provider-Risiko (Account-Sperre, Insolvenz, Region-Outage) wird sonst nicht reduziert |
|
||||
| **anderer physischer Standort** als Unraid-Host | Brand-/Diebstahl-/Wasser-Schutz |
|
||||
| **Borg-kompatibel** (SSH + Repo-Layout) | bestehendes Borg-UI-Setup soll wiederverwendbar bleiben |
|
||||
| **bezahlbar im Privatrahmen** | grobe Zielgroesse: < 10 EUR / Monat fuer ~1 TB |
|
||||
| **stabil ueber Monate** | wenig Eingriff, keine taeglichen Quirks |
|
||||
| **keine Konto-Komplexitaet** | 2FA-Recovery muss sauber, ohne Telefon-Nummer-Hacks etc. moeglich sein |
|
||||
|
||||
## Drei Optionen
|
||||
|
||||
### Option A - rsync.net Borg-Plan
|
||||
|
||||
- **Was:** seit Jahren etablierter Anbieter mit dediziertem Borg-Plan (eingebaute `borg`-Binary, SSH-Account, Snapshot-Schutz).
|
||||
- **Zielanbindung:** `borg init --encryption=repokey-blake2 user@hostname:repo`.
|
||||
- **Standort:** Schweiz/USA (je nach Konto-Region).
|
||||
- **Preis (Stand 2026, grob):** ~10-15 USD pro Monat fuer 1 TB; Mindestbestelldauer keine.
|
||||
- **Vorteile:** Borg-First, ZFS-Snapshots als zusaetzlicher Schutz vor Repo-Loeschung, sehr lange Track-Record, keine SMB-/CIFS-Quirks.
|
||||
- **Nachteile:** USD-Preis, Standort ausserhalb EU je nach Konto, etwas teurer als reine Storage Boxes.
|
||||
- **Konto-Risiko:** unabhaengig von Hetzner-Konto.
|
||||
|
||||
### Option B - BorgBase EU2 (zweite Region beim gleichen Borg-Spezialisten)
|
||||
|
||||
- **Was:** BorgBase ist Borg-as-a-Service mit mehreren Regionen.
|
||||
- **Zielanbindung:** identisch zu bestehendem Borg-UI-Pfad.
|
||||
- **Standort:** zweite EU-Region als EU1.
|
||||
- **Preis (Stand 2026, grob):** ~10 EUR / Monat fuer ~1 TB.
|
||||
- **Vorteile:** identisches Borg-Modell, geringer Lernaufwand, einfache Web-UI.
|
||||
- **Nachteile:** Anbieter-Risiko nicht vollstaendig getrennt (gleicher Anbieter, andere Region). Bei Account-Sperre/Insolvenz waeren beide Ziele gleichzeitig betroffen.
|
||||
- **Konto-Risiko:** **gleicher** Anbieter, **anderes** Geo-Risiko.
|
||||
|
||||
### Option C - Rotierende Cold-Wechselplatte ausser Haus
|
||||
|
||||
- **Was:** zweite externe HDD (z. B. 2x WD Elements 4 TB), die im monatlichen Wechsel zwischen Heim-LAN und vertrauter dritter Person (Familie, Schliessfach, Buero) rotiert.
|
||||
- **Zielanbindung:** Borg-Repo lokal auf der eingesteckten Platte; Backup-Lauf nur wenn die Platte gerade vor Ort ist.
|
||||
- **Standort:** echtes Ausserhaus, dazwischen offline (Air-Gap).
|
||||
- **Preis (einmalig):** zwei Platten ~250 EUR, keine laufenden Kosten.
|
||||
- **Vorteile:** echtes Air-Gap, keine Provider-Abhaengigkeit, keine Bandbreitenfrage, keine Konto-Risiken.
|
||||
- **Nachteile:** manuelle Disziplin noetig, Recovery-Zeit haengt davon ab, dass die Platte gerade erreichbar ist. Nicht so taggenau wie Cloud-Borg.
|
||||
- **Konto-Risiko:** keines (keine Provider-Bindung).
|
||||
|
||||
## Bewertung gegen die Anforderungen
|
||||
|
||||
| Anforderung | Hetzner (Ist) | Option A rsync.net | Option B BorgBase EU2 | Option C Cold-Platte |
|
||||
|---|---|---|---|---|
|
||||
| Anderer Anbieter | - | ja | nein (gleicher) | ja (keiner) |
|
||||
| Anderer Standort | - | ja | ja | ja |
|
||||
| Borg-kompatibel | ja | ja | ja | ja |
|
||||
| Preis < 10 EUR/Monat | ja | grenzwertig | ja | einmalig ~250 EUR |
|
||||
| Stabilitaet | hoch | hoch | hoch | Operator-Disziplin abhaengig |
|
||||
| 2FA/Konto-Recovery | OK | OK | OK | n/a |
|
||||
|
||||
## Empfehlung (nicht Entscheidung)
|
||||
|
||||
Wenn der Operator die geringste Bedienung bei maximalem Provider-getrennten Schutz will: **Option A rsync.net**. Echte Anbieter-Trennung gegenueber Hetzner, Borg-First-Anbieter, ZFS-Snapshot-Schutz, keine zusaetzliche Hardware noetig.
|
||||
|
||||
Wenn Air-Gap und Null-Provider-Abhaengigkeit am wichtigsten sind und der Operator die monatliche Rotation tatsaechlich diszipliniert macht: **Option C Cold-Platte**.
|
||||
|
||||
**Option B (BorgBase EU2) wird nicht empfohlen** als zweites Ziel, weil das das Provider-Risiko nicht reduziert.
|
||||
|
||||
## Was vor einer Buchung zu tun ist
|
||||
|
||||
1. Operator-Entscheidung Option A vs. C dokumentieren (kein Provider-Kontakt vor Entscheidung).
|
||||
2. Falls Option A:
|
||||
- Konto bei rsync.net anlegen, Borg-Plan waehlen.
|
||||
- SSH-Key vom Borg-UI-Container exportieren bzw. dediziertes Key-Pair erzeugen.
|
||||
- `borg init` gegen das neue Repo durchfuehren (separate Passphrase oder gleiche - bewusst entscheiden).
|
||||
- Borg-UI um zweites Repository erweitern (separater Eintrag, kein Replace).
|
||||
- Schedule pruefen: erstes Vollbackup als One-Shot, danach inkrementell.
|
||||
- `docs/SECRETS_MAP.md` und `docs/EXTERNAL_DEPENDENCIES.md` um neuen Provider ergaenzen.
|
||||
- `docs/RESTORE_MATRIX.md` und `docs/STORAGE_LAYOUT.md` Backup-Ziel-Liste aktualisieren.
|
||||
3. Falls Option C:
|
||||
- zwei Platten beschaffen, Filesystem XFS oder ext4 (kein NTFS).
|
||||
- Rotations-Plan in `docs/STORAGE_LAYOUT.md` §8.1 ergaenzen.
|
||||
- Borg-Repo-Init pro Platte; Borg-UI um lokales Repo erweitern (nur aktiv wenn Platte eingesteckt).
|
||||
- Operator-Disziplin: monatliche Rotation als Kalender-Reminder.
|
||||
|
||||
## Was bewusst NICHT in dieser Vorlage steht
|
||||
|
||||
- Konkrete Hetzner-Konto-Daten, rsync.net-Accountnamen, IBANs, Telefonnummern. Diese Daten gehoeren nirgendwo in dieses Repo.
|
||||
- Borg-Passphrasen. Bleiben ausserhalb des Repos.
|
||||
- "Migrieren weg von Hetzner" als Option. Hetzner bleibt; das zweite Ziel ist Ergaenzung, nicht Ablosung.
|
||||
|
||||
## Offene Punkte
|
||||
|
||||
| Status | Punkt | Naechster Schritt |
|
||||
|---|---|---|
|
||||
| offen | Entscheidung Option A vs. C | Operator |
|
||||
| offen | Budget-Freigabe | Operator |
|
||||
| offen | Provider-/Hardware-Beschaffung | nach Entscheidung |
|
||||
| offen | Schedule-Anpassung in `ops/borg-ui` | nach Provider-Bereitstellung |
|
||||
@@ -1,73 +0,0 @@
|
||||
# Documentation Index
|
||||
|
||||
Typ: Einstieg/Index · Stand: 2026-06-11 · Status: aktiv
|
||||
|
||||
Diese Datei trennt aktive Betriebsdokumentation von historischer Arbeitsdoku.
|
||||
Neue operative Dokumente duerfen nur in `docs/` liegen, wenn sie heute als
|
||||
Einstieg, Runbook, Inventar, Entscheidung oder Statusliste gebraucht werden.
|
||||
Abgeschlossene Audits, Drills und Plaene wandern nach `archive/` oder werden
|
||||
geloescht (Git-Historie ist das Archiv). Verbindliche Doku-Regeln:
|
||||
`REPO_MAP.md` Abschnitt "Doku-Regeln".
|
||||
|
||||
## Pflicht-Einstieg
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `../README.md` | kurzer Repo-Einstieg |
|
||||
| `../AGENTS.md` | Einstiegspunkt fuer KI-Agenten (Codex u. a.) |
|
||||
| `../HOMELAB_ARCHITECTURE_MASTER_V2.md` | Architektur-Quelle fuer Netz, Zugriff und Ausnahmen |
|
||||
| `WORKFLOW.md` | verbindlicher GitOps-/No-Drift-Ablauf |
|
||||
| `REPO_MAP.md` | technische Landkarte des Repositories + Doku-Regeln |
|
||||
| `SERVICE_CATALOG.md` | produktiver Service-Katalog |
|
||||
| `DECISIONS.md` | Entscheidungs-Register (ADR-light) |
|
||||
| `MASTER_TODO.md` | einzige operative Statusliste |
|
||||
|
||||
## Betrieb und Recovery
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `DISASTER_RECOVERY.md` | Wiederanlauf nach Host-/Systemausfall |
|
||||
| `RESTORE_MATRIX.md` | Restore-Quellen, Dumps, Secrets, Smoke-Tests und Test-Reifegrad je Dienst |
|
||||
| `SERVICES_RECOVERY.md` | Gitea-/Komodo-/Services-Bootstrap |
|
||||
| `ROLLBACK.md` | Rueckweg bei GitOps-/Deploy-Fehlern |
|
||||
| `GITOPS_DRIFT_RUNBOOK.md` | Pflichtmatrix bei Drift zwischen Git, Komodo, Docker und Host |
|
||||
| `DR_WORKSTATION_SETUP.md` | DR-Gaming-PC einrichten (WSL2 + Borg-Client + SSH-Keys) |
|
||||
| `../ops/restore-tests/README.md` | Restore-Test-Betrieb, Skripte und Kadenz |
|
||||
|
||||
## Inventare und Policies
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `STORAGE_LAYOUT.md` | verbindliche Storage-/Share-/Pfad-Regeln |
|
||||
| `SECRETS_MAP.md` | Secret-Namen, Speicherorte und Einbindungsarten ohne Werte |
|
||||
| `AUTHELIA_OIDC_PLAN.md` | Plan & Runbook fuer app-uebergreifendes SSO via Authelia OIDC |
|
||||
| `HARDWARE_INVENTORY.md` | Host-, Disk-, SMART- und Power-Baseline |
|
||||
| `NETWORK_INVENTORY.md` | Router, DNS, Tailscale, Portfreigaben und Netzthemen |
|
||||
| `GUEST_IOT_NETWORK.md` | Sicherer Ablauf fuer FRITZ!Box-Gastnetz / IoT-Isolation |
|
||||
| `EXTERNAL_DEPENDENCIES.md` | Provider, Konten, DR-Workstation-Kit und externe Abhaengigkeiten |
|
||||
| `EXTERNAL_OPERATOR_RUNBOOK.md` | Hetzner-/Borg-/FRITZ!Box-Betreibercheck |
|
||||
| `CAPACITY_AND_LIFECYCLE.md` | Kapazitaet, Wachstum, Upgrade-Trigger, H:/-Nearline-Einordnung |
|
||||
|
||||
## Monitoring und Automatisierung
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `ALERT_RULES.md` | Prometheus-/ntfy-Regeln und Handlungslogik |
|
||||
| `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 |
|
||||
|
||||
## Nutzer- und Statusdoku
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `FAMILY_ONBOARDING.md` | familienverstaendliche Nutzungsdoku |
|
||||
| `AI_CONTEXT.md` | kompakter Kontext fuer KI-Agenten (Regeln + Pointer, kein Status) |
|
||||
| `homelab-optimierung.md` | technisches Optimierungs-Assessment 2026-06-10 (offene Empfehlungen) |
|
||||
|
||||
## Archiv
|
||||
|
||||
Abgeschlossene Snapshots, Drills und Audits: `archive/README.md`.
|
||||
Windows-Neuaufsetzen-Doku (Projekt abgeschlossen) liegt ebenfalls dort;
|
||||
aktiv geblieben sind nur Veeam-Baseline und Laufwerksstruktur unter
|
||||
`../ops/windows-reinstall/`.
|
||||
@@ -0,0 +1,89 @@
|
||||
# Recovery Handoff - KalliLab CORE - 2026-05-15
|
||||
|
||||
Zweck: Startpunkt fuer einen neuen Chat, ohne das komplette Repo erneut zu lesen.
|
||||
|
||||
## Kontext
|
||||
|
||||
- Incident: NTFS-Cache-Vorfall ab 2026-05-11.
|
||||
- Host: Unraid `Kallilabcore`, SSH `root@192.168.178.58`.
|
||||
- Root Cause: Cache war NTFS/ntfs3; Disk1 ist noch NTFS/ntfs3 und wird spaeter separat migriert.
|
||||
- Recovery-Prinzip: `docs/STORAGE_LAYOUT.md` ist bindend. Zum Zeitpunkt dieses Handoffs hiess die Datei noch `docs/STORAGE_LAYOUT.draft.md`.
|
||||
- Keine Stacks starten, wenn ein Pfad/Setting gegen Storage Layout, Restore Matrix oder Architecture Master verstoesst.
|
||||
|
||||
## Host-Zustand
|
||||
|
||||
- Cache wurde erfolgreich von NTFS auf XFS neu formatiert.
|
||||
- Verifiziert: `/mnt/cache` ist XFS auf `/dev/nvme0n1p1`.
|
||||
- Disk1 bleibt vorerst NTFS auf `/mnt/disk1`; Migration ist Phase 2 nach stabilem Cache-Betrieb.
|
||||
- Docker und Libvirt wurden nach dem Format wieder gestoppt.
|
||||
- `/mnt/user/appdata` ist leer bzw. nur Basisverzeichnis; produktive Appdaten sind noch nicht restored.
|
||||
- Share-Settings wurden nach Storage Layout korrigiert:
|
||||
- `appdata`, `system`, `domains`: cache `only`
|
||||
- `services`, `documents`, `photos`, `backups`, `media`, `finance`, `projekte`: cache `no`, include `disk1`
|
||||
- `isos`: cache `yes`
|
||||
- Backup alter Share-Configs: `/boot/config/shares.bak-20260515-pre-storage-layout`
|
||||
|
||||
## Image und Backups
|
||||
|
||||
- Full NVMe image liegt auf Windows `H:\kallilab-recovery\2026-05-14\nvme0n1-full-20260514.img`.
|
||||
- `dd` exit code war `0`; Image-Groesse/Padding geprueft; Source-Raw-Hash war fertig.
|
||||
- Image-Data-Hash wurde aus Zeitgruenden bewusst abgebrochen. Risiko wurde als ca. 1-3 Prozent eingeschaetzt.
|
||||
- Hetzner-Borg-Archiv `Taegliche-Sicherung-2026-05-10T04:30:52.050` wurde als lesbare Recovery-Quelle verifiziert.
|
||||
- Verifiziert wurden u. a. Vaultwarden SQLite, Gitea SQLite, Postgres-Dumps und Komodo Mongo-Archiv-Header.
|
||||
- Lokaler Verify-Auszug liegt unter `H:\kallilab-recovery\2026-05-14\borg-verify-may10`.
|
||||
|
||||
## Entscheidungen seit dem Cache-Rebuild
|
||||
|
||||
- WD MyBookLive Duo wird komplett aus dem Setup entfernt.
|
||||
- Backrest wird komplett aus dem aktiven Setup entfernt.
|
||||
- Borg ist alleinige Backup-Technologie.
|
||||
- Appdata Backup Plugin bleibt deaktiviert; WD-Ziele wurden aus aktiver Host-Konfiguration geleert.
|
||||
- Unassigned Devices SMB-Remote fuer `//MYBOOKLIVEDUO/Public` wurde aus aktiver Host-Konfiguration entfernt.
|
||||
- Backrest User Script `check_backrest_hetzner` wurde aus Schedule/Cron entfernt.
|
||||
- Host-Konfig-Backup fuer diese Bereinigung: `/boot/config/cleanup-backup-20260515-remove-wd-backrest`
|
||||
|
||||
## Repo-Aenderungen im aktuellen Arbeitsbaum
|
||||
|
||||
Backrest wurde aus dem aktiven Zielbild entfernt:
|
||||
|
||||
- `ops/backrest/docker-compose.yml` geloescht
|
||||
- `HOMELAB_ARCHITECTURE_MASTER_V2.md` aktualisiert
|
||||
- `docs/REPO_MAP.md` aktualisiert
|
||||
- `docs/SERVICE_CATALOG.md` aktualisiert
|
||||
- `docs/RESTORE_MATRIX.md` aktualisiert
|
||||
- `docs/AI_CONTEXT.md` aktualisiert
|
||||
- `docs/DISASTER_RECOVERY.md` aktualisiert
|
||||
- `ops/borg-ui/BACKUP_SCOPE.md` aktualisiert
|
||||
- `ops/hermes-agent/services.json` aktualisiert
|
||||
- `ops/hermes-agent/services.yaml` aktualisiert
|
||||
- `ops/policy-checks/last-report.md` aktualisiert
|
||||
|
||||
Verifikation:
|
||||
|
||||
- `rg "/mnt/(cache|disk1|disks|remotes)" -g docker-compose.yml -g compose.yaml -g *.yml -g *.yaml` findet keine aktiven Compose/YAML-Treffer.
|
||||
- `rg "ops/backrest|backrest.kaleschke|/mnt/user/appdata/backrest|192.168.178.86|MYBOOKLIVEDUO|WD-DUO"` findet nur historische/gewollte Hinweise.
|
||||
- `python -m json.tool ops/hermes-agent/services.json` ok.
|
||||
- `ops/hermes-agent/services.yaml` YAML ok.
|
||||
- `ops/policy-checks/check_repo.ps1` ok: 29 Compose-Dateien, 0 Critical, 4 Warnings.
|
||||
|
||||
## Wichtigste Stop-Regeln
|
||||
|
||||
- Keine Container starten, solange Core-Pfade oder Share-Settings nicht gegen Storage Layout geprueft sind.
|
||||
- Keine Backrest-/WD-Referenzen reaktivieren.
|
||||
- Keine Bind-Mounts auf `/mnt/cache`, `/mnt/disk1`, `/mnt/disks`, `/mnt/remotes`.
|
||||
- Keine Schreibaktionen auf Disk1 ausser bewusst noetig; Disk1 ist noch NTFS.
|
||||
- Komodo nur gemeinsam und explizit anfassen.
|
||||
- Erst Daten/Secrets restoren, dann Stacks einzeln starten und smoke-testen.
|
||||
|
||||
## Naechster sinnvoller Schritt
|
||||
|
||||
1. Repo-Aenderungen kurz reviewen und committen/pushen, bevor Komodo wieder produktiv wird.
|
||||
2. DNS-Basis wiederherstellen:
|
||||
- AdGuard: `/mnt/user/appdata/adguard/conf` aus Borg oder Image restoren; `work` kann frisch sein.
|
||||
- Unbound: `/mnt/user/appdata/unbound/config` aus Borg oder Image restoren.
|
||||
- Danach nur AdGuard + Unbound starten und DNS testen.
|
||||
3. Danach Traefik + Authelia + Gitea/Vaultwarden in kleinen Schritten.
|
||||
|
||||
## Startprompt fuer neuen Chat
|
||||
|
||||
Lies zuerst `docs/RECOVERY_HANDOFF_2026-05-15.md`, dann `docs/STORAGE_LAYOUT.md`, `docs/RESTORE_MATRIX.md` und nur die Compose-Dateien des naechsten betroffenen Stacks. Fuehre den KalliLab-CORE-Restore token-sparend fort. Nichts erfinden, keine Container starten, wenn etwas gegen Storage Layout verstoesst. Backrest und WD MyBookLive Duo sind entfernt und duerfen nicht wieder ins Setup.
|
||||
+9
-35
@@ -1,7 +1,7 @@
|
||||
# Renovate Bot - Self-hosted gegen Gitea
|
||||
|
||||
Status: **live seit 2026-05-29**; PAT, State-Verzeichnis und Cron sind auf dem Host aktiv.
|
||||
Audit-Bezug: Mai-2026-Audit Finding **F-12**.
|
||||
Status: **vorbereitet 2026-05-29**; PAT-Setup und Cron-Aktivierung sind Operator-Schritte.
|
||||
Audit-Bezug: `docs/AUDIT_2026-05-25.md` Finding **F-12**.
|
||||
|
||||
## Zweck
|
||||
|
||||
@@ -13,12 +13,12 @@ Bewusst kein Auto-Merge: jede PR braucht eine Operator-Sichtpruefung und einen M
|
||||
|
||||
- **Image:** `renovate/renovate:41` (versioniert, kein latest)
|
||||
- **Lauf:** ein-shot pro Cron-Tick, danach beendet sich der Container; persistente State liegt in `/mnt/user/services/renovate/state/`
|
||||
- **Schedule:** alle 6 Stunden per Unraid User-Script `renovate-six-hourly` (`20 */6 * * *`)
|
||||
- **Schedule:** alle 6 Stunden (User-Script `renovate-six-hourly`)
|
||||
- **Plattform:** Gitea via `https://git.kaleschke.info/api/v1`
|
||||
- **Authentifizierung:** Gitea-PAT als Host-Secret-Datei
|
||||
- **Konfiguration:** `renovate.json` im Repo-Root
|
||||
|
||||
## Operator-Setup (historisch, einmalig)
|
||||
## Operator-Setup (einmalig, ~10 Minuten)
|
||||
|
||||
### Schritt 1 - Service-Account in Gitea
|
||||
|
||||
@@ -27,9 +27,7 @@ Bewusst kein Auto-Merge: jede PR braucht eine Operator-Sichtpruefung und einen M
|
||||
- Username: `renovate`
|
||||
- E-Mail: ein gueltiges Postfach (Renovate sendet keine Mails, aber Gitea braucht eine Adresse)
|
||||
- Passwort: zufaellig, in Vaultwarden speichern
|
||||
3. Diesem User Schreibrechte fuer das Repo geben, das Renovate scannen soll: Repo `homelab-infra` -> Einstellungen -> Mitarbeiter -> `renovate` mit Permission `Schreibrechte` hinzufuegen.
|
||||
|
||||
**Wichtig:** Den Collaborator immer ueber die Gitea-UI/API hinzufuegen, nicht ueber direkten SQL-Insert. Die UI/API loest einen Permissions-Cache-Refresh aus; ein DB-Insert tut das nicht und fuehrt dazu, dass Renovate spaeter "Repository does not permit pull or push" meldet, obwohl die DB den Write-Mode kennt (Befund am 2026-05-29).
|
||||
3. Diesem User Schreibrechte fuer die Repos geben, die Renovate scannen soll. Einfachster Weg: dem User direkt Maintainer-Recht in jedem Repo unter `Micha/` geben (Settings -> Collaborators -> Add Collaborator -> `renovate` -> Permission `Write`).
|
||||
|
||||
### Schritt 2 - Access-Token erzeugen
|
||||
|
||||
@@ -87,43 +85,19 @@ Script: bash /mnt/user/services/homelab-infra/ops/renovate/run-renovate.sh
|
||||
|---|---|---|
|
||||
| Major-Updates | `groupName: major-updates`, `automerge: false` | Eine gesammelte PR pro Lauf mit allen Major-Updates, manueller Merge |
|
||||
| Minor + Patch + Digest fuer Docker-Compose | `groupName: minor-and-patch-updates`, `automerge: false` | Eine gesammelte PR; Operator merged manuell |
|
||||
| Tier-1-Datenhalter (Postgres, Mongo, Redis, Immich-Postgres) | `groupName: null`, eigener Label | Einzelne PRs ohne Group, hoehere Sichtbarkeit |
|
||||
| Tier-1-Datenhalter (Postgres, Mongo, Redis, pgvecto-rs) | `groupName: null`, eigener Label | Einzelne PRs ohne Group, hoehere Sichtbarkeit |
|
||||
| Komodo-Major-Updates | `enabled: false` fuer matchPackageNames + matchUpdateTypes major | Komodo bleibt auf `:2`, wird nicht versehentlich auf `:3` migriert |
|
||||
| Lock-File-Maintenance | `lockFileMaintenance.enabled: false` | Renovate macht keine reinen Lock-File-Refreshs |
|
||||
| Schedule | `extends ["schedule:weekly"]` | Renovate-Engine prueft, aber PRs/Updates folgen Wochen-Profilen wo sinnvoll |
|
||||
| Dependency Dashboard | aktiv | Gitea-Issue, die alle ausstehenden Updates auflistet |
|
||||
| Onboarding-PR | `onboarding: false` | Keine `Configure Renovate`-Onboarding-PR; wir nutzen die Repo-`renovate.json` direkt |
|
||||
| Ignore-Pfade | `_archive`, `ops/grafana-influxdb`, `ops/loki`, `ops/komodo` | Renovate scant alte/abgeloeste Stacks nicht; `ops/komodo` ist bewusst raus (siehe unten) |
|
||||
| Ignore-Pfade | `_archive`, `ops/grafana-influxdb`, `ops/loki` | Renovate scant alte/abgeloeste Stacks nicht |
|
||||
|
||||
## Ausnahme: komodo-Stack ist inline-verwaltet, nicht git-deployed
|
||||
|
||||
Der `komodo`-Stack (Komodo-Core/Mongo/Periphery, Datei `ops/komodo/docker-compose.yml`) wird **nicht aus diesem Repo deployed**. In Komodo ist der Stack als **inline `file_contents`** (UI-defined) gespeichert (`repo` leer, `files_on_host=false`, `has_inline_file_contents=true`) und hat bewusst `webhook_enabled=false`, damit Komodo sich nicht selbst per Webhook recreated (Bootstrap-/Henne-Ei-Fall).
|
||||
|
||||
Konsequenz: Ein Renovate-PR auf `ops/komodo/docker-compose.yml` wirkt zur Laufzeit **nicht** (Komodo deployt aus seiner Inline-Definition) und erzeugt nur Git↔Komodo-Scheinsicherheit. Deshalb steht `ops/komodo/**` in `ignorePaths`. Die Repo-Datei bleibt als Doku/Spiegel und traegt den aktuell real laufenden Digest.
|
||||
|
||||
Befund-Datum 2026-06-10: Renovate-PR #13 (mongo-8.0.23 Digest-Refresh) wurde gemergt, wirkte aber nicht; der Digest wurde im Repo auf den laufenden Stand zurueckgesetzt und der Pfad ausgenommen. Echte Updates des komodo-Stacks laufen bis auf Weiteres manuell ueber Komodo (Inline-Compose anpassen) bzw. spaeter via Migration auf git-backed (eigener Aenderungsblock).
|
||||
|
||||
## Aktueller Betriebsstand
|
||||
|
||||
Erstlauf 2026-05-29 erfolgreich: Renovate erzeugte das Dependency Dashboard und die ersten fuenf PRs. Diese wurden am 2026-05-31 manuell gemerged, deployed und danach in Gitea geschlossen. Die erledigten Branches wurden anschliessend remote geloescht:
|
||||
|
||||
- `renovate/mongo-7.0.32`
|
||||
- `renovate/postgres-17.9`
|
||||
- `renovate/minor-patch-updates`
|
||||
- `renovate/mongo-7.x`
|
||||
- `renovate/postgres-17.x`
|
||||
|
||||
Stand nach den 2026-05-31-Migrationen: PostgreSQL 18, Redis 8 und Immich-Postgres mit VectorChord sind produktiv ausgerollt und in `renovate.json` per `allowedVersions` auf die jeweiligen Major-/Image-Schienen begrenzt. Die Renovate-PRs #9 `renovate/postgres-18.x` und #10 `renovate/redis-8.x` wurden deshalb am 2026-05-31 geschlossen statt gemerged.
|
||||
|
||||
Grafana 13 wurde anschliessend manuell aus #7 `renovate/major-major-updates` uebernommen, vor dem Recreate mit `grafana.db`-/Plugin-Backup gesichert, auf `grafana/grafana:13.0.1` deployed und verifiziert (`/api/health` 13.0.1, 3 Datasources, 4 Dashboards in Unified Storage). #7 wurde danach geschlossen statt gemerged.
|
||||
|
||||
Komodo-Mongo laeuft bereits auf der erlaubten MongoDB-8.0-Schiene; ein offener Mongo-8-Renovate-PR ist aktuell nicht vorhanden.
|
||||
|
||||
## Erwartete erste PRs (historisch)
|
||||
## Erwartete erste PRs
|
||||
|
||||
Beim Erstlauf wird Renovate vermutlich PRs fuer einige der digest-gepinnten Images oeffnen, weil diese Digests seit Wochen nicht erneuert wurden. Reihenfolge der Sichtpruefung:
|
||||
|
||||
1. **Stateful Tier-1 zuerst, einzeln**: Postgres, Redis, Mongo, Immich-Postgres - jeder eigener PR, einzeln pruefen und mergen. Smoke-Test nach Merge ueber Komodo-Webhook-Deploy beobachten.
|
||||
1. **Stateful Tier-1 zuerst, einzeln**: Postgres, Redis, Mongo, pgvecto-rs - jeder eigener PR, einzeln pruefen und mergen. Smoke-Test nach Merge ueber Komodo-Webhook-Deploy beobachten.
|
||||
2. **Gruppe minor-and-patch-updates**: Alle anderen Docker-Compose-Images zusammen. Wenn der Diff vernuenftig aussieht, mergen.
|
||||
3. **Gruppe major-updates**: Erst nach Operator-Sichtpruefung pro Image, ggf. zurueckstellen oder manuell entscheiden.
|
||||
|
||||
|
||||
+236
-46
@@ -1,63 +1,253 @@
|
||||
# Repository Map
|
||||
|
||||
Stand: 2026-05-31
|
||||
Stand: 2026-05-23
|
||||
|
||||
Kurzkarte des Repositories. Diese Datei ist bewusst kein zweites Handbuch; fuer
|
||||
Details gilt immer die betroffene Compose-Datei oder das jeweilige Runbook.
|
||||
Diese Datei ist eine technische Landkarte des Repositories. Sie wurde aus Markdown-Dokumenten, `docker-compose.yml`-Dateien, Env-Beispielen, Traefik-Dynamic-Configs, Komodo/Periphery-Dateien und Skripten abgeleitet. Sie beschreibt den Repo-Sollzustand, nicht zwingend den Live-Zustand auf dem Host.
|
||||
|
||||
## Top-Level
|
||||
Secret-Werte werden hier nicht dokumentiert. Aufgefuehrt werden nur Variablennamen, Secret-Namen und Pfade.
|
||||
|
||||
## Ordnerstruktur
|
||||
|
||||
| Pfad | Zweck |
|
||||
|---|---|
|
||||
| `apps/` | produktive Anwendungen und vorbereitete App-Stacks |
|
||||
| `apps/` | Produktive Anwendungen und vorbereitete App-Stacks |
|
||||
| `core/` | Basisdienste, aktuell Gitea |
|
||||
| `docs/` | aktive Betriebsdoku, Restore, Inventare, Arbeitsregeln |
|
||||
| `env/` | nicht geheime Beispiel-Env-Dateien |
|
||||
| `host-services/` | host-nahe Dienste mit direkten Ports oder Host-Netz |
|
||||
| `docs/` | Betriebsdokumentation, Restore, Rollback, GitOps-Regeln |
|
||||
| `env/` | globale nicht geheime Beispiel-Env-Dateien |
|
||||
| `host-services/` | Host-nahe Dienste mit direkten Ports oder Host-Netz |
|
||||
| `infra/` | technische Infrastruktur wie PostgreSQL, Redis, DDNS |
|
||||
| `monitoring/` | Prometheus, Grafana, Loki, InfluxDB 3 Core |
|
||||
| `ops/` | Admin-, Backup-, Restore- und Wartungswerkzeuge |
|
||||
| `security/` | Authelia, Vaultwarden und Security-Konfiguration |
|
||||
| `services/` | Host-seitige Betriebsskripte und Recovery-Hilfen |
|
||||
| `traefik/` | Reverse Proxy und dynamic File-Provider-Konfiguration |
|
||||
| `ops/` | Operations-, Backup-, Monitoring- und Admin-Tools |
|
||||
| `services/` | Host-seitige Betriebsskripte und Recovery-kritische Service-Hilfen |
|
||||
| `security/` | Identity/Security-Dienste wie Authelia und Vaultwarden |
|
||||
| `traefik/` | Reverse Proxy Compose und dynamic File-Provider-Konfiguration |
|
||||
|
||||
## Einstiegspunkte
|
||||
## Wichtige Dokumente
|
||||
|
||||
| Datei | Wann lesen |
|
||||
| Datei | Bedeutung |
|
||||
|---|---|
|
||||
| `README.md` | Repo-Einstieg |
|
||||
| `HOMELAB_ARCHITECTURE_MASTER_V2.md` | Architektur, Netzmodell, Ausnahmen |
|
||||
| `docs/WORKFLOW.md` | vor operativen Aenderungen |
|
||||
| `docs/SERVICE_CATALOG.md` | Service-Zweck, Pfade, Besonderheiten |
|
||||
| `docs/DISASTER_RECOVERY.md` | echter Wiederanlauf |
|
||||
| `docs/RESTORE_MATRIX.md` | Restore-Quelle je Dienst |
|
||||
| `docs/SECRETS_MAP.md` | Secret-Namen und Pfade ohne Werte |
|
||||
| `docs/GITOPS_DRIFT_RUNBOOK.md` | Git/Gitea/Komodo/Docker/Host-Drift |
|
||||
| `docs/MASTER_TODO.md` | einzige operative Statusliste |
|
||||
| `docs/DECISIONS.md` | Entscheidungs-Register (ADR-light) |
|
||||
| `docs/DR_WORKSTATION_SETUP.md` | Schritt-fuer-Schritt-Runbook fuer den DR-Gaming-PC (WSL2 + Borg-Client + SSH-Keys) |
|
||||
| `docs/runbooks/komodo-bulk-deploy-dns.md` | Bulk-Deploy-Pulls scheitern an DNS, wenn AdGuard im selben Batch recreated wird |
|
||||
| `README.md` | Einstieg und Kurzueberblick |
|
||||
| `HOMELAB_ARCHITECTURE_MASTER_V2.md` | operative Architektur-Quelle fuer Netzwerk, Zugriff und Ausnahmen |
|
||||
| `docs/WORKFLOW.md` | GitOps-/No-Drift-Arbeitsregeln |
|
||||
| `docs/GITOPS_DRIFT_RUNBOOK.md` | Pflichtmatrix fuer Git/Gitea/Komodo/Docker/Host-Drift |
|
||||
| `docs/DISASTER_RECOVERY.md` | Wiederanlauf nach Host-/Systemausfall |
|
||||
| `docs/RESTORE_MATRIX.md` | Restore-Quellen, Dump-Artefakte und Smoke-Tests je Dienst |
|
||||
| `docs/SERVICES_RECOVERY.md` | Recovery-kritische `/mnt/user/services`-Pfade, Gitea-Mirror und Komodo-Bootstrap |
|
||||
| `docs/STORAGE_LAYOUT.md` | verbindliche Storage-/Share-/Pfad-Konstitution |
|
||||
| `docs/HARDWARE_INVENTORY.md` | Hardware-, Disk-, SMART-, USV- und Strom-Inventar |
|
||||
| `docs/NETWORK_INVENTORY.md` | Router, DNS, Tailscale, Portfreigaben und Netztrennung |
|
||||
| `docs/EXTERNAL_DEPENDENCIES.md` | Externe Provider, Konten, Ausfall-Szenarien und kritische Off-Repo-Abhaengigkeiten |
|
||||
| `docs/CAPACITY_AND_LIFECYCLE.md` | Capacity-Schwellen, Wachstum, Upgrade-Trigger und Restore-Zeitziele |
|
||||
| `docs/FAMILY_ONBOARDING.md` | Familienorientierte Nutzungsdoku ohne Operator-Details |
|
||||
| `docs/FAMILY_VIEW_DASHBOARD.md` | Spezifikation fuer das Grafana Family-View-Dashboard (Doku-only, kein JSON) |
|
||||
| `docs/RESTORE_DRILL_ROUTINE.md` | Quartalsweise Restore-Drill-Routine, Tier-Belegung, DR-Sanity-Check |
|
||||
| `docs/IMMICH_RESTORE_TEST.md` | Operator-Overview Immich-Restore-Test, Erstlauf 2026-05-27 erfolgreich |
|
||||
| `docs/RENOVATE.md` | Self-hosted Renovate gegen Gitea (Setup + Wartung) |
|
||||
| `docs/FRITZBOX_PORT_CORRECTION_PLAN.md` | Vorbereitungs-Doku fuer FRITZ!Box-Portfreigaben-Korrektur (kein Router-Eingriff) |
|
||||
| `docs/OFFSITE_BACKUP_OPTIONS.md` | Entscheidungsvorlage zweites Offsite-Backup-Ziel (rsync.net vs. BorgBase EU2 vs. Cold-Platte) |
|
||||
| `docs/AUDIT_2026-05-25_TODO.md` | Operative Arbeitsliste aus dem Audit vom 2026-05-25; Authelia-2FA bewusst geparkt |
|
||||
| `docs/ALERTING_MAP.md` | ntfy Topic-Konvention und Sender-Mapping fuer Homelab-Alerts |
|
||||
| `docs/ROLLBACK.md` | Rueckweg bei Fehlern im GitOps-Betrieb |
|
||||
| `docs/SECRETS_MAP.md` | Secret-Namen, Pfade und Einbindungsarten ohne Werte |
|
||||
| `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md` | Home Assistant -> InfluxDB 3 -> Grafana Ablauf |
|
||||
| `docs/AI_CONTEXT.md` | Gesamtverstaendnis fuer KI-Agenten |
|
||||
| `docs/SERVICE_CATALOG.md` | produktiver Service-Katalog |
|
||||
|
||||
## Wichtige Skripte
|
||||
## Relevante Nicht-Compose-Dateien
|
||||
|
||||
| Datei | Zweck |
|
||||
| Datei | Zweck / Hinweis |
|
||||
|---|---|
|
||||
| `ops/borg-ui/scripts/pre-backup-dumps.sh` | Dump-Erzeugung vor Borg |
|
||||
| `ops/borg-ui/scripts/gitea-bundle-mirror.sh` | Gitea-Bundles fuer DR |
|
||||
| `ops/restore-tests/run-restore-checks.sh` | Restore-Test-Einstieg |
|
||||
| `ops/restore-tests/schedule.md` | Restore-Test-Kadenz |
|
||||
| `services/posture-check/posture-check.sh` | Host-Posture-Check |
|
||||
| `services/posture-check/export-prometheus-textfile.sh` | Borg-/Container-/Drift-Metriken |
|
||||
| `services/authelia-diff.sh` | Authelia ACL Repo-zu-Host-Vergleich |
|
||||
| `ops/h-drive-nearline/pull-critical-backups.ps1` | H:/ Nearline-Pull |
|
||||
| `traefik/dynamic/middlewares.yml` | zentrale `secure-headers` und `authelia` ForwardAuth Middleware; manuelle Host-Sync-Ausnahme |
|
||||
| `traefik/dynamic/dashboards.yml` | leer; File-Provider-Platzhalter |
|
||||
| `traefik/dynamic/tls.yml` | leer; File-Provider-Platzhalter |
|
||||
| `security/authelia/configuration.yml` | versionierte Authelia-Baseline fuer nicht geheime ACL-/Session-/Storage-Einstellungen; manuelle Host-Merge-Pflicht, User-Daten, OIDC-Client-Konfiguration und Secret-Werte bleiben ausserhalb von Git |
|
||||
| `monitoring/prometheus/prometheus.yml` | Prometheus Scrape-Konfiguration fuer dedizierten Monitoring-Stack |
|
||||
| `monitoring/loki/loki-config.yml` | Loki Filesystem/Retention-Konfiguration fuer dedizierten Monitoring-Stack |
|
||||
| `monitoring/promtail/promtail-config.yml` | Promtail Docker-Socket-Discovery fuer dedizierten Monitoring-Stack |
|
||||
| `monitoring/grafana/provisioning/*` | Grafana Datasource-/Dashboard-Provisioning fuer Prometheus und Loki |
|
||||
| `ops/glance/config/glance.yml` | Glance Dashboard-Konfiguration fuer Homelab-Monitore, Internet-/DNS-/VPN-Widgets, Community-Widgets, Docker-Containergruppen, Zeitfortschritt, Host-Snapshot, Bookmarks und zweite Infrastruktur-Seite |
|
||||
| `ops/borg-ui/scripts/pre-backup-dumps.sh` | Host-seitiges Dump-Skript fuer PostgreSQL, SQLite-Container-Dumps und Komodo Mongo |
|
||||
| `services/posture-check/posture-check.sh` | Host-seitiger Posture-Check fuer Filesystem, Mover-Drift, NVMe-SMART, Fuellstand und ntfy-Alarmierung |
|
||||
| `services/posture-check/docker-critical-events.sh` | Host-seitiger Docker-Event-Watcher fuer kritische ntfy-Alarme |
|
||||
| `services/posture-check/posture_check.sh` | Kompatibilitaets-Wrapper fuer die historische Schreibweise aus `STORAGE_LAYOUT.draft.md` |
|
||||
| `ops/hermes-agent/config/hermes/config.yaml` | Hermes Agent Konfiguration mit Env-Platzhaltern |
|
||||
| `ops/hermes-agent/hermes.env.example` | Beispiel fuer Hermes `.env`; echte Datei liegt auf Host-Appdata |
|
||||
| `ops/hermes-agent/stack.env.example` | Beispiel fuer Hermes Stack-ENV; echte `stack.env` bleibt host-/komodoseitig und ist per `.gitignore` ausgeschlossen |
|
||||
| `monitoring/stack.env.example` | `INFLUXDB_BIND_IP` Default `127.0.0.1`; im Zielzustand fuer Home Assistant auf LAN-IP setzen |
|
||||
| `ops/komodo/stack.env.example` | Komodo Stack-ENV-Beispiel, Secret-Werte nicht enthalten |
|
||||
|
||||
## Doku-Regeln
|
||||
## Stack-Inventar
|
||||
|
||||
1. **Ein Fakt, ein Zuhause.** Status -> `docs/MASTER_TODO.md`; Entscheidungen -> `docs/DECISIONS.md`; Zielbild -> `HOMELAB_ARCHITECTURE_MASTER_V2.md`/Inventare/`SERVICE_CATALOG`; Ablauf -> genau ein Runbook; Beleg -> Host-Report (`/mnt/user/backups/restore-reports/`) oder Git-Commit. Alle anderen Stellen verlinken statt kopieren.
|
||||
2. **Erledigt = raus aus der Arbeitskopie.** Abgeschlossene Plaene, Sprints, Audits und Drills nach `docs/archive/` (Belege mit Referenzwert) oder loeschen (Sprint-Boards, erledigte Listen) - Git ist das Archiv.
|
||||
3. **Neue Datei nur mit klarem Typ:** Einstieg/Index, Architektur, Inventar/Referenz, Runbook, Entscheidung, Status oder befristeter Snapshot. Sonst ist es ein Eintrag in einer bestehenden Datei.
|
||||
4. **Done-Eintraege max. 3 Zeilen**, Details in Commit/Report; Kurzlog in `MASTER_TODO` max. 5 Eintraege.
|
||||
5. **Datum im Dateinamen nur fuer Snapshots**; datierte Dateien im `docs/`-Root sind per Definition Aufraeum-Kandidaten.
|
||||
6. **Index-Pflicht:** jede neue/geloeschte Doku-Datei aktualisiert `docs/README.md` im selben Commit.
|
||||
7. **Quartals-Gaertnern (~15 min):** Datiertes archivieren, Done-/Review-Logs kuerzen, tote Links pruefen.
|
||||
8. **Kopfzeile je Dokument:** `Typ: ... · Stand: YYYY-MM-DD · Status: ...`. Bestandsnamen (SCREAMING_SNAKE) bleiben; neue Dateien in Unterordnern in kebab-case.
|
||||
### Apps
|
||||
|
||||
| Stack | Compose | Services / Images | Traefik Hosts | Networks | Ports | Abhaengigkeiten |
|
||||
|---|---|---|---|---|---|---|
|
||||
| BentoPDF | `apps/bentopdf/docker-compose.yml` | `bentopdf` -> `bentopdfteam/bentopdf:2.8.4` | `pdf.kaleschke.info` | `frontend_net` | keine | Traefik + Authelia; COOP/COEP Middleware |
|
||||
| Immich | `apps/immich/docker-compose.yml` | `immich-server`, `immich-machine-learning`, `database`, `redis` | `immich.kaleschke.info` | `frontend_net`, `immich_default` | keine | `immich-server` depends on `database`, `redis` |
|
||||
| Mail Archiver | `apps/mail-archiver/docker-compose.yml` | `mail-archiver` -> `s1t5/mailarchiver@sha256:...` | `mail.kaleschke.info` | `frontend_net`, `backend_net` | keine | shared PostgreSQL via env connection string; Internet fuer IMAP |
|
||||
| Mealie | `apps/mealie/docker-compose.yml` | `mealie`, `mealie-postgres` | `mealie.kaleschke.info` | `frontend_net`, `mealie_internal` | keine | eigene PostgreSQL im internen Netz |
|
||||
| Nextcloud | `apps/nextcloud/docker-compose.yml` | `nextcloud`, `nextcloud-postgres`, `nextcloud-redis` | `cloud.kaleschke.info` | `frontend_net`, `nextcloud_internal` | keine | native Nextcloud-Auth; eigene DB und Redis |
|
||||
| ntfy | `apps/ntfy/docker-compose.yml` | `ntfy` -> `binwiederhier/ntfy:latest@sha256:...` | `ntfy.kaleschke.info` | `frontend_net` | keine | mobile Push via upstream `ntfy.sh` |
|
||||
| Paperless-ngx | `apps/paperless/docker-compose.yml` | `paperless` -> `ghcr.io/paperless-ngx/paperless-ngx:2.20.10` | `paperless.kaleschke.info` | `frontend_net`, `backend_net` | keine | shared PostgreSQL + Redis; DB/Redis via Stack ENV |
|
||||
| Paperless-GPT | `apps/paperless-gpt/docker-compose.yml` | `paperless-gpt` -> `icereed/paperless-gpt:v0.24.0` | `paperless-gpt.kaleschke.info` | `frontend_net` | keine | Paperless API, Ollama/LLM config |
|
||||
| Unbound | `apps/unbound/docker-compose.yml` | `unbound` -> `shaanmajid/unbound:latest@sha256:...` | keine | `dns_net` | keine | Upstream Resolver fuer AdGuard |
|
||||
|
||||
### Core / Security / Infra
|
||||
|
||||
| Stack | Compose | Services / Images | Traefik Hosts | Networks | Ports | Abhaengigkeiten |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Gitea | `core/gitea/docker-compose.yml` | `gitea` -> `docker.gitea.com/gitea:1.25.4@sha256:...` | `git.kaleschke.info` | `frontend_net` | `222:22/tcp` | SQLite in `/data`; SSH-Port ist dokumentierte Ausnahme; `github.com` ist als Mirror-Ziel erlaubt und externe DNS-Resolver sind gesetzt |
|
||||
| Authelia | `security/authelia/docker-compose.yml` | `authelia` -> `authelia/authelia:latest@sha256:...` | `auth.kaleschke.info` | `frontend_net`, `backend_net` | keine | PostgreSQL 17 Storage, Traefik ForwardAuth; bewusst ohne Redis-Session-Backend |
|
||||
| Vaultwarden | `security/vaultwarden/docker-compose.yml` | `vaultwarden` -> `vaultwarden/server:latest@sha256:...` | `vault.kaleschke.info` | `frontend_net` | keine | Datei-Persistenz, `ADMIN_TOKEN_FILE` |
|
||||
| ddns-updater | `infra/ddns-updater/docker-compose.yml` | `ddns-updater` -> `ghcr.io/qdm12/ddns-updater:latest@sha256:...` | keine | `frontend_net` | keine | Cloudflare/API-Internetbedarf |
|
||||
| PostgreSQL 17 | `infra/postgresql17/docker-compose.yml` | `postgresql17` -> `postgres:17.9@sha256:...` | keine | `backend_net` | keine | shared DB-Cluster |
|
||||
| Redis | `infra/redis/docker-compose.yml` | `Redis` -> `redis:7.4-alpine@sha256:...` | keine | `backend_net` | keine | primaer Paperless-Redis (App-Cache); historisch als "shared" angelegt, faktisch nur von Paperless genutzt; Passwort-Datei |
|
||||
|
||||
### Host Services
|
||||
|
||||
| Stack | Compose | Services / Images | Hosts | Networks | Ports / Mode | Abhaengigkeiten |
|
||||
|---|---|---|---|---|---|---|
|
||||
| AdGuard Home | `host-services/Adguard/docker-compose.yml` | `adguard` -> `adguard/adguardhome:v0.107.52` | keine Traefik-Route | `dns_net`, `frontend_net` | `53/tcp`, `53/udp`, `100.80.98.33:8082:80/tcp` | Unbound in `dns_net`; DNS-Port 53 ist direkte Ausnahme; Admin 8082 ist auf Tailscale-IP begrenzt |
|
||||
| Plex | `host-services/plex/docker-compose.yml` | `plex` -> `plexinc/pms-docker:1.43.1.10611-1e34174b1@sha256:...` | keine Traefik-Route | `network_mode: host` | host network | Medienserver; Host-Netz bleibt fuer Discovery / Plex GDM dokumentierte Ausnahme |
|
||||
| Tailscale | `host-services/tailscale/docker-compose.yml` | `Tailscale-Docker` -> `tailscale/tailscale:stable@sha256:...` | keine | `network_mode: host` | host network | VPN/Remote-Zugang |
|
||||
|
||||
### Operations
|
||||
|
||||
| Stack | Compose | Services / Images | Traefik Hosts | Networks | Ports | Abhaengigkeiten |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Borg UI | `ops/borg-ui/docker-compose.yml` | `borg-ui` -> `ainullcode/borg-ui:latest@sha256:...` | `borg.kaleschke.info` | `frontend_net` | keine | Borg repo, Dump-Scope, Restore-Ziel |
|
||||
| code-server | `ops/code-server/docker-compose.yml` | `code-server` -> `lscr.io/linuxserver/code-server:4.116.0@sha256:...` | `code.kaleschke.info` | `frontend_net` | keine | Passwort-Datei, Workspace-Mounts |
|
||||
| Filebrowser | `ops/filebrowser/docker-compose.yml` | `filebrowser` -> `filebrowser/filebrowser:v2.63.2@sha256:...` | `files.kaleschke.info` | `frontend_net` | keine | Documents/Photos/Projekte-Mounts, Admin-UI hinter Authelia |
|
||||
| Glance | `ops/glance/docker-compose.yml` | `glance` -> `glanceapp/glance:v0.8.4`, `glance-docker-socket-proxy` -> `tecnativa/docker-socket-proxy:v0.4.2` | `glance.kaleschke.info` | `frontend_net`, `glance_socket_net` | keine | Homelab-Dashboard mit Home- und Infrastructure-Seite, Monitor-, Community-, Docker-, Internet-/DNS-/VPN- und Server-Stats-Widgets; aktives Community-Widget: Immich; Docker-API nur ueber internen Socket-Proxy |
|
||||
| Glances | `ops/glances/docker-compose.yml` | `glances` -> `nicolargo/glances:latest-full@sha256:...` | `glances.kaleschke.info` | `frontend_net` | keine | Rootfs/Docker-Socket fuer Monitoring |
|
||||
| Monitoring | `monitoring/docker-compose.yml` | `monitoring-prometheus`, `monitoring-alertmanager`, `monitoring-alertmanager-ntfy-bridge`, `monitoring-blackbox-exporter`, `monitoring-loki`, `monitoring-promtail`, `monitoring-grafana`, `monitoring-node-exporter`, `monitoring-cadvisor`, `monitoring-influxdb3-core`, optional `monitoring-grafana-dashboard-importer` | `monitoring.kaleschke.info` | `frontend_net`, `monitoring_net`, `monitoring_influx_lan` | `monitoring-influxdb3-core`: `${INFLUXDB_BIND_IP:-127.0.0.1}:8181:8181` | zentraler Zielstack fuer Prometheus/Loki/Grafana/InfluxDB; Alertmanager sendet via ntfy-Bridge nach `homelab-alerts`; Blackbox ersetzt Uptime-Kuma-Checks nach Parallelphase; Promtail nutzt Docker socket read-only; Dashboard-Importer nur via `bootstrap`-Profil |
|
||||
| Hermes Agent | `ops/hermes-agent/docker-compose.yml` | `hermes-gateway`, `hermes-dashboard` -> local build from Dockerfile | `hermes.kaleschke.info` via `${HERMES_DASHBOARD_HOST}` | `hermes_net`, dashboard zusaetzlich `frontend_net` | `8642` nur expose intern | SSH runner, Home Assistant optional, LLM provider env; Dashboard hinter Authelia |
|
||||
| Komodo | `ops/komodo/docker-compose.yml` | `komodo-core`, `komodo-mongo`, `komodo-periphery` | `komodo.kaleschke.info` | `frontend_net`, `komodo_net` | keine | Mongo, Docker socket, `/mnt/user/services` workspace mount, Gitea DNS override |
|
||||
| Scrutiny | `ops/scrutiny/docker-compose.yml` | `scrutiny` -> `ghcr.io/starosdev/scrutiny:latest-omnibus@sha256:...` | `scrutiny.kaleschke.info` | `frontend_net` | keine | `privileged: true`, device mounts fuer SMART |
|
||||
| Speedtest Tracker | `ops/speedtest/docker-compose.yml` | `speedtest-tracker` -> `lscr.io/linuxserver/speedtest-tracker:1.13.12@sha256:...` | `speedtest.kaleschke.info` | `frontend_net` | keine | App key/admin env, SQLite/config path |
|
||||
|
||||
### Traefik
|
||||
|
||||
| Stack | Compose | Service / Image | Hosts | Networks | Ports | Abhaengigkeiten |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Traefik | `traefik/docker-compose.yml` | `traefik` -> `traefik:v3.6` | `traefik.kaleschke.info` | `frontend_net`, `backend_net` | `80:80/tcp`, `443:443/tcp` | Docker provider, Cloudflare DNS token secret, dynamic config |
|
||||
|
||||
## Traefik Hosts
|
||||
|
||||
| Host | Service | Zugriff |
|
||||
|---|---|---|
|
||||
| `auth.kaleschke.info` | Authelia | Auth provider / bypass fuer eigene Domain |
|
||||
| `borg.kaleschke.info` | Borg UI | Traefik + Authelia |
|
||||
| `cloud.kaleschke.info` | Nextcloud | Traefik, native App-Auth |
|
||||
| `code.kaleschke.info` | code-server | Traefik + Authelia |
|
||||
| `files.kaleschke.info` | Filebrowser | Traefik + Authelia |
|
||||
| `git.kaleschke.info` | Gitea Web | Traefik |
|
||||
| `glance.kaleschke.info` | Glance | Traefik + Authelia |
|
||||
| `glances.kaleschke.info` | Glances | Traefik + Authelia |
|
||||
| `hermes.kaleschke.info` | Hermes Dashboard | Traefik + Authelia |
|
||||
| `immich.kaleschke.info` | Immich | Traefik, native App-Auth |
|
||||
| `komodo.kaleschke.info` | Komodo | Traefik, native Komodo-Auth; keine pauschale ForwardAuth |
|
||||
| `mail.kaleschke.info` | Mail Archiver | Traefik + Authelia + App-Auth |
|
||||
| `mealie.kaleschke.info` | Mealie | Traefik |
|
||||
| `monitoring.kaleschke.info` | Monitoring Grafana | Traefik + Authelia |
|
||||
| `ntfy.kaleschke.info` | ntfy | Traefik |
|
||||
| `paperless.kaleschke.info` | Paperless-ngx | Traefik |
|
||||
| `paperless-gpt.kaleschke.info` | Paperless-GPT | Traefik + Authelia |
|
||||
| `pdf.kaleschke.info` | BentoPDF | Traefik + Authelia + COOP/COEP |
|
||||
| `scrutiny.kaleschke.info` | Scrutiny | Traefik + Authelia |
|
||||
| `speedtest.kaleschke.info` | Speedtest Tracker | Traefik + Authelia |
|
||||
| `traefik.kaleschke.info` | Traefik Dashboard | Traefik + Authelia |
|
||||
| `vault.kaleschke.info` | Vaultwarden | Traefik |
|
||||
|
||||
## Networks
|
||||
|
||||
| Network | Typ / Status | Nutzer |
|
||||
|---|---|---|
|
||||
| `frontend_net` | external bridge | Web-/Proxy-Netz fuer Traefik und alle gerouteten UIs |
|
||||
| `backend_net` | external/internal laut Architektur | PostgreSQL 17, Redis, Authelia, Paperless, Mail Archiver, Traefik |
|
||||
| `dns_net` | App-/Host-Netz | AdGuard Home und Unbound |
|
||||
| `immich_default` | Compose-intern, `internal: true` | Immich Server, ML, Postgres, Redis |
|
||||
| `mealie_internal` | Compose-intern; Laufzeitname mit Compose-Projektpraefix typischerweise `mealie_mealie_internal` | Mealie und Mealie Postgres |
|
||||
| `nextcloud_internal` | Compose-intern | Nextcloud, Nextcloud Postgres, Nextcloud Redis |
|
||||
| `monitoring_net` | Compose-/Stack-Netz bridge | Prometheus, Loki, Promtail, Monitoring-Grafana, node-exporter, cAdvisor; Traefik fuer Metrics-Scrape |
|
||||
| `monitoring_influx_lan` | Compose-intern bridge | InfluxDB Host-Port-Publishing fuer LAN Writer im zentralen Monitoring-Stack |
|
||||
| `glance_socket_net` | Compose-intern, `internal: true` | Glance und `glance-docker-socket-proxy`; keine Traefik-Anbindung |
|
||||
| `komodo_net` | Compose-intern, `internal: true` | Komodo Core, Mongo, Periphery |
|
||||
| `hermes_net` | Compose-intern bridge | Hermes Gateway/Dashboard |
|
||||
| `host` | Host-Netz | Tailscale; Plex als Repo-Compose-Stack unter `host-services/plex/` |
|
||||
|
||||
## Volumes und Datenpfade
|
||||
|
||||
| Bereich | Wichtige Pfade |
|
||||
|---|---|
|
||||
| Traefik | `/mnt/user/appdata/traefik/dynamic`, `/mnt/user/appdata/traefik/letsencrypt`, Cloudflare Secret |
|
||||
| Gitea | `/mnt/user/services/gitea/data` |
|
||||
| Authelia | `/mnt/user/appdata/authelia/config`, Authelia Secret-Dateien |
|
||||
| Vaultwarden | `/mnt/user/appdata/vaultwarden`, Admin-Token-Datei |
|
||||
| PostgreSQL 17 | `/mnt/user/appdata/postgresql17`, `postgres_password.txt` |
|
||||
| Redis | `/mnt/user/appdata/redis`, `redis_password.txt` |
|
||||
| Paperless | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/scans_inbox` |
|
||||
| Immich | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive`, `/mnt/user/appdata/immich_postgres`, `model-cache` |
|
||||
| Mealie | `/mnt/user/appdata/mealie/data`, `/mnt/user/appdata/mealie/postgres` |
|
||||
| Mail Archiver | `/mnt/user/appdata/mailarchiver/data-protection-keys` |
|
||||
| Nextcloud | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data`, `/mnt/user/appdata/nextcloud/postgres`, `/mnt/user/appdata/nextcloud/redis` |
|
||||
| Plex | `/mnt/user/appdata/plex/config`, `/mnt/user/appdata/plex/transcode`, `/mnt/user/media`, `/mnt/user/photos` |
|
||||
| ntfy | `/mnt/user/appdata/ntfy` |
|
||||
| Paperless-GPT | `/mnt/user/appdata/paperless-gpt/data`, `/mnt/user/appdata/paperless-gpt/prompts` |
|
||||
| AdGuard | `/mnt/user/appdata/adguard/work`, `/mnt/user/appdata/adguard/conf` |
|
||||
| Tailscale | `/mnt/user/appdata/tailscale` |
|
||||
| Borg UI | `/mnt/user/appdata/borg-ui/data`, `/mnt/user/appdata/borg-ui/cache`, `/mnt/user/backups/borg/dumps`, selected restore/source mounts |
|
||||
| code-server | `/mnt/user/appdata/code-server`, `/mnt/user/services/dev` |
|
||||
| Filebrowser | `/mnt/user/documents`, `/mnt/user/photos`, `/mnt/user/projekte`, Filebrowser database/config paths |
|
||||
| Glance | Repo-Konfiguration unter `ops/glance/config/glance.yml`; keine produktive Datenpersistenz; Docker-Socket nur am internen Proxy |
|
||||
| Glances | `/`, Docker socket, `/etc/os-release` |
|
||||
| Scrutiny | `/mnt/user/appdata/scrutiny/*`, `/run/udev`, selected `/dev/...` disks |
|
||||
| Speedtest | `/mnt/user/appdata/speedtest-tracker/config` |
|
||||
| Monitoring | named volumes `prometheus_data`, `loki_data`, `promtail_positions`, `grafana_data`; InfluxDB-Persistenz unter `/mnt/user/appdata/influxdb3/data` und `/mnt/user/appdata/influxdb3/plugins`; Provisioning im Repo unter `monitoring/grafana/provisioning`; Dashboards unter `monitoring/grafana/dashboards`; historische Altstandsdaten unter `/mnt/user/appdata/grafana`, `/mnt/user/appdata/loki` und `/mnt/user/appdata/alloy` nicht blind loeschen |
|
||||
| Hermes Agent | `/mnt/user/appdata/hermes-agent/data`, `/mnt/user/appdata/hermes-agent/ssh`, SSH private key path |
|
||||
| Komodo | `komodo_keys`, `/mnt/user/appdata/komodo/core`, `/mnt/user/appdata/komodo/mongo`, `/mnt/user/appdata/komodo/periphery`, `/mnt/user/services` |
|
||||
|
||||
## Secrets und Env-Hinweise
|
||||
|
||||
| Dienst / Stack | Secret-/Env-Hinweise ohne Werte |
|
||||
|---|---|
|
||||
| Traefik | `cloudflare_dns_api_token` als Docker Secret / `CF_DNS_API_TOKEN_FILE` |
|
||||
| Authelia | JWT, Session, Storage Encryption, Postgres Password via `_FILE` |
|
||||
| Vaultwarden | `ADMIN_TOKEN_FILE` |
|
||||
| PostgreSQL 17 | `POSTGRES_PASSWORD_FILE` |
|
||||
| Redis | Passwort-Datei und Startkommando |
|
||||
| Paperless | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS` als Komodo Stack ENV |
|
||||
| Immich | `IMMICH_DB_PASSWORD` Stack ENV; `immich_postgres_password.txt` fuer Postgres |
|
||||
| Mail Archiver | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` als Stack ENV |
|
||||
| Glance | `GLANCE_IMMICH_API_KEY`, `GLANCE_ADGUARD_USERNAME`, `GLANCE_ADGUARD_PASSWORD`, `GLANCE_SPEEDTEST_API_KEY` als Stack ENV fuer Community-/Live-Widgets |
|
||||
| Speedtest | `APP_KEY`, `ADMIN_PASSWORD` als Stack ENV |
|
||||
| Nextcloud | Admin User, Admin Password, Postgres Password via Secret-Dateien |
|
||||
| Komodo | `KOMODO_SECRET_KEY`, `KOMODO_WEBHOOK_SECRET`, `KOMODO_JWT_SECRET`, `KOMODO_MONGO_PASSWORD`, `KOMODO_PERIPHERY_PASSKEY`; Mongo Passwort-Datei |
|
||||
| Borg UI | Borg Credentials, Admin Login, SSH Keys in persistentem Appdata, nicht im Git |
|
||||
| Hermes Agent | provider keys, API server key, messaging tokens, Home Assistant token in Host `.env`; SSH private key als Host-Secret |
|
||||
| Monitoring | `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json` fuer zentrale Grafana-/InfluxDB-Funktionen; ersetzt Uptime Kuma fuer HTTP-Verfuegbarkeit |
|
||||
|
||||
## Skripte
|
||||
|
||||
| Skript | Ausfuehrungsort | Zweck |
|
||||
|---|---|---|
|
||||
| `ops/borg-ui/scripts/pre-backup-dumps.sh` | Unraid Host, nicht Borg-UI Inline-Hook | erzeugt aktuelle Dumps unter `/mnt/user/backups/borg/dumps/latest` |
|
||||
| `services/posture-check/posture-check.sh` | Unraid Host | schreibt `/mnt/user/services/posture-check/last.json` und alarmiert via ntfy bei Warning/Critical |
|
||||
| `services/posture-check/docker-critical-events.sh` | Unraid Host | beobachtet Docker `die`/`oom`/`kill` Events und alarmiert via `homelab-alerts` |
|
||||
|
||||
Das Skript liest Secret-Dateien auf dem Host und schreibt Dump-Artefakte. Bei Analyse niemals Secret-Inhalte ausgeben.
|
||||
|
||||
## Unsicherheiten / TODOs aus Repo-Sicht
|
||||
|
||||
- Echte `stack.env`- und `.env`-Dateien sind per `.gitignore` ausgeschlossen; nur `*.example`-Dateien gehoeren ins Repo.
|
||||
- Hardware-, Netzwerk- und Provider-Inventare sind initiale Templates und muessen nach einem Host-Audit mit echten Werten gefuellt werden.
|
||||
- Authelia-2FA-/OIDC-Aenderungen sind nach Audit 2026-05-25 bewusst geparkt und werden nicht als Sofortmassnahme behandelt.
|
||||
- Authelia `configuration.yml` ist Repo-Baseline fuer nicht geheime Einstellungen, wird aber nicht automatisch von Komodo auf den Host kopiert. Die produktive Host-Datei kann zusaetzliche OIDC-/Secret-Konfiguration enthalten; Aenderungen muessen manuell gemerged und validiert werden.
|
||||
- `backend_net` ist in der Architektur als `internal: true` beschrieben; einzelne Compose-Dateien referenzieren es external. Live-Netz-Attribute bei Drift-Fragen pruefen.
|
||||
- Einige Images bleiben trotz Digest-Pin semantisch auf mutable Tags (`latest@sha256`, `release@sha256`). Das ist bewusst dokumentiert, aber bei Updates gesondert pruefen.
|
||||
- Stateful Datenhalter sind seit 2026-05-05 bevorzugt mit Minor-/Patch-Tag plus Digest gepinnt; Redis-Caches wurden im Hardening-Sprint 2026-05-16 auf `redis:7.4-alpine@sha256:...` vereinheitlicht.
|
||||
- `scrutiny` bleibt `privileged: true`; dokumentierte Ausnahme, aber weiterhin pruefenswert.
|
||||
- `tailscale` nutzt Host-Netz, `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` als dokumentierte VPN-Ausnahme.
|
||||
- `monitoring-influxdb3-core` laeuft aktuell als `user: "0"`; UID/GID-Hardening nur als eigener Sprint.
|
||||
- Leere `.keep`-Platzhalter wurden entfernt; neue Verzeichnisse sollen erst mit konkretem Inhalt ins Repo.
|
||||
- `plex` ist als Repo-Compose-Stack unter `host-services/plex/` enthalten; `network_mode: host` bleibt die dokumentierte Discovery-Ausnahme.
|
||||
- BentoPDF kann je nach Live-Stand vorbereitet statt produktiv sein; Hermes Dashboard ist produktiv unter `hermes.kaleschke.info`.
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# Restore-Drill Routine - KalliLab CORE
|
||||
|
||||
Status: **verbindliche Routine (Doku-only)**, 2026-05-27.
|
||||
Audit-Bezug: `docs/AUDIT_2026-05-25.md` Sprint 7 "Restore-Lab-Drill quartalsweise dokumentieren".
|
||||
Verwandte Docs: `docs/RESTORE_MATRIX.md`, `docs/RESTORE_HANDBOOK.md`, `docs/DISASTER_RECOVERY.md`, `ops/restore-tests/schedule.md`.
|
||||
|
||||
## Ziel
|
||||
|
||||
Sicherstellen, dass die Backup-Kette nicht nur weiter laeuft, sondern auch **wiederherstellbar** ist. Restore-Tests werden nicht ad-hoc gemacht, wenn ein Problem auftritt, sondern in einer planbaren Kadenz, damit das Vertrauen ueber die Zeit waechst und Drift fruehzeitig auffaellt.
|
||||
|
||||
Diese Datei beschreibt nur die **Routine** (wann, was, wie pruefen). Die operativen Anleitungen pro Dienst stehen in `docs/RESTORE_HANDBOOK.md` und den dienstspezifischen Runbooks unter `ops/restore-tests/<dienst>-runbook.md`.
|
||||
|
||||
## Drei-Stufen-Modell
|
||||
|
||||
| Stufe | Frequenz | Aufwand | Ziel |
|
||||
|---|---|---|---|
|
||||
| Freshness-Check | woechentlich | Minuten | Backup-Artefakte sind frisch, Reports lesbar |
|
||||
| Mini-Restore | monatlich/quartalsweise | 15-60 Min | Ein konkreter Dienst wird in isoliertem Test-Lab restauriert |
|
||||
| DR-Sanity-Check | quartalsweise | 1-2 h | Reihenfolge, Doku, Tier-Reihenfolge in der DR-Doku gegen Realitaet pruefen |
|
||||
|
||||
## Bestaetigte Mini-Restores
|
||||
|
||||
Wenn ein Mini-Restore zum ersten Mal sauber durchlaeuft, wird er hier als Referenz gefuehrt. Der Eintrag wird **nicht** entfernt, wenn er wiederholt wird; stattdessen aendert sich der Datums-Stand.
|
||||
|
||||
| Dienst | Erster bestaetigter Lauf | Letzter Erfolg | Report | Repo-Skript |
|
||||
|---|---|---|---|---|
|
||||
| Vaultwarden | 2026-05-07 | 2026-05-07 | `/mnt/user/backups/restore-reports/vaultwarden-2026-05-07.md` | `ops/restore-tests/vaultwarden-restore-test.sh` |
|
||||
| Gitea | 2026-05-07 | 2026-05-07 | `/mnt/user/backups/restore-reports/gitea-2026-05-07.md` | `ops/restore-tests/gitea-restore-test.sh` |
|
||||
| Paperless | 2026-05-07 | 2026-05-07 | `/mnt/user/backups/restore-reports/paperless-2026-05-07.md` | `ops/restore-tests/paperless-restore-test.sh` |
|
||||
| Immich | **2026-05-27** | **2026-05-27** | `/mnt/user/backups/restore-reports/immich-2026-05-27.md` | `ops/restore-tests/immich-restore-test.sh` |
|
||||
|
||||
Bei jedem weiteren Lauf wird die Spalte "Letzter Erfolg" aktualisiert.
|
||||
|
||||
## Quartals-Kadenz
|
||||
|
||||
Ein Kalenderjahr enthaelt vier Quartals-Drills. Jeder Quartals-Drill besteht aus dem Mini-Restore eines anderen Tier-2-Dienstes plus einem DR-Sanity-Check der Tier-1-Dienste.
|
||||
|
||||
| Quartal | Mini-Restore | DR-Sanity-Check Fokus |
|
||||
|---|---|---|
|
||||
| Q1 (Januar-Maerz) | `paperless` | Tier-1-Reihenfolge, Posture-Check-Status, Borg-Frische-Alerts |
|
||||
| Q2 (April-Juni) | `immich` | Komodo-Bootstrap-Pfad, Gitea-Bundles, Secrets-Pfad-Inventur |
|
||||
| Q3 (Juli-September) | `mealie` oder `nextcloud` (Operator-Wahl) | DNS-Pfad (AdGuard/Unbound/Tailscale), Cert-Expiry-Sicht |
|
||||
| Q4 (Oktober-Dezember) | `vaultwarden` oder `gitea` (Operator-Wahl) | Externe Abhaengigkeiten (Cloudflare, Hetzner, GitHub-Mirror), Off-site-Zweitziel-Diskussion |
|
||||
|
||||
Diese Liste ist bewusst auf Tier-2 und Tier-1-Dienste fokussiert. Tier-3-Dienste (Filebrowser, Glances, Scrutiny, Speedtest, Glance) werden im Drill nicht explizit ausgefuehrt, weil sie rebuildbar sind oder keinen kritischen Datenbestand haben.
|
||||
|
||||
### Q2 2026 - Konkrete Belegung
|
||||
|
||||
- Mini-Restore: **Immich (erledigt 2026-05-27)**.
|
||||
- DR-Sanity-Check (offen, vor Quartalsende 2026-06-30): Komodo-Bootstrap-Pfad gegen `docs/SERVICES_RECOVERY.md` durchgehen, Gitea-Bundles ueber `ops/borg-ui/scripts/gitea-bundle-mirror.sh` auf Frische und Bundle-Klonbarkeit pruefen, Secrets-Inventur gegen `docs/SECRETS_MAP.md` abgleichen.
|
||||
|
||||
### Wer schiebt das an?
|
||||
|
||||
- **Operator** loest jeden Drill manuell aus, idealerweise am 2. Wochenende des ersten Monats im Quartal.
|
||||
- Es gibt **keinen** automatischen Host-Schedule fuer den Quartals-Drill. Die woechentliche Freshness-Pruefung und die monatlichen Mini-Restores in `ops/restore-tests/schedule.md` laufen separat.
|
||||
- Bei akuten Aenderungen (Major-Upgrade eines Dienstes, FS-Migration, Repo-Strukturaenderung): zusaetzlichen Ad-hoc-Drill ausserhalb der Quartals-Kadenz einplanen.
|
||||
|
||||
## Freshness-Check (woechentlich)
|
||||
|
||||
- Skript: `ops/restore-tests/check-restore-freshness.sh` (Host-Bash) bzw. `ops/restore-tests/check-restore-freshness.ps1` (Windows-Operator).
|
||||
- Erwartete Pruefungen:
|
||||
- Letzter Borg-Archiv-Stand juenger als die Schwellwerte aus `docs/STORAGE_LAYOUT.md` §11.
|
||||
- Kanonische Dump-Artefakte unter `/mnt/user/backups/borg/dumps/latest/` vorhanden und juenger als 26 h.
|
||||
- Letzte Report-Dateien unter `/mnt/user/backups/restore-reports/` lesbar.
|
||||
- Gitea-Bundles unter `/mnt/user/backups/git-bundles/gitea/` plausibel aktuell.
|
||||
|
||||
Ergebnis ist ein kurzes Konsolen-Log; bei Fehler greift die ntfy-Alarmierung aus `docs/ALERTING_MAP.md`.
|
||||
|
||||
## Mini-Restore (monatlich / bimonatlich)
|
||||
|
||||
Skripte folgen alle demselben Muster:
|
||||
|
||||
- isoliertes Test-Lab unter `/mnt/user/backups/restore-lab/<dienst>`
|
||||
- isolierte Test-Container `restoretest-*`
|
||||
- nur `127.0.0.1`-Ports, keine Traefik-Labels, keine produktive Domain
|
||||
- Smoke-Test mit Erfolgsregel "Container laeuft reicht nicht"
|
||||
- Report unter `/mnt/user/backups/restore-reports/<dienst>-YYYY-MM-DD.md`
|
||||
|
||||
Operative Anleitungen je Dienst:
|
||||
|
||||
- `ops/restore-tests/vaultwarden-runbook.md`
|
||||
- `ops/restore-tests/gitea-runbook.md`
|
||||
- `ops/restore-tests/paperless-runbook.md`
|
||||
- `ops/restore-tests/immich-runbook.md`
|
||||
|
||||
## DR-Sanity-Check (quartalsweise)
|
||||
|
||||
Der Sanity-Check ist **kein** echter Restore. Er ist eine Doku-/Konsistenz-Pruefung mit zehn Punkten:
|
||||
|
||||
1. `docs/DISASTER_RECOVERY.md` Phase 1-5 noch konsistent mit Repo und Live-Stand?
|
||||
2. `docs/RESTORE_MATRIX.md` Tier-Klassifizierung pro Dienst aktuell?
|
||||
3. `docs/SECRETS_MAP.md` Pfade existieren, Stack-ENV-only-Liste aktuell?
|
||||
4. `docs/SERVICES_RECOVERY.md` Komodo-Bootstrap-Pfad noch in Stufen A-F konsistent?
|
||||
5. Gitea-Bundle-Mechanik laeuft und letzter Bundle-Stand klonbar (`git clone .../homelab-infra.bundle /tmp/restore-test`)?
|
||||
6. Externe Mirrors (`michaelkaleschke-spec/homelab-infra` auf GitHub) gemaess `docs/EXTERNAL_DEPENDENCIES.md` noch erreichbar und aktuell?
|
||||
7. ntfy-Push-Pfad noch erreichbar? (Test-Nachricht an `homelab-info`.)
|
||||
8. Letzte vier Quartals-Mini-Restores im Report-Verzeichnis vorhanden?
|
||||
9. Borg-Repo-Passphrase Offline-Sicherung noch auffindbar? (Pruefung durch Operator, nicht durch Skript, kein Wert ablegen.)
|
||||
10. Capacity-Stand gegen Schwellen aus `docs/CAPACITY_AND_LIFECYCLE.md` abgeglichen?
|
||||
|
||||
Jeder Punkt wird in einem kurzen Quartals-Eintrag in `docs/MIGRATION_LOG.md` als `ok` / `Abweichung` / `Folgeaufgabe` festgehalten.
|
||||
|
||||
## Abbruch-Regeln
|
||||
|
||||
Wenn ein Drill fehlschlaegt, gilt die Stop-Regel aus `docs/WORKFLOW.md`:
|
||||
|
||||
- nach zwei fehlgeschlagenen Reparaturversuchen nicht weiterschreiben
|
||||
- stattdessen Pflichtmatrix aus `docs/GITOPS_DRIFT_RUNBOOK.md` durchgehen
|
||||
- Befund dokumentieren, naechsten Schritt mit dem Operator klaeren
|
||||
- erst danach den Drill erneut starten oder das Quartal als "Drill incomplete" markieren
|
||||
|
||||
## Berichte
|
||||
|
||||
- Mini-Restore-Reports liegen unter `/mnt/user/backups/restore-reports/<dienst>-YYYY-MM-DD.md`.
|
||||
- Quartals-Sanity-Checks landen als kurzer Block in `docs/MIGRATION_LOG.md`, nicht als eigenes Dokument.
|
||||
- Reports werden nicht aus dem Repo verlinkt, weil sie nicht im Repo liegen. Operator dokumentiert nur Vorhanden/Erfolg/Datum.
|
||||
|
||||
## Geltungsdauer
|
||||
|
||||
Diese Routine gilt ab Q2 2026. Bei groesseren Aenderungen (zweites Off-site, Authelia-OIDC-Aktivierung, Hardware-Migration) wird die Liste pro Quartal angepasst.
|
||||
@@ -0,0 +1,206 @@
|
||||
# Restore Handbook - KalliLab CORE
|
||||
|
||||
Stand: 2026-05-07
|
||||
|
||||
Dieses Handbuch ist die praktische Betriebsanleitung fuer Restore-Checks und Restore-Lab in KalliLab CORE.
|
||||
|
||||
Es ergaenzt:
|
||||
|
||||
- `docs/RESTORE_MATRIX.md`
|
||||
- `docs/DISASTER_RECOVERY.md`
|
||||
- `ops/restore-tests/*`
|
||||
|
||||
---
|
||||
|
||||
## 1. Ziel
|
||||
|
||||
Dieses Handbuch beantwortet vier Fragen:
|
||||
|
||||
1. Was ist die Restore-Quelle?
|
||||
2. Wo wird getestet?
|
||||
3. Wie pruefen wir Erfolg?
|
||||
4. Wie machen wir das regelmaessig mit wenig Handarbeit?
|
||||
|
||||
---
|
||||
|
||||
## 2. Grundmuster
|
||||
|
||||
Alle validierten Restore-Tests folgen demselben Muster:
|
||||
|
||||
- Quelle bleibt das produktive Borg-Repo bei Hetzner
|
||||
- Borg-Zugriff laeuft ueber den vorhandenen `borg-ui`-Container
|
||||
- Passphrase kommt aus `/mnt/user/appdata/secrets/borg_repo_passphrase.txt`
|
||||
- Testdaten landen unter `/mnt/user/backups/restore-lab/<dienst>`
|
||||
- Reports landen unter `/mnt/user/backups/restore-reports`
|
||||
- Testinstanzen laufen lokal ohne Traefik und ohne produktive Domain
|
||||
- nach Erfolg werden Testcontainer und Testdaten wieder entfernt
|
||||
|
||||
---
|
||||
|
||||
## 3. Bereits praktisch verifiziert
|
||||
|
||||
### Vaultwarden
|
||||
|
||||
- Report: `/mnt/user/backups/restore-reports/vaultwarden-2026-05-07.md`
|
||||
- Nachweis:
|
||||
- Borg-Restore erfolgreich
|
||||
- Testcontainer startete
|
||||
- Login-Seite war erreichbar
|
||||
|
||||
### Gitea
|
||||
|
||||
- Report: `/mnt/user/backups/restore-reports/gitea-2026-05-07.md`
|
||||
- Nachweis:
|
||||
- Borg-Restore erfolgreich
|
||||
- Web-UI antwortete
|
||||
- SSH-Port reagierte
|
||||
|
||||
### Paperless
|
||||
|
||||
- Report: `/mnt/user/backups/restore-reports/paperless-2026-05-07.md`
|
||||
- Nachweis:
|
||||
- Borg-Datei-Restore erfolgreich
|
||||
- Paperless-Dump aus Borg importiert
|
||||
- Login-Seite war erreichbar
|
||||
- Test-DB enthielt `25` Dokumente
|
||||
|
||||
---
|
||||
|
||||
## 4. Verzeichnisstruktur
|
||||
|
||||
### Produktiv
|
||||
|
||||
- `/mnt/user/appdata`
|
||||
- `/mnt/user/services`
|
||||
- `/mnt/user/documents`
|
||||
- `/mnt/user/backups/borg/dumps/latest`
|
||||
|
||||
### Restore-Lab
|
||||
|
||||
- `/mnt/user/backups/restore-lab/vaultwarden`
|
||||
- `/mnt/user/backups/restore-lab/gitea`
|
||||
- `/mnt/user/backups/restore-lab/paperless`
|
||||
|
||||
### Reports
|
||||
|
||||
- `/mnt/user/backups/restore-reports`
|
||||
|
||||
---
|
||||
|
||||
## 5. Restore-Frequenz
|
||||
|
||||
- jeden Montag, 06:30:
|
||||
- Frische-Check fuer Dumps und Reports
|
||||
- 1. Samstag im Monat, 07:00:
|
||||
- Vaultwarden
|
||||
- 3. Samstag im Monat, 07:00:
|
||||
- Gitea
|
||||
- jeder 2. Monat, 2. Samstag, 08:00:
|
||||
- Paperless
|
||||
|
||||
---
|
||||
|
||||
## 6. Betriebsmodi
|
||||
|
||||
### V1
|
||||
|
||||
- validierte Bash-Host-Jobs
|
||||
- Host-Job-Definitionen liegen im Repo
|
||||
- Scheduler kann bereits echte Frische- und Restore-Checks fahren
|
||||
- `ntfy` und Hermes-Auswertung folgen danach
|
||||
|
||||
### V2
|
||||
|
||||
- `ntfy` bei Erfolg/Fehler
|
||||
- Hermes liest Reports und baut Uebersichten
|
||||
- zusaetzliche Rotation, Sammelreports und weitere Dienste
|
||||
|
||||
---
|
||||
|
||||
## 7. User Script Jobs auf Unraid
|
||||
|
||||
Die Vorlagen stehen in:
|
||||
|
||||
- `ops/restore-tests/unraid-user-scripts.md`
|
||||
|
||||
Host-Repo-Pfad:
|
||||
|
||||
```text
|
||||
/mnt/user/services/homelab
|
||||
```
|
||||
|
||||
V1-Jobs:
|
||||
|
||||
1. `restore-freshness-weekly`
|
||||
2. `restore-vaultwarden-monthly`
|
||||
3. `restore-gitea-monthly`
|
||||
4. `restore-paperless-bimonthly`
|
||||
|
||||
---
|
||||
|
||||
## 8. Erfolgskriterien
|
||||
|
||||
Ein Restore-Test gilt nur dann als erfolgreich, wenn:
|
||||
|
||||
- Restore-Quelle lesbar war
|
||||
- Daten im Restore-Lab ankamen
|
||||
- Testcontainer startete
|
||||
- Smoke-Test erfolgreich war
|
||||
- Report geschrieben wurde
|
||||
|
||||
Nur `Container laeuft` reicht nicht.
|
||||
|
||||
---
|
||||
|
||||
## 9. Sicherheitsregeln
|
||||
|
||||
- keine produktiven Pfade beschreiben
|
||||
- keine produktiven Container fuer Restore-Tests verwenden
|
||||
- keine produktiven Domains fuer Testinstanzen verwenden
|
||||
- keine Secrets im Repo
|
||||
- keine Restore-Automatik fuer neue Dienste ohne bewusste Freigabe
|
||||
|
||||
---
|
||||
|
||||
## 10. Schnellstart
|
||||
|
||||
### Frische-Check
|
||||
|
||||
Auf dem Unraid-Host:
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab/ops/restore-tests/run-restore-checks.sh freshness
|
||||
```
|
||||
|
||||
### Vaultwarden Restore-Check
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab/ops/restore-tests/run-restore-checks.sh vaultwarden
|
||||
```
|
||||
|
||||
### Gitea Restore-Check
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab/ops/restore-tests/run-restore-checks.sh gitea
|
||||
```
|
||||
|
||||
### Paperless Restore-Check
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab/ops/restore-tests/run-restore-checks.sh paperless
|
||||
```
|
||||
|
||||
### Optional mit `ntfy`
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab/ops/restore-tests/run-restore-job-with-ntfy.sh freshness homelab-info
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Naechste Ausbaustufen
|
||||
|
||||
1. Vollautomatik fuer Vaultwarden, Gitea und Paperless
|
||||
2. `ntfy`-Meldungen fuer Erfolg/Fehler
|
||||
3. Hermes-Zusammenfassung ueber vorhandene Reports
|
||||
4. naechster Referenz-Restore fuer `mail-archiver` oder `mealie`
|
||||
+19
-78
@@ -28,23 +28,15 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`.
|
||||
|---|---|---|---|---|---|---|
|
||||
| Unraid OS Flash | Borg-Artefakt + optional Unraid Connect | `/boot/config` aus `unraid-flash-config.tar.gz` | `unraid-flash-config.tar.gz`, `.sha256`, Manifest | enthaelt sensible Host-Konfiguration, wie Secret-Material behandeln | Unraid USB Flash Creator / neuer Boot-Stick | Unraid bootet, Array-Zuordnung und Shares sind sichtbar |
|
||||
| Traefik | Share / Borg | `/mnt/user/appdata/traefik`, besonders `dynamic/`, `letsencrypt`, `secrets` | keine eigene DB | `cloudflare_dns_api_token` | `frontend_net`, `backend_net` | `https://traefik.kaleschke.info` erreichbar, Dashboard ueber Authelia |
|
||||
| AdGuard Home | Share / Borg | `/mnt/user/appdata/adguard/conf` | keine | keine zusaetzlichen Repo-Secrets dokumentiert | `dns_net`, `frontend_net` | DNS-Aufloesung funktioniert; Restore-Smoke am 2026-06-06 erfolgreich |
|
||||
| Tailscale | Flash-Backup (funktional) / Share | **Funktional: `/boot/config/plugins/tailscale/state`** (native Unraid-Plugin-Instanz `kallilabcore`, Subnet-Router, im Flash-Backup gesichert). Der frueher hier genannte Pfad `/mnt/user/appdata/tailscale` gehoert zum **userspace-only Docker-Stack** `kallilab-core` (redundant, Abbau geplant — siehe `docs/NETWORK_INVENTORY.md`) | keine | Tailscale-State im jeweiligen State-Pfad | Host-Netz | Tailscale verbunden, Subnet-Route `192.168.178.0/24` aktiv |
|
||||
| PostgreSQL 18 | Share + Dumps | `/mnt/user/appdata/postgresql18` (archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/postgresql17`) | `postgresql17-globals.sql`, `postgresql17-mailarchiver.dump`, `postgresql17-paperless.dump`, optional `postgresql17-authelia.dump` | `postgres_password.txt`, App-Rollen-Passwoerter aus den jeweiligen Stack-ENV/Secret-Dateien | `backend_net` | DB startet, Ziel-Datenbanken vorhanden; `SHOW data_checksums` ist `on` |
|
||||
| Redis 8 | Share / Host | `/mnt/user/appdata/redis`; Rollback-Backup unter `/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-<ts>` | RDB/AOF-Dateien im Datenpfad | `redis_password.txt` | `backend_net` | Redis startet, `redis_version` ist 8.x, Apps verbinden sich; Restore-Smoke am 2026-06-06 erfolgreich |
|
||||
| Authelia | Borg | `/mnt/user/appdata/authelia/config`, `/mnt/user/appdata/secrets/*authelia*` | Shared PostgreSQL 18, optional Dump `postgresql17-authelia.dump` | JWT/Session/Storage/Postgres-/SMTP-Secret-Dateien | PostgreSQL 18, Traefik, GMX SMTP | Login-Seite und ForwardAuth funktionieren; SMTP-Notifier startet; aktive Sessions werden nach Restart neu aufgebaut; Restore-Smoke am 2026-06-03 erfolgreich: Config aus Borg, minimale Test-Config, frisches Test-Postgres, HTTP `/api/health` 200, Report `/mnt/user/backups/restore-reports/authelia-2026-06-03.md` |
|
||||
| AdGuard Home | Share / Borg | `/mnt/user/appdata/adguard/conf` | keine | keine zusaetzlichen Repo-Secrets dokumentiert | `dns_net`, `frontend_net` | DNS-Aufloesung funktioniert |
|
||||
| Tailscale | Share / Borg | `/mnt/user/appdata/tailscale` | keine | Tailscale-State im Pfad | Host-Netz | Tailscale verbunden |
|
||||
| PostgreSQL 17 | Share + Dumps | `/mnt/user/appdata/postgresql17` | `postgresql17-globals.sql`, `postgresql17-mailarchiver.dump`, `postgresql17-paperless.dump`, optional `postgresql17-authelia.dump` | `postgres_password.txt` | `backend_net` | DB startet, Ziel-Datenbanken vorhanden |
|
||||
| Redis | Share / Host | `/mnt/user/appdata/redis` | keine | `redis_password.txt` | `backend_net` | Redis startet, Apps verbinden sich |
|
||||
| Authelia | Borg | `/mnt/user/appdata/authelia/config`, `/mnt/user/appdata/secrets/*authelia*` | Shared PostgreSQL, optional Dump `postgresql17-authelia.dump` | JWT/Session/Storage/Postgres-/SMTP-Secret-Dateien | PostgreSQL 17, Traefik, GMX SMTP | Login-Seite und ForwardAuth funktionieren; SMTP-Notifier startet; aktive Sessions werden nach Restart neu aufgebaut |
|
||||
| Gitea | GitHub-Mirror + Gitea-Bundles fuer Repo-Bootstrap, Borg + Dump fuer Gitea-Appstate | `/mnt/user/services/gitea/data`, `/mnt/user/backups/git-bundles/gitea` | `gitea.sqlite.dump`, Bundle-Report `latest-report.md` | `borg_repo_passphrase.txt` fuer Restore-Tests; GitHub-Push-Mirror-PAT liegt nur in Gitea-Mirror-Settings | Traefik | Web-UI erreichbar, Repo sichtbar, SSH-Port reagiert; Bundle laesst sich klonen und `git fsck` ist sauber; GitHub-Push-Mirror synchronisiert ohne `last_error`; Mini-Restore nach `/mnt/user/backups/restore-lab/gitea` am 2026-05-07 erfolgreich validiert |
|
||||
| Komodo | Borg / Share | `/mnt/user/appdata/komodo/core`, `/mnt/user/appdata/komodo/periphery`, `/mnt/user/services/stacks` | `komodo-mongo.archive.gz` falls verifiziert | `komodo_mongo_password.txt`, `KOMODO_*` Stack ENV | Traefik, Mongo, Gitea | UI erreichbar, Periphery verbunden |
|
||||
| GitOps Host Automation | Borg / Git | `/mnt/user/services/homelab-infra`, `/mnt/user/services/posture-check` | keine eigene DB | keine | Gitea, Komodo, Unraid User Scripts | `posture-check` laeuft vom Host-Pfad und liefert `warning_count: 0` im bekannten Uebergangszustand |
|
||||
| Vaultwarden | Borg + Dump | `/mnt/user/appdata/vaultwarden` | `vaultwarden.sqlite.dump` | `vaultwarden_admin_token.txt` fuer Produktion; Restore-Test nutzt Wegwerf-Admin-Token und `borg_repo_passphrase.txt` | Traefik | Login-Seite erreichbar, Tresor-Daten sichtbar; Mini-Restore nach `/mnt/user/backups/restore-lab/vaultwarden` am 2026-05-07 erfolgreich validiert |
|
||||
|
||||
---
|
||||
|
||||
## Workstations
|
||||
|
||||
| System | Fuehrende Quelle | Datei-Restore | Dump / DB | Secrets / ENV | Abhaengigkeiten | Smoke-Test |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `baerchen` Windows 11 | Veeam Agent Image auf Unraid-SMB | `/mnt/user/backups/windows-images/baerchen/` bzw. `\\kallilabcore\backups\windows-images\baerchen` | Veeam Restore Points im Zielordner; erster Full-Lauf 2026-06-05, GUI-Groesse 53,8 GB, Dauer 0:11:31, MetaCheck 0 Fehler/0 Warnungen | SMB-User `micha`; Veeam Job Encryption Password nur noetig, falls Storage Encryption spaeter aktiviert wird; BitLocker-Recovery-Key erst noetig, wenn BitLocker spaeter aktiviert wird | Veeam Recovery USB `VEEAMRE`, SMB auf `kallilabcore`, AdGuard/DNS oder direkte IP | Recovery-Test am 2026-06-06 erfolgreich: USB-Boot, SMB-Ziel erreichbar, Restore Point sichtbar, vor echtem Restore abgebrochen; Runbook `ops/windows-reinstall/docs/windows-image-backup-baseline.md` |
|
||||
| Vaultwarden | Borg + Dump | `/mnt/user/appdata/vaultwarden` | `vaultwarden.sqlite.dump` | `vaultwarden_admin_token.txt`, `borg_repo_passphrase.txt` fuer Restore-Tests | Traefik | Login-Seite erreichbar, Tresor-Daten sichtbar; Mini-Restore nach `/mnt/user/backups/restore-lab/vaultwarden` am 2026-05-07 erfolgreich validiert |
|
||||
|
||||
---
|
||||
|
||||
@@ -52,17 +44,14 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`.
|
||||
|
||||
| Dienst | Fuehrende Quelle | Datei-Restore | Dump / DB | Secrets / ENV | Abhaengigkeiten | Smoke-Test |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Paperless-ngx | Borg + Dumps | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/paperless/export`, `/mnt/user/documents/scans_inbox` | `postgresql17-paperless.dump` | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS`, `borg_repo_passphrase.txt` fuer Restore-Tests | PostgreSQL 18, Redis, Traefik | Web-UI startet, Dokumente vorhanden; Restore-Test am 2026-05-31 erfolgreich: Borg-Archiv `Tägliche-Sicherung-2026-05-31T04:30:13.181`, isolierter PostgreSQL-18-/Redis-8-Testpfad, HTTP `200`, `32` Dokumente im Test-DB-Check, Report `/mnt/user/backups/restore-reports/paperless-2026-05-31.md` |
|
||||
| Mealie | Borg + Dump | `/mnt/user/appdata/mealie/data`, `/mnt/user/appdata/mealie/postgres18` (archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/mealie-postgres17`) | `mealie.dump` | `mealie_postgres_password.txt` | `mealie-postgres`, Traefik | UI startet, Rezepte vorhanden |
|
||||
| Immich | Borg + Dump | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive`, `/mnt/user/appdata/immich_postgres_vectorchord`; archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/immich-postgres-pgvecto-rs` | `immich.dump`; nach VectorChord braucht ein Restore ein Postgres-Image mit VectorChord | `IMMICH_DB_PASSWORD`, `immich_postgres_password.txt`, `borg_repo_passphrase.txt` fuer Restore-Tests | `immich_postgres`, `immich_redis`, Traefik | DB- und UI-Smoke gegen produktives Borg-Archiv am 2026-05-27 erfolgreich validiert; VectorChord-Migration am 2026-05-31: `11977` Assets, `11107` Smart-Search-Zeilen, `7092` Face-Search-Zeilen, `vchord 0.4.3`, `vector 0.8.1`, HTTP/API-Smoke 200. Voll-Restore der Foto-Dateien bleibt separater DR-Drill |
|
||||
| Mail-Archiver | Borg + Shared Dump | `/mnt/user/appdata/mailarchiver/data-protection-keys` | `postgresql17-mailarchiver.dump` | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` | PostgreSQL 18, Traefik, Authelia | Authelia-Weiterleitung greift; nach Login startet die Web-UI und das Archiv laesst sich oeffnen |
|
||||
| Nextcloud | Borg + Dump | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data`, `/mnt/user/appdata/nextcloud/postgres18` (archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/nextcloud-postgres17`), `/mnt/user/appdata/nextcloud/redis` | `nextcloud.dump`; Redis-Backup vor Redis-8-Cutover unter `/mnt/user/backups/borg/dumps/latest/nextcloud-redis-pre-redis8-<ts>` | `nextcloud_admin_user.txt`, `nextcloud_admin_password.txt`, `nextcloud_postgres_password.txt`; produktive DB-Rolle laut `config.php` ist `oc_admin` | `nextcloud-postgres`, `nextcloud-redis`, Traefik | Web-UI startet, Login funktioniert, Dateien sichtbar; `occ status` zeigt `maintenance: false` |
|
||||
| Paperless-ngx | Borg + Dumps | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/paperless/export`, `/mnt/user/documents/scans_inbox` | `postgresql17-paperless.dump` | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS`, `borg_repo_passphrase.txt` fuer Restore-Tests | PostgreSQL 17, Redis, Traefik | Web-UI startet, Dokumente vorhanden; Mini-Restore nach `/mnt/user/backups/restore-lab/paperless` am 2026-05-07 erfolgreich validiert |
|
||||
| Mealie | Borg + Dump | `/mnt/user/appdata/mealie/data`, optional `/mnt/user/appdata/mealie/postgres` bei lokalem Share-Weiterbetrieb | `mealie.dump` | `mealie_postgres_password.txt` | `mealie-postgres`, Traefik | UI startet, Rezepte vorhanden |
|
||||
| Immich | Borg + Dump | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive` | `immich.dump` | `IMMICH_DB_PASSWORD`, `immich_postgres_password.txt`, `borg_repo_passphrase.txt` fuer Restore-Tests | `immich_postgres`, `immich_redis`, Traefik | DB- und UI-Smoke gegen produktives Borg-Archiv am 2026-05-27 erfolgreich validiert: `immich.dump` extrahiert, isolierter pgvecto-rs-Postgres importiert, Immich-Loginseite HTTP 200, `11977` Assets und `1` User im Test-DB-Check; Report `/mnt/user/backups/restore-reports/immich-2026-05-27.md`. Voll-Restore der Foto-Dateien bleibt separater DR-Drill |
|
||||
| Mail-Archiver | Borg + Shared Dump | `/mnt/user/appdata/mailarchiver/data-protection-keys` | `postgresql17-mailarchiver.dump` | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` | PostgreSQL 17, Traefik, Authelia | Authelia-Weiterleitung greift; nach Login startet die Web-UI und das Archiv laesst sich oeffnen |
|
||||
| Nextcloud | Borg + Dump | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data` | `nextcloud.dump` | `nextcloud_admin_user.txt`, `nextcloud_admin_password.txt`, `nextcloud_postgres_password.txt` | `nextcloud-postgres`, `nextcloud-redis`, Traefik | Web-UI startet, Login funktioniert, Dateien sichtbar |
|
||||
| Glance | Git / Borg-Repo | Repo-Konfiguration unter `ops/glance/config/glance.yml`; keine kritische Datenpersistenz | keine | `GLANCE_IMMICH_API_KEY`, `GLANCE_ADGUARD_USERNAME`, `GLANCE_ADGUARD_PASSWORD`, `GLANCE_SPEEDTEST_API_KEY` | Traefik, Authelia, optional interne API-Ziele | Dashboard startet, Widgets laden, Docker-Status laeuft nur ueber `glance-docker-socket-proxy` |
|
||||
| ntfy | Borg / Share | `/mnt/user/appdata/ntfy` | keine | keine besonderen Secret-Dateien dokumentiert | Traefik | UI und Push-Endpunkt erreichbar |
|
||||
| Paperless-GPT | Borg / Share | `/mnt/user/appdata/paperless-gpt` | keine eigene DB | `PAPERLESS_API_TOKEN`, `OPENAI_API_KEY` | Traefik, Paperless, OpenAI API | UI startet, Konfiguration vorhanden; LLM-Provider zeigt `openai` / `gpt-5.4-mini` |
|
||||
| Home Assistant | Borg + HA-native Backups + Fachrepo | `/mnt/user/appdata/homeassistant` inkl. `.storage`, `secrets.yaml`, `trusted_proxies.yaml`; Fach-YAML aus `/mnt/user/services/smart-home-kalli/home-assistant` | HA-native Backup-Artefakte unter `/mnt/user/appdata/homeassistant/backups` falls vorhanden; keine externe DB in Phase 1 | HA-Secrets in `secrets.yaml`, Integrations-Tokens in `.storage`, MQTT-Credentials, spaeter InfluxDB-Token | Traefik, `frontend_net`, `smarthome_net`, Mosquitto, Fachrepo-Clone | `https://home.kaleschke.info` zeigt Login, MQTT-Integration verbindet sich, `backup.create` funktioniert, Energy-Dashboard-Konfiguration bleibt erhalten |
|
||||
| Smart-Home MQTT / Mosquitto | Borg / Share | `/mnt/user/appdata/mosquitto/config`, `/mnt/user/appdata/mosquitto/data`, `/mnt/user/appdata/mosquitto/log` | Mosquitto persistiert retained messages/subscriptions dateibasiert | `passwordfile`, `aclfile`, spaeter per-Device-User | `smarthome_net`, Home Assistant, spaeter ESPHome/Zigbee2MQTT | Container startet, HA kann sich authentifiziert verbinden, retained Testtopic bleibt nach Restart erhalten |
|
||||
| Smart-Home Fachrepo | Gitea + Borg-Repo-Clone | `/mnt/user/services/smart-home-kalli` | keine | keine echten Secrets im Repo; `secrets-template/` nur Beispiele | Gitea, Home Assistant Mounts | `git status` sauber, HA liest `configuration.yaml` und `packages/` aus dem Clone |
|
||||
| Paperless-GPT | Borg / Share | `/mnt/user/appdata/paperless-gpt` | keine eigene DB | `PAPERLESS_API_TOKEN` | Traefik, Paperless | UI startet, Konfiguration vorhanden |
|
||||
|
||||
---
|
||||
|
||||
@@ -80,8 +69,6 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`.
|
||||
| InfluxDB 3 Core | historischer Altstand / Datenuebernahme | `/mnt/user/appdata/influxdb3/data`, `/mnt/user/appdata/influxdb3/plugins` | dateibasierter Object Store | `influxdb3_admin_token.json` | `monitoring-influxdb3-core` | Datenpfad wird vom Monitoring-Zielstack weitergenutzt und darf nicht blind geloescht werden |
|
||||
| Loki / Alloy | historischer Altstand | `/mnt/user/appdata/loki/config`, `/mnt/user/appdata/loki/data`, `/mnt/user/appdata/alloy/config` | keine primaere DB; Loki-Dateispeicher war transient | keine zusaetzlichen Secrets | nicht aktiv | Compose-Pfad aus aktivem Repo entfernt; aktuelle Logsammlung laeuft ueber `monitoring-loki`/`monitoring-promtail` |
|
||||
| Monitoring Stack | Rebuild + named volumes + InfluxDB-Appdata | `prometheus_data`, `loki_data`, `promtail_positions`, `grafana_data`; InfluxDB unter `/mnt/user/appdata/influxdb3/data` und `/mnt/user/appdata/influxdb3/plugins`; Provisioning aus `monitoring/grafana/provisioning` | Prometheus-TSDB, Loki-Dateispeicher und InfluxDB-Dateistore; Diagnose-/Langzeitdaten, keine Tier-1-Restore-Quelle | `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json` | `monitoring_net`, `monitoring_influx_lan`, `frontend_net`, Traefik, Authelia, Docker socket read-only fuer Promtail, Host-Mounts fuer node-exporter/cAdvisor | `https://monitoring.kaleschke.info` leitet zu Authelia; Prometheus Targets sind up; Grafana-Datasources `Prometheus`, `Loki` und `InfluxDB 3 Core` funktionieren |
|
||||
| Zigbee2MQTT (geplant) | Borg + Fachrepo | `/mnt/user/appdata/zigbee2mqtt` inkl. `configuration.yaml`, `database.db`, `coordinator_backup.json`, `state.json`; Fach-Doku im Repo `smart-home-kalli` | keine externe DB | `network_key`, MQTT-Credentials, LAN-Koordinator-IP/Firmwarestand | Mosquitto, LAN-PoE-Koordinator, `smarthome_net` | Z2M startet, Coordinator verbindet sich, geraete bleiben gepairt, Testgeraet sendet MQTT-State |
|
||||
| ESPHome (geplant) | Fachrepo + Borg fuer Build-/Runtime-State | `/mnt/user/appdata/esphome` falls Dashboard/Build-Cache genutzt wird; YAML unter `/mnt/user/services/smart-home-kalli/esphome` | keine | ESPHome-Secrets ausserhalb Git, API-/OTA-Keys | WLAN/LAN, Mosquitto falls MQTT genutzt wird | Dashboard startet, ein Testgeraet kompiliert/validiert, OTA/API-Verbindung funktioniert |
|
||||
| Hermes Agent | VM-seitig offen | `/mnt/user/appdata/hermes-agent/data`, `/mnt/user/appdata/hermes-agent/ssh` | keine eigene DB | Host-`.env` fuer Provider-/API-/Home-Assistant-Tokens, `hermes_runner_id_ed25519`, `HERMES_DASHBOARD_HOST` | separate Hermes-VM/Runner, Traefik, Authelia, `hermes_net` | NAS-Stack nicht starten, solange Runner-VM und echte `.env` fehlen |
|
||||
| ddns-updater | Rebuildbar | geringe Persistenzrelevanz | keine | Provider-Zugang ueber Stack ENV | Internetzugang | Update-Job laeuft |
|
||||
|
||||
@@ -110,14 +97,6 @@ Aktuell relevante Dump-Artefakte unter `/mnt/user/backups/borg/dumps/latest`:
|
||||
|
||||
Die Dump-Erzeugung ist host-seitig ueber `ops/borg-ui/scripts/pre-backup-dumps.sh` vorgesehen.
|
||||
|
||||
### PostgreSQL 18 Restore- und Rollback-Regeln
|
||||
|
||||
- PostgreSQL-18-Container verwenden das Docker-Image-Layout mit Mount auf `/var/lib/postgresql` und `PGDATA=/var/lib/postgresql/18/docker`.
|
||||
- Die alten PostgreSQL-17-Datenpfade wurden nach Burn-in am 2026-06-02 aus den aktiven Appdata-Pfaden entfernt und unter `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602` archiviert.
|
||||
- Shared-Cluster-Restore: zuerst `pg_dumpall --globals-only` einspielen, dann die einzelnen Custom-Format-Dumps per `pg_restore`. Der Bootstrap-Rollenkonflikt fuer `mailarchiver` ist benign, solange `CREATE ROLE mailarchiver;` gezielt ausgelassen und das folgende `ALTER ROLE mailarchiver ...` eingespielt wird.
|
||||
- Nextcloud-Restore: vor dem Dump `occ maintenance:mode --on`, nach erfolgreichem Restore und `occ status` wieder `occ maintenance:mode --off`. Die Rolle `oc_admin` muss mit dem in `config.php` hinterlegten DB-Passwort existieren.
|
||||
- Rollback: betroffene App(s) und DB stoppen, archivierten Altstand zurueck an den frueheren Datenpfad verschieben, Compose auf das vorherige PostgreSQL-17-Image und den alten Datenpfad zuruecksetzen, dann DB und App wieder starten.
|
||||
|
||||
---
|
||||
|
||||
## Praktische Restore-Regeln
|
||||
@@ -138,51 +117,13 @@ Die Dump-Erzeugung ist host-seitig ueber `ops/borg-ui/scripts/pre-backup-dumps.s
|
||||
|
||||
---
|
||||
|
||||
## Restore-Test-Reifegrad
|
||||
## Erste sinnvolle Referenz-Restores
|
||||
|
||||
Stand 2026-06-06. Pro Dienst auf einen Blick: Wurde der Restore schon einmal real getestet?
|
||||
Wenn weitere Restore-Uebungen dokumentiert werden sollen, sind diese Dienste besonders geeignet:
|
||||
|
||||
| Dienst | Tier | Letzter Restore-Test | Typ | Naechster Lauf |
|
||||
|---|---|---|---|---|
|
||||
| Vaultwarden | 1 | 2026-05-07 | File + Container + HTTP | monatlich (1. Sa) |
|
||||
| Gitea | 1 | 2026-05-07 | File + Container + HTTP + TCP | monatlich (3. Sa) |
|
||||
| Authelia | 1 | 2026-06-03 | Config + Validate + HTTP Health | zweimonatlich (2. Sa gerade Mon.) |
|
||||
| Komodo Bootstrap | 1 | 2026-05-30 | Compose + Mongo + HTTP | quartalsweise |
|
||||
| Paperless | 2 | 2026-05-31 | File + Dump + Container + HTTP + Doc-Count | zweimonatlich (2. Sa ungerade Mon.) |
|
||||
| Immich | 2 | 2026-05-27 | Dump + Container + HTTP + Asset-Count | quartalsweise (2. So Feb/Mai/Aug/Nov) |
|
||||
| Unraid OS Flash | 1 | 2026-06-05 (Artefakt-Validierung) | sha256 OK + 390 Eintraege + 8 Kern-Configs vorhanden (`ops/maintenance/check-unraid-flash-backup.sh`); **physischer Ersatzstick-Boot-Test weiter offen** | Stick-Boot-Test nach Bedarf |
|
||||
| Traefik | 1 | 2026-06-03 | Config + LE-State + File-Provider + Ping 200 | quartalsweise |
|
||||
| AdGuard Home | 1 | 2026-06-06 | Config + Container + HTTP 401 + DNS + Filter-Count | quartalsweise oder nach DNS-Aenderungen |
|
||||
| Tailscale | 1 | - | noch kein Test | - |
|
||||
| PostgreSQL 18 Cluster | 1 | 2026-06-03 | globals + 5 per-DB dumps, 290 Tabellen gesamt | quartalsweise |
|
||||
| Redis 8 | 1 | 2026-06-06 | Pre-Cutover-Artefakt + Container + PING + INFO + DBSIZE | quartalsweise oder vor/nach Redis-Major-Aenderungen |
|
||||
| Komodo Mongo Daten | 1 | 2026-06-03 | mongorestore --archive --gzip, 86904 docs | quartalsweise |
|
||||
| Nextcloud | 2 | 2026-06-03 | File + Dump + Container + HTTP 200 + occ status + Table-Count (126) | quartalsweise |
|
||||
| Mealie | 2 | 2026-06-03 | File + Dump + Container + HTTP + Recipe-Count (3) | quartalsweise |
|
||||
| Mail-Archiver | 2 | 2026-06-03 | Keys + 645M Dump + Container + HTTP 200 | quartalsweise |
|
||||
| Glance | 2 | - | rebuildbar, kein Test noetig | - |
|
||||
| ntfy | 2 | - | rebuildbar, kein Test noetig | - |
|
||||
| Borg UI | 3 | - | rebuildbar | - |
|
||||
| Filebrowser | 3 | - | rebuildbar | - |
|
||||
| baerchen Windows Image | Workstation | 2026-06-06 | Full-Backup geschrieben; Recovery-USB-Boot, SMB-Mount und Restore-Point-Sichtpruefung erfolgreich; vor echtem Restore abgebrochen | nach Image-Aenderungen oder quartalsweise |
|
||||
1. `mail-archiver`
|
||||
2. `paperless-ngx`
|
||||
3. `gitea`
|
||||
4. `vaultwarden`
|
||||
|
||||
---
|
||||
|
||||
## Naechste Restore-Test-Kandidaten (priorisiert)
|
||||
|
||||
Stand 2026-06-06. Die frueheren Kandidaten (Shared PG18, Komodo Mongo, Mailarchiver, Mealie, Traefik)
|
||||
wurden alle am 2026-06-03 abgeschlossen und sind in der Reifegrad-Tabelle belegt.
|
||||
|
||||
Verbleibende offene Restore-Pfade ohne vollstaendigen Test:
|
||||
|
||||
1. **Unraid OS Flash** - Artefakt-Validierung am 2026-06-05 erfolgreich (siehe Reifegrad-Tabelle und `ops/restore-tests/unraid-flash-runbook.md`); offen bleibt nur der **physische Ersatzstick-Boot-Test**.
|
||||
2. **Tailscale** - State-/Reconnect-Pfad dokumentiert testen (`ops/restore-tests/tailscale-runbook.md`)
|
||||
|
||||
---
|
||||
|
||||
## Restore-Test-Runbooks
|
||||
|
||||
Die Ablaeufe je Dienst liegen als Runbooks und automatisierte Skripte unter
|
||||
`ops/restore-tests/` (Einstieg: `ops/restore-tests/README.md`). Fuer die noch
|
||||
offenen Pfade: `ops/restore-tests/unraid-flash-runbook.md` und
|
||||
`ops/restore-tests/tailscale-runbook.md`.
|
||||
Sie liefern hohen Erkenntnisgewinn ohne den kompletten Homelab-Neuaufbau zu brauchen.
|
||||
|
||||
+63
-14
@@ -1,10 +1,6 @@
|
||||
# Rollback Guide - Homelab
|
||||
|
||||
Typ: Runbook · Stand: 2026-06-11 · Status: aktiv
|
||||
# Rollback Guide - Homelab
|
||||
|
||||
Dieses Dokument beschreibt den sicheren Rueckweg im aktuellen GitOps-Betrieb.
|
||||
Rollback-Anleitungen fuer bereits entfernte Dienste (Uptime-Kuma, Grafana-/
|
||||
InfluxDB-Altstack, Stirling-PDF) liegen in der Git-Historie, nicht mehr hier.
|
||||
|
||||
---
|
||||
|
||||
@@ -76,14 +72,59 @@ Bei Problemen mit Borg UI oder Dump-Automatisierung:
|
||||
3. Persistenz unter `/mnt/user/appdata/borg-ui/` und `/mnt/user/backups/borg/dumps/` nicht blind loeschen
|
||||
4. Restore zuerst in einen Testpfad schreiben, nicht direkt in Produktivpfade
|
||||
|
||||
## Monitoring-Stack Rollback
|
||||
## BentoPDF / Stirling-PDF Rollback
|
||||
|
||||
`monitoring/` ist der einzige Observability-Stack. Bei Problemen:
|
||||
Bei Problemen mit BentoPDF:
|
||||
|
||||
1. Git-Stand auf die letzte funktionierende Stirling-PDF-Compose zuruecknehmen oder gezielt `apps/bentopdf` wieder durch `apps/stirling-pdf` ersetzen
|
||||
2. Commit + Push nach Gitea
|
||||
3. betroffenen Stack in Komodo redeployen
|
||||
4. `https://pdf.kaleschke.info` pruefen
|
||||
|
||||
Die alte Stirling-PDF-Persistenz unter `/mnt/user/appdata/stirling-pdf` nicht loeschen, solange der BentoPDF-Ersatz nicht fachlich abgenommen ist.
|
||||
|
||||
## Grafana / InfluxDB Rollback
|
||||
|
||||
Vor dem ersten produktiven Einsatz reicht es, den vorbereiteten Stack nicht zu deployen oder per Ruecknahme-Commit aus dem Repo zu entfernen.
|
||||
|
||||
Nach einem Deploy:
|
||||
|
||||
1. alten Grafana/InfluxDB-Stack in Komodo gestoppt lassen; der fruehere Compose-Pfad `ops/grafana-influxdb` ist seit 2026-05-26 nicht mehr im aktiven Repo
|
||||
2. Persistenz unter `/mnt/user/appdata/grafana` und `/mnt/user/appdata/influxdb3` unangetastet lassen
|
||||
3. Secrets unter `/mnt/user/appdata/secrets/grafana_admin_password.txt`, `/mnt/user/appdata/secrets/grafana_influxdb_token.txt` und `/mnt/user/appdata/secrets/influxdb3_admin_token.json` nur nach bewusstem Entscheid entfernen
|
||||
4. Grafana-Domain und InfluxDB-Zugriff testen, bis klar ist, dass keine produktiven Dashboards oder Writer mehr davon abhaengen
|
||||
|
||||
## Monitoring-Zielstack Rollback
|
||||
|
||||
Der Zielzustand ist `monitoring/` als einziger Observability-Stack. Bei Problemen nach der Migration:
|
||||
|
||||
1. `monitoring` in Komodo stoppen oder auf den letzten funktionierenden Commit zurueckgehen
|
||||
2. named volumes `prometheus_data`, `loki_data`, `promtail_positions`, `grafana_data` sowie `/mnt/user/appdata/influxdb3` nicht blind loeschen
|
||||
3. Secrets (`monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json`) nur nach bewusstem Entscheid entfernen
|
||||
4. Grafana-Datasources `Prometheus`, `Loki` und `InfluxDB 3 Core` testen
|
||||
2. nur im echten Notfall die abgeloesten Altstaende aus der Git-Historie vor dem Repo-Cleanup wiederherstellen, z. B. aus Commit `ff5991c`; nicht dauerhaft parallel zum Zielstack betreiben
|
||||
3. named volumes `prometheus_data`, `loki_data`, `promtail_positions`, `grafana_data` sowie `/mnt/user/appdata/influxdb3` nicht blind loeschen
|
||||
4. Secrets `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt` und `influxdb3_admin_token.json` nur nach bewusstem Entscheid entfernen
|
||||
5. Home Assistant Writer erst wieder umstellen, wenn `curl -i http://192.168.178.58:8181/` erwartbar `401 Unauthorized` liefert
|
||||
6. Grafana-Datasources `Prometheus`, `Loki` und `InfluxDB 3 Core` testen
|
||||
|
||||
## Uptime Kuma Removal Rollback
|
||||
|
||||
Falls die Blackbox-/Grafana-Ablösung unerwartet nicht ausreicht:
|
||||
|
||||
1. per Ruecknahme-Commit `ops/uptime-kuma/docker-compose.yml`, die Blackbox-/Glance-/Authelia-Referenzen und die Restore-Freshness-Pruefung auf den letzten Uptime-Kuma-Stand zurueckbringen
|
||||
2. nach Gitea pushen und den Uptime-Kuma-Stack in Komodo neu anlegen oder aus dem letzten Stack-Backup wiederherstellen
|
||||
3. `/mnt/user/appdata/_archive/uptime-kuma-removed-2026-05-25` nach `/mnt/user/appdata/uptime-kuma` zurueckverschieben, falls die Archivierung bereits erfolgt ist
|
||||
4. `https://uptime.kaleschke.info` und die Monitore pruefen
|
||||
5. erst danach den Blackbox-/Grafana-Zielzustand erneut bewerten
|
||||
|
||||
## Glance Dashboard Rollback
|
||||
|
||||
Vor dem ersten produktiven Einsatz reicht es, den vorbereiteten Stack `ops/glance` nicht zu deployen oder per Ruecknahme-Commit aus dem Repo zu entfernen.
|
||||
|
||||
Nach einem Deploy:
|
||||
|
||||
1. `glance` in Komodo stoppen oder auf den letzten funktionierenden Commit zurueckgehen
|
||||
2. keine Produktivdaten loeschen; Glance nutzt nur Repo-Konfiguration und Stack-ENV
|
||||
3. pruefen, ob `https://glance.kaleschke.info` nicht mehr geroutet wird oder wieder den erwarteten Stand zeigt
|
||||
4. der `glance-docker-socket-proxy` darf nicht separat als Dauercontainer laufen bleiben
|
||||
|
||||
---
|
||||
|
||||
@@ -91,11 +132,19 @@ Bei Problemen mit Borg UI oder Dump-Automatisierung:
|
||||
|
||||
Bevorzugte Quellen:
|
||||
|
||||
- Borg-Restore (zuerst in Testpfade unter `/mnt/user/backups/restore-lab/`)
|
||||
- erzeugte Dumps unter `/mnt/user/backups/borg/dumps/latest`
|
||||
- bekannte Appdata-Archivstaende unter `/mnt/user/appdata/_archive/`
|
||||
- Borg-Restore
|
||||
- erzeugte PostgreSQL-/MariaDB-Dumps
|
||||
- bekannte Appdata-Snapshots
|
||||
|
||||
Dienst-spezifische Restore-Quellen, Dumps und Smoke-Tests stehen in `docs/RESTORE_MATRIX.md`.
|
||||
Beispiele:
|
||||
|
||||
```bash
|
||||
cp -r /mnt/user/appdata/<service> /mnt/user/backup/
|
||||
```
|
||||
|
||||
```bash
|
||||
pg_dumpall > /mnt/user/backup/pg_dump_$(date +%Y%m%d).sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
|
||||
+6
-24
@@ -17,15 +17,13 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
|
||||
| Service | Secret | Datei / Methode | Status |
|
||||
|---|---|---|---|
|
||||
| Vaultwarden | `ADMIN_TOKEN` | `/mnt/user/appdata/secrets/vaultwarden_admin_token.txt` -> `ADMIN_TOKEN_FILE` | aktiv |
|
||||
| Vaultwarden | SMTP Password | `/mnt/user/appdata/secrets/homelab_smtp_password.txt` -> `SMTP_PASSWORD_FILE` fuer Einladungen/Benachrichtigungen | aktiv |
|
||||
| Traefik | Cloudflare DNS API Token | `/mnt/user/appdata/traefik/secrets/cloudflare_dns_api_token` -> Docker Secret `cloudflare_dns_api_token` | aktiv |
|
||||
| PostgreSQL 18 | DB Password | `/mnt/user/appdata/secrets/postgres_password.txt` -> `POSTGRES_PASSWORD_FILE` | aktiv |
|
||||
| PostgreSQL 17 | DB Password | `/mnt/user/appdata/secrets/postgres_password.txt` -> `POSTGRES_PASSWORD_FILE` | aktiv |
|
||||
| Redis | Passwort | `/mnt/user/appdata/secrets/redis_password.txt` -> Datei-Mount + Startkommando in `infra/redis/docker-compose.yml` | aktiv |
|
||||
| Mealie | DB Password | `/mnt/user/appdata/secrets/mealie_postgres_password.txt` -> nicht versionierte Stack-`.env` `${MEALIE_POSTGRES_PASSWORD}` -> `POSTGRES_PASSWORD` | aktiv |
|
||||
| mealie-postgres | DB Password | `/mnt/user/appdata/secrets/mealie_postgres_password.txt` -> `POSTGRES_PASSWORD_FILE` | aktiv |
|
||||
| Paperless-ngx | DB Password | Stack ENV `${PAPERLESS_DBPASS}` | aktiv |
|
||||
| Paperless-ngx | Redis URL | Stack ENV `${PAPERLESS_REDIS}` | aktiv |
|
||||
| Paperless-GPT | OpenAI API Key | Stack ENV `${OPENAI_API_KEY}`; nicht im Repo, nicht in Logs | aktiv |
|
||||
| code-server | Passwort | `/mnt/user/appdata/code-server/secrets/password` -> `FILE__PASSWORD` | aktiv |
|
||||
| Filebrowser | Admin Password | `/mnt/user/appdata/secrets/filebrowser_admin_password.txt` -> initialisierte SQLite-DB | aktiv |
|
||||
| Immich (server) | DB Password | Stack ENV `${IMMICH_DB_PASSWORD}` | aktiv |
|
||||
@@ -40,7 +38,7 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
|
||||
| Komodo Mongo | Root Password | `/mnt/user/appdata/secrets/komodo_mongo_password.txt` -> `MONGO_INITDB_ROOT_PASSWORD_FILE` | aktiv |
|
||||
| Komodo Core | App Secrets | Stack ENV `${KOMODO_SECRET_KEY}`, `${KOMODO_WEBHOOK_SECRET}`, `${KOMODO_JWT_SECRET}`, `${KOMODO_MONGO_PASSWORD}`, `${KOMODO_PERIPHERY_PASSKEY}` | aktiv |
|
||||
| Gitea Push Mirror | GitHub fine-grained PAT fuer `michaelkaleschke-spec/homelab-infra` | Gitea Repository Mirror Settings, persistent in `/mnt/user/services/gitea/data`; kein Datei-Secret im Repo | aktiv |
|
||||
| Glance | Community Widget API Tokens | Stack ENV `${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}` (alle read-only anlegen) | aktiv |
|
||||
| Glance | Community Widget API Tokens | Stack ENV `${GLANCE_IMMICH_API_KEY}`, `${GLANCE_ADGUARD_USERNAME}`, `${GLANCE_ADGUARD_PASSWORD}`, `${GLANCE_SPEEDTEST_API_KEY}` | aktiv |
|
||||
| speedtest-tracker | App Key / Admin-Zugang | Stack ENV `${APP_KEY}`, `${ADMIN_PASSWORD}` | aktiv |
|
||||
| Nextcloud | Admin User | `/mnt/user/appdata/secrets/nextcloud_admin_user.txt` -> `NEXTCLOUD_ADMIN_USER_FILE` | neu |
|
||||
| Nextcloud | Admin Password | `/mnt/user/appdata/secrets/nextcloud_admin_password.txt` -> `NEXTCLOUD_ADMIN_PASSWORD_FILE` | neu |
|
||||
@@ -53,16 +51,8 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
|
||||
| InfluxDB 3 Core | Admin Token JSON | `/mnt/user/appdata/secrets/influxdb3_admin_token.json` -> Docker Secret `/run/secrets/influxdb3_admin_token` | aktiv |
|
||||
| Monitoring Grafana | Admin Password | `/mnt/user/appdata/secrets/monitoring_grafana_admin_password.txt` -> Docker Secret `/run/secrets/monitoring_grafana_admin_password` -> `GF_SECURITY_ADMIN_PASSWORD__FILE` | aktiv |
|
||||
| Monitoring Grafana -> InfluxDB | Datasource Token | `/mnt/user/appdata/secrets/monitoring_grafana_influxdb_token.txt` -> Docker Secret `/run/secrets/monitoring_grafana_influxdb_token` | aktiv |
|
||||
| Grafana OIDC (Authelia) | Client Secret | `/mnt/user/appdata/secrets/grafana_oidc_client_secret` (Klartext, chmod 600) -> Docker Secret `/run/secrets/grafana_oidc_client_secret` -> `GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET__FILE`. Zugehoeriger pbkdf2-Hash liegt im Authelia-Host-Config-Client `grafana` (kein Wert im Repo) | aktiv (2026-06-06) |
|
||||
| Mealie OIDC (Authelia) | Client Secret | Stack-ENV `${MEALIE_OIDC_CLIENT_SECRET}` in `/mnt/user/services/stacks/mealie/apps/mealie/.env` (Komodo-Stack-ENV); pbkdf2-Hash im Authelia-Host-Config-Client `mealie` (kein Wert im Repo) | aktiv (2026-06-06) |
|
||||
| Home Assistant -> InfluxDB | HA InfluxDB Token | `/homeassistant/secrets.yaml` -> `influxdb3_homeassistant_token` | geplant |
|
||||
| Renovate Bot | Gitea Service-Account PAT | `/mnt/user/appdata/secrets/renovate_token.txt` -> Host-Datei (chmod 600), gelesen von `ops/renovate/run-renovate.sh` und an Renovate-Container als `RENOVATE_TOKEN` weitergegeben | aktiv nach Operator-Setup (siehe `docs/RENOVATE.md`) |
|
||||
| n8n | Encryption Key fuer interne Credential-Verschluesselung | `/mnt/user/appdata/secrets/n8n_encryption_key.txt` (chmod 600) -> Komodo Stack ENV `${N8N_ENCRYPTION_KEY}`; kein `_FILE`-Support im Upstream-Image | aktiv |
|
||||
| n8n | GMX IMAP Login (Mail-Trigger Workflow) | n8n Credentials Store (Typ `imap`), nur in `/mnt/user/appdata/n8n/data` mit `N8N_ENCRYPTION_KEY` verschluesselt | aktiv |
|
||||
| n8n | OpenAI API Key (LLM-Extraktion Workflow) | n8n Credentials Store (Typ `httpHeaderAuth`, Header `Authorization: Bearer ...`) | aktiv |
|
||||
| n8n | Gitea PAT fuer `n8n-bot` (Issue-Erstellung Workflow) | n8n Credentials Store (Typ `httpHeaderAuth`, Header `Authorization: token ...`); separater Bot-User mit Scope `write:issue` auf `Micha/mails` | aktiv |
|
||||
| baerchen Veeam | Veeam Job Encryption Password | Vaultwarden Secure Note `Veeam baerchen backup encryption password`; kein Datei-Secret im Repo | geplant, nur noetig falls Veeam Storage Encryption aktiviert wird |
|
||||
| baerchen SMB Backup Target | SMB Credential fuer User `micha` | bestehender Unraid-/Vaultwarden-Zugang fuer Share `backups`; wird im Veeam-Job gespeichert, Wert nie dokumentieren | aktiv |
|
||||
| baerchen BitLocker | BitLocker Recovery Key C: | **bewusst deaktiviert (Entscheidung 2026-06-06):** kein BitLocker, kein Recovery-Key noetig. Falls spaeter aktiviert: Key nach `D:\30_Finanzen\BitLocker-RecoveryKey-baerchen-<DATUM>.txt` + Vaultwarden Secure Note + physischer Ausdruck | nicht aktiv (bewusst) |
|
||||
|
||||
---
|
||||
|
||||
@@ -99,7 +89,6 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
|
||||
|-- borg_repo_passphrase.txt
|
||||
|-- influxdb3_admin_token.json
|
||||
|-- filebrowser_admin_password.txt
|
||||
|-- homelab_smtp_password.txt
|
||||
`-- vaultwarden_admin_token.txt
|
||||
```
|
||||
|
||||
@@ -112,12 +101,6 @@ Weitere dokumentierte Secret-Pfade:
|
||||
- Die Borg-Repo-Passphrase liegt zusaetzlich als Host-Secret-Datei fuer Restore-Tests und Notfallzugriff vor. Der Wert ist laut Operator-Bestaetigung vom 2026-05-26 offline gesichert; Ablageort und Wert werden nicht im Repo dokumentiert.
|
||||
- Gitea verwaltet den GitHub-Push-Mirror-PAT in den Repository-Mirror-Settings. Der Wert wird nicht dokumentiert und nicht in Dateien unter `docs/` oder `core/gitea/` geschrieben.
|
||||
- `paperless-ngx` ist eine bewusste Ausnahme: DB-Passwort und Redis-URL bleiben aktuell als Komodo Stack Environment Variables hinterlegt, um den stabil laufenden Produktionsstand nicht fuer eine reine Secret-Mechanik-Migration zu riskieren.
|
||||
- `baerchen` nutzt fuer das Veeam-Backup aktuell den bestehenden SMB-User
|
||||
`micha`. Ein dedizierter SMB-User `veeam-baerchen` ist nur ein spaeteres
|
||||
Hardening-Ziel, solange keine Unraid-User-/Share-Aenderungen gewuenscht sind.
|
||||
- Das Veeam-Job-Encryption-Passwort ist restore-kritisch. Ohne diesen Wert ist
|
||||
das Image unter `\\kallilabcore\backups\windows-images\baerchen` nicht
|
||||
brauchbar.
|
||||
|
||||
---
|
||||
|
||||
@@ -126,7 +109,8 @@ Weitere dokumentierte Secret-Pfade:
|
||||
Einige Secrets liegen bewusst nur als Komodo Stack Environment Variables vor, weil das Image kein `_FILE` unterstuetzt oder ein laufender stabiler Produktionsstand nicht fuer eine reine Mechanik-Migration geopfert werden soll. Diese Werte existieren **ausschliesslich** an folgenden Stellen:
|
||||
|
||||
1. **Komodo Mongo** (Runtime und Backup-Dump `komodo-mongo.archive.gz` unter `/mnt/user/backups/borg/dumps/latest/`).
|
||||
2. **Externe Operator-Notiz** (analoge Sicherung, vergleichbar mit der Borg-Passphrase).
|
||||
2. **Vaultwarden** (Operator-Eintrag pro Stack, sofern dort gepflegt).
|
||||
3. **Externe Operator-Notiz** (analoge Sicherung, vergleichbar mit der Borg-Passphrase).
|
||||
|
||||
**Bei Komodo-Restore aus kaltem Zustand wird immer in dieser Reihenfolge gesucht.** Konkrete Werte werden im Repo, in Logs, in Doku-Kommentaren und in ntfy-Meldungen niemals wiedergegeben.
|
||||
|
||||
@@ -135,14 +119,12 @@ Einige Secrets liegen bewusst nur als Komodo Stack Environment Variables vor, we
|
||||
| Stack | Stack-ENV-Variablen | Restore-Quelle (Reihenfolge) | Folgen bei Verlust aller Quellen |
|
||||
|---|---|---|---|
|
||||
| `paperless-ngx` | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | App-DB ist im Postgres-Cluster, Passwort muss in Postgres und Stack-ENV synchron neu gesetzt werden; Redis-URL ist deterministisch rekonstruierbar (Host, Port, Passwort), wenn Redis-Passwort-Datei vorliegt |
|
||||
| `paperless-gpt` | `PAPERLESS_API_TOKEN`, `OPENAI_API_KEY` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | Paperless-Token kann in Paperless neu erzeugt werden; OpenAI-Key muss im OpenAI-Projekt rotiert/neu erstellt werden |
|
||||
| `immich-server` | `IMMICH_DB_PASSWORD` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | analog Paperless: Postgres-User-Passwort in `immich_postgres` und Stack-ENV gemeinsam zuruecksetzen |
|
||||
| `mail-archiver` | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | DB-Connection-String enthaelt Postgres-Pass; App-Auth-Password fuer Web-UI |
|
||||
| `speedtest-tracker` | `APP_KEY`, `ADMIN_PASSWORD` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | `APP_KEY` ist verschluesselungsrelevant; bei echtem Verlust App-State frisch initialisieren |
|
||||
| `komodo-core` | `KOMODO_SECRET_KEY`, `KOMODO_WEBHOOK_SECRET`, `KOMODO_JWT_SECRET`, `KOMODO_MONGO_PASSWORD`, `KOMODO_PERIPHERY_PASSKEY` | Vaultwarden -> externe Notiz (Henne-Ei: Komodo-Mongo-Dump ist hier **nicht** Restore-Quelle, weil Komodo dafuer schon laufen muesste) | siehe `docs/SERVICES_RECOVERY.md` Komodo-Bootstrap; ohne diese Werte ist der Self-Stack nicht reproduzierbar |
|
||||
| `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` | Provider-UIs (Immich, AdGuard, Speedtest-Tracker, Komodo, Gitea, Paperless, Mealie) neu erzeugen | rebuildbar; alle read-only; Widgets bleiben leer bis Tokens neu erzeugt sind, kein kritischer Datentopf |
|
||||
| `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. |
|
||||
| `glance` | `GLANCE_IMMICH_API_KEY`, `GLANCE_ADGUARD_USERNAME`, `GLANCE_ADGUARD_PASSWORD`, `GLANCE_SPEEDTEST_API_KEY` | Provider-UIs (Immich, AdGuard, Speedtest-Tracker) neu erzeugen | rebuildbar; Widgets bleiben leer bis Tokens neu erzeugt sind, kein kritischer Datentopf |
|
||||
|
||||
### Komodo-Sonderfall
|
||||
|
||||
|
||||
+19
-22
@@ -138,31 +138,19 @@ Erfolgskriterium: Komodo-UI laedt, Periphery `Online`, mindestens ein Stack aus
|
||||
|
||||
Erst nach erfolgreichem Komodo-Bootstrap werden produktive Stacks ueber den dokumentierten Stufenpfad in `docs/DISASTER_RECOVERY.md` Phase 4 hochgefahren (Traefik, AdGuard, Tailscale, dann PostgreSQL, Authelia, Redis, Gitea, dann Apps).
|
||||
|
||||
### Trockenlauf (als Repo-Skript, bestaetigt)
|
||||
### Trockenlauf-Idee (Doku-only, nicht ausgefuehrt)
|
||||
|
||||
Trockenlauf gegen Wegwerf-Pfade ist seit 2026-05-29 als Repo-Skript abgelegt:
|
||||
`ops/restore-tests/komodo-bootstrap-compose.test.yml`,
|
||||
`ops/restore-tests/komodo-bootstrap-test.sh` und
|
||||
`ops/restore-tests/komodo-bootstrap-runbook.md`. Aufruf:
|
||||
Ein bewusster Trockenlauf des Komodo-Bootstraps gegen Wegwerf-Pfade ist die naechste sinnvolle Reife-Stufe. Vorschlag:
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab-infra/ops/restore-tests/komodo-bootstrap-test.sh --what-if # nur Plan
|
||||
bash /mnt/user/services/homelab-infra/ops/restore-tests/komodo-bootstrap-test.sh --keep-data # echter Lauf
|
||||
```
|
||||
|
||||
Erstlauf 2026-05-30 erfolgreich: `SUCCESS`, alle 5 Checks gruen (compose config valid, Mongo healthy, Mongo authenticated ping ok, Komodo Core HTTP `200`, Test-Periphery `running`). Report unter `/mnt/user/backups/restore-reports/komodo-bootstrap-2026-05-30.md`. Produktive Komodo-Container, Mongo-Datadir und Secrets wurden nicht beruehrt.
|
||||
|
||||
Test-Isolation:
|
||||
|
||||
| Bereich | Wegwerf-Wert |
|
||||
| Schritt | Inhalt |
|
||||
|---|---|
|
||||
| Compose-Project | `restoretest-komodo` (isoliert von Produktions-Project `komodo`) |
|
||||
| Test-Mongo-Datadir | `/mnt/user/backups/restore-lab/komodo/mongo` |
|
||||
| Test-Port | `127.0.0.1:19120` (kein LAN, kein Traefik) |
|
||||
| Test-Periphery | ohne `docker.sock`-Mount, ohne `/mnt/user/services`-Mount |
|
||||
| `KOMODO_*`-Secrets | Wegwerf-Werte im Test-Compose, niemals produktive Werte |
|
||||
| 1 | Test-Compose aus `ops/komodo/docker-compose.yml` in `/mnt/user/backups/restore-lab/komodo/` kopieren |
|
||||
| 2 | Test-`.env` mit Wegwerf-Secrets erzeugen (nicht produktive Werte!) |
|
||||
| 3 | `docker compose -f .../restore-lab/komodo/docker-compose.yml -p restoretest-komodo up -d` |
|
||||
| 4 | Smoke: Mongo healthy, Core antwortet auf `http://127.0.0.1:<test-port>/api/health`, Periphery verbindet |
|
||||
| 5 | `docker compose -p restoretest-komodo down -v` und Restore-Lab bereinigen |
|
||||
|
||||
Damit ist `ops/komodo/docker-compose.yml` als Recovery-Anker fuer Stufen A-F **belegt** tauglich, nicht nur angenommen tauglich.
|
||||
Der Trockenlauf ist **noch nicht** als Repo-Skript abgelegt. Er bleibt als Folgeschritt analog zum Immich-Restore-Test geplant.
|
||||
|
||||
### Validierungs-Kommandos (Snapshot)
|
||||
|
||||
@@ -202,4 +190,13 @@ Authoritativ ist `docs/SECRETS_MAP.md`. Fuer den Kaltstart ist diese Reihenfolge
|
||||
- Wenn Gitea und Komodo beide down sind, gewinnt der externe GitHub-Mirror als Repo-Quelle.
|
||||
- Wenn Borg ohne Passphrase nicht entschluesselbar ist, ist Recovery blockiert. Die Offline-Sicherung wurde am 2026-05-26 vom Operator bestaetigt; bei Reviews nur pruefen, dass sie weiterhin auffindbar und lesbar ist.
|
||||
|
||||
Offene Folgepunkte werden in `docs/MASTER_TODO.md` gefuehrt.
|
||||
## Naechste Aufgaben
|
||||
|
||||
| Status | Aufgabe |
|
||||
|---|---|
|
||||
| erledigt (Skript + Host-Test) | Gitea-Bundle- oder Mirror-Mechanik final entscheiden |
|
||||
| erledigt | Komodo-Bootstrap-Quelle finalisieren |
|
||||
| erledigt (Doku) | Komodo-Kaltstart in linearen Stufen A-F dokumentieren |
|
||||
| offen | Komodo-Trockenlauf-Skript in `ops/restore-tests/` analog zu Immich vorbereiten |
|
||||
| offen | Restore-Kommandos nach erstem Trockenlauf mit echten Pfaden ergaenzen |
|
||||
| erledigt | Services-Recovery in `docs/DISASTER_RECOVERY.md` verlinken |
|
||||
|
||||
+19
-28
@@ -1,6 +1,6 @@
|
||||
# Service Catalog
|
||||
|
||||
Stand: 2026-06-02
|
||||
Stand: 2026-05-23
|
||||
|
||||
Dieser Katalog beschreibt produktive und repo-vorbereitete Dienste aus Sicht von Betrieb, Restore und KI-Kontext. Er basiert auf dem Repo-Sollzustand. Vor produktiven Eingriffen immer den Live-Zustand in Komodo/Docker pruefen.
|
||||
|
||||
@@ -13,44 +13,43 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
|
||||
| `traefik` | zentraler Reverse Proxy, TLS, Docker-Label-Routing | `traefik/docker-compose.yml`, `traefik/dynamic/*` | `https://traefik.kaleschke.info` | Docker socket, Cloudflare DNS API, `frontend_net`, `backend_net` | `/mnt/user/appdata/traefik/dynamic`, `/mnt/user/appdata/traefik/letsencrypt` | Tier 1, Share/Borg | ja, eigene Dashboard-Route mit Authelia | Host-Ports 80/443 sind zentrale Ausnahme; dynamic configs werden nicht automatisch von Komodo deployed |
|
||||
| `adguard` | DNS-Server / LAN DNS | `host-services/Adguard/docker-compose.yml` | LAN-Port `53`, Admin `100.80.98.33:8082` | `dns_net`, `frontend_net`, Unbound | `/mnt/user/appdata/adguard/conf`, `/mnt/user/appdata/adguard/work` | Tier 1, config relevant | nein | Direkter DNS-Port 53 bleibt; Admin-Port ist bewusst ohne Traefik/2FA, aber auf Tailscale-IP begrenzt (Operator-Entscheidung 2026-05-26) |
|
||||
| `unbound` | Upstream DNS Resolver fuer AdGuard | `apps/unbound/docker-compose.yml` | intern | `dns_net` | `/mnt/user/appdata/unbound/config` | rebuildbar / config relevant | nein | intern isoliert |
|
||||
| `tailscale` | VPN/Remote-Zugang, Subnet-Router | **Natives Unraid-Plugin** `tailscale.plg` (nicht repo-/Komodo-verwaltet) | Tailscale | Host-Netz (`tailscale1`) | `/boot/config/plugins/tailscale/state` (im Flash-Backup) | Tier 1, State relevant | nein | Subnet-Router `192.168.178.0/24`; redundanter Docker-Stack `host-services/tailscale/` am 2026-06-06 entfernt |
|
||||
| `tailscale` | VPN/Remote-Zugang | `host-services/tailscale/docker-compose.yml` | Tailscale | Host-Netz | `/mnt/user/appdata/tailscale` | Tier 1, State relevant | nein | `network_mode: host`, `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` sind dokumentierte VPN-Ausnahmen |
|
||||
| `gitea` | Git-Server / origin fuer GitOps | `core/gitea/docker-compose.yml` | `https://git.kaleschke.info`, SSH `222` | Traefik, `frontend_net`, externe DNS-Resolver fuer GitHub-Push-Mirror | `/mnt/user/services/gitea/data` | Tier 1, `gitea.sqlite.dump` + Share; privater GitHub-Push-Mirror fuer Repo-Bootstrap | ja | SSH-Port 222 direkte Host-Port-Ausnahme; Push-Mirror nach `michaelkaleschke-spec/homelab-infra` reduziert das DR-Bootstrap-Risiko |
|
||||
|
||||
## Security / Identity
|
||||
|
||||
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| `authelia` | ForwardAuth / zentrale Auth fuer Admin-UIs | `security/authelia/docker-compose.yml`, `security/authelia/configuration.yml` | `https://auth.kaleschke.info` | PostgreSQL 18, Traefik, GMX SMTP | `/mnt/user/appdata/authelia/config`, Authelia Secret-Dateien | Tier 1, config + DB + secrets | ja | Bewusst ohne Redis-Session-Backend; SMTP-Notifier via GMX und `authelia_smtp_password.txt`; explizite DNS-Server fuer SMTP/NTP; Repo-Baseline muss manuell in die Host-Config gemerged werden, OIDC/Secrets bleiben hostseitig; Access-Control und Compose-Middleware bei Aenderungen abgleichen |
|
||||
| `vaultwarden` | Passwort-Tresor | `security/vaultwarden/docker-compose.yml` | `https://vault.kaleschke.info` | Traefik, `frontend_net`, GMX SMTP | `/mnt/user/appdata/vaultwarden` | Tier 1, `vaultwarden.sqlite.dump` + Share | ja | `ADMIN_TOKEN_FILE`; SMTP ueber `homelab_smtp_password.txt` fuer Einladungen/Benachrichtigungen; keine direkten Ports |
|
||||
| `authelia` | ForwardAuth / zentrale Auth fuer Admin-UIs | `security/authelia/docker-compose.yml`, `security/authelia/configuration.yml` | `https://auth.kaleschke.info` | PostgreSQL 17, Traefik, GMX SMTP | `/mnt/user/appdata/authelia/config`, Authelia Secret-Dateien | Tier 1, config + DB + secrets | ja | Bewusst ohne Redis-Session-Backend; SMTP-Notifier via GMX und `authelia_smtp_password.txt`; explizite DNS-Server fuer SMTP/NTP; Repo-Baseline muss manuell in die Host-Config gemerged werden, OIDC/Secrets bleiben hostseitig; Access-Control und Compose-Middleware bei Aenderungen abgleichen |
|
||||
| `vaultwarden` | Passwort-Tresor | `security/vaultwarden/docker-compose.yml` | `https://vault.kaleschke.info` | Traefik, `frontend_net` | `/mnt/user/appdata/vaultwarden` | Tier 1, `vaultwarden.sqlite.dump` + Share | ja | `ADMIN_TOKEN_FILE`; keine direkten Ports |
|
||||
|
||||
## Shared Infrastructure
|
||||
|
||||
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| `postgresql17` | shared PostgreSQL 18 Cluster (historischer Service-Name bleibt fuer DNS/Clients stabil) | `infra/postgresql17/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/postgresql18`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/postgresql17`, `postgres_password.txt` | Tier 1; Dumps unter `/mnt/user/backups/borg/dumps/latest` | nein | keine Host-Ports; raw DB nicht primaerer Restore-Weg |
|
||||
| `Redis` | primaer Paperless-Redis (App-Cache); historisch als "shared" angelegt, faktisch nur von Paperless genutzt | `infra/redis/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/redis`, `redis_password.txt` | transiente Daten, bewusst nicht kritisch | nein | Redis 8.8; Passwort-Datei; optional named volume offen. Immich, Nextcloud und Mealie nutzen jeweils eigene Redis-Instanzen; Authelia laeuft bewusst ohne Redis-Session-Backend. Bei Wegfall ist Paperless der einzige betroffene Stack. |
|
||||
| `postgresql17` | shared PostgreSQL Cluster | `infra/postgresql17/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/postgresql17`, `postgres_password.txt` | Tier 1; Dumps unter `/mnt/user/backups/borg/dumps/latest` | nein | keine Host-Ports; raw DB nicht primaerer Restore-Weg |
|
||||
| `Redis` | primaer Paperless-Redis (App-Cache); historisch als "shared" angelegt, faktisch nur von Paperless genutzt | `infra/redis/docker-compose.yml` | intern | `backend_net` | `/mnt/user/appdata/redis`, `redis_password.txt` | transiente Daten, bewusst nicht kritisch | nein | Passwort-Datei; optional named volume offen. Immich, Nextcloud und Mealie nutzen jeweils eigene Redis-Instanzen; Authelia laeuft bewusst ohne Redis-Session-Backend. Bei Wegfall ist Paperless der einzige betroffene Stack. |
|
||||
| `ddns-updater` | Cloudflare/DDNS Aktualisierung | `infra/ddns-updater/docker-compose.yml` | intern | Internetzugang, `frontend_net` | `/mnt/user/appdata/ddns-updater` | rebuildbar | nein | bleibt bewusst in `frontend_net`, weil `backend_net` internal ist |
|
||||
|
||||
## Public / User Apps
|
||||
|
||||
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| `paperless-ngx` | Dokumentenmanagement | `apps/paperless/docker-compose.yml` | `https://paperless.kaleschke.info` | PostgreSQL 18, Redis 8, Traefik | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/scans_inbox` | Tier 2, Borg + `postgresql17-paperless.dump` | ja | DB/Redis Secrets bleiben bewusst Stack ENV; Dump-Dateiname behaelt den historischen Cluster-Namen |
|
||||
| `paperless-gpt` | KI-Ergaenzung fuer Paperless | `apps/paperless-gpt/docker-compose.yml` | `https://paperless-gpt.kaleschke.info` | Paperless API, OpenAI API, Traefik | `/mnt/user/appdata/paperless-gpt/data`, `/mnt/user/appdata/paperless-gpt/prompts` | Tier 2 | ja + Authelia | `PAPERLESS_API_TOKEN` und `OPENAI_API_KEY` als Stack ENV; LLM und Vision-OCR laufen ueber `gpt-5.4-mini`, kein Zugriff mehr auf lokale Ollama-VM. **Behalten-Entscheidung 2026-05-28:** Container bleibt aktiv, auch wenn aktuell keine Traefik-Zugriffe in der Woche; Ablouseplanung erst mit Paperless-NGX 3.0 (eigene KI-Features erwartet) - dann neu bewerten. |
|
||||
| `paperless-ngx` | Dokumentenmanagement | `apps/paperless/docker-compose.yml` | `https://paperless.kaleschke.info` | PostgreSQL 17, Redis, Traefik | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/scans_inbox` | Tier 2, Borg + `postgresql17-paperless.dump` | ja | DB/Redis Secrets bleiben bewusst Stack ENV |
|
||||
| `paperless-gpt` | KI-Ergaenzung fuer Paperless | `apps/paperless-gpt/docker-compose.yml` | `https://paperless-gpt.kaleschke.info` | Paperless API, LLM/Ollama, Traefik | `/mnt/user/appdata/paperless-gpt/data`, `/mnt/user/appdata/paperless-gpt/prompts` | Tier 2 | ja + Authelia | API Token als Stack ENV; OCR/LLM-Konfig bei Aenderungen pruefen. **Behalten-Entscheidung 2026-05-28:** Container bleibt aktiv, auch wenn aktuell keine Traefik-Zugriffe in der Woche; Ablouseplanung erst mit Paperless-NGX 3.0 (eigene KI-Features erwartet) - dann neu bewerten. |
|
||||
| `immich_server` | Foto-/Video-App | `apps/immich/docker-compose.yml` | `https://immich.kaleschke.info` | Immich Postgres, Immich Redis, ML, Traefik | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive` | Tier 2, Borg + `immich.dump` | ja | native App-Auth; externes Fotoarchiv gemountet |
|
||||
| `immich_postgres` | Immich-Datenbank | `apps/immich/docker-compose.yml` | intern | `immich_default` | `/mnt/user/appdata/immich_postgres_vectorchord`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/immich-postgres-pgvecto-rs`, `immich_postgres_password.txt` | Dump `immich.dump`; Restore braucht ein Image mit VectorChord/pgvector | nein | PG14 bleibt bewusst; Immich-DB-Image `ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0`; nie ins `frontend_net` |
|
||||
| `immich_redis` | Immich Cache | `apps/immich/docker-compose.yml` | intern | `immich_default` | kein kritischer Pfad dokumentiert | rebuildbar | nein | Redis 8.8; Architektur nennt anonymes Volume -> named volume als offenes Thema |
|
||||
| `immich_postgres` | Immich-Datenbank | `apps/immich/docker-compose.yml` | intern | `immich_default` | `/mnt/user/appdata/immich_postgres`, `immich_postgres_password.txt` | Dump `immich.dump` | nein | nie ins `frontend_net` |
|
||||
| `immich_redis` | Immich Cache | `apps/immich/docker-compose.yml` | intern | `immich_default` | kein kritischer Pfad dokumentiert | rebuildbar | nein | Architektur nennt anonymes Volume -> named volume als offenes Thema |
|
||||
| `immich_machine_learning` | Immich ML | `apps/immich/docker-compose.yml` | intern | `immich_default` | `model-cache` | rebuildbar | nein | intern-only |
|
||||
| `mealie` | Rezeptverwaltung | `apps/mealie/docker-compose.yml` | `https://mealie.kaleschke.info` | `mealie-postgres`, Traefik | `/mnt/user/appdata/mealie/data` | Tier 2, Borg + `mealie.dump` | ja | App + DB in internem Netz getrennt |
|
||||
| `mealie-postgres` | Mealie-Datenbank | `apps/mealie/docker-compose.yml` | intern | `mealie_internal` | `/mnt/user/appdata/mealie/postgres18`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/mealie-postgres17`, `mealie_postgres_password.txt` | Dump `mealie.dump` | nein | interne DB; PostgreSQL 18 |
|
||||
| `mail-archiver` | Mail-Archivierung | `apps/mail-archiver/docker-compose.yml` | `https://mail.kaleschke.info` | PostgreSQL 18, Internet/IMAP, Traefik, Authelia | `/mnt/user/appdata/mailarchiver/data-protection-keys` | Tier 2, `postgresql17-mailarchiver.dump` | ja + Authelia | Hybrid-Dienst: `frontend_net` fuer Internet, `backend_net` fuer DB; App-eigene Auth bleibt zusaetzliche Schutzschicht; Dump-Dateiname behaelt den historischen Cluster-Namen |
|
||||
| `mealie-postgres` | Mealie-Datenbank | `apps/mealie/docker-compose.yml` | intern | `mealie_internal` | `/mnt/user/appdata/mealie/postgres`, `mealie_postgres_password.txt` | Dump `mealie.dump` | nein | interne DB |
|
||||
| `mail-archiver` | Mail-Archivierung | `apps/mail-archiver/docker-compose.yml` | `https://mail.kaleschke.info` | PostgreSQL 17, Internet/IMAP, Traefik, Authelia | `/mnt/user/appdata/mailarchiver/data-protection-keys` | Tier 2, `postgresql17-mailarchiver.dump` | ja + Authelia | Hybrid-Dienst: `frontend_net` fuer Internet, `backend_net` fuer DB; App-eigene Auth bleibt zusaetzliche Schutzschicht |
|
||||
| `nextcloud` | Datei-/Cloud-Dienst | `apps/nextcloud/docker-compose.yml` | `https://cloud.kaleschke.info` | eigene PostgreSQL, eigene Redis, Traefik | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data` | Tier 2, `nextcloud.dump` + Share | ja | native App-Auth ohne zentrale ForwardAuth; WebDAV/CardDAV beachten |
|
||||
| `nextcloud-postgres` | Nextcloud-Datenbank | `apps/nextcloud/docker-compose.yml` | intern | `nextcloud_internal` | `/mnt/user/appdata/nextcloud/postgres18`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/nextcloud-postgres17`, `nextcloud_postgres_password.txt` | `nextcloud.dump`, raw DB nicht primaerer Restore-Weg | nein | interne DB; PostgreSQL 18 |
|
||||
| `nextcloud-redis` | Nextcloud Cache/Locking | `apps/nextcloud/docker-compose.yml` | intern | `nextcloud_internal` | `/mnt/user/appdata/nextcloud/redis` | Teil von Nextcloud-Restore | nein | interne Redis 8.8 |
|
||||
| `plex` | Medienserver mit LAN-/Client-Discovery | `host-services/plex/docker-compose.yml`, `traefik/dynamic/plex.yml` | `https://plex.kaleschke.info`, LAN `http://192.168.178.58:32400/web`, Remote Access deaktiviert | Host-Netz, Traefik File provider | `/mnt/user/appdata/plex/config`, `/mnt/user/appdata/plex/transcode`, `/mnt/user/media`, `/mnt/user/photos` | Tier 2, Appdata + Medienpfade im Borg-/Share-Scope | ja, native Plex-Auth | Repo-Compose-Stack; `network_mode: host` bleibt dokumentierte Discovery-Ausnahme. Traefik routet via File-Provider-Ausnahme auf `http://192.168.178.58:32400`, weil Docker-Labels Host-Netz-Container aus Traefik heraus auf `127.0.0.1` routen wuerden. Keine FRITZ!Box-Freigabe fuer `32400`. Keine Authelia-ForwardAuth, weil Plex Web/App-Clients native Plex-Auth und eigene Flows nutzen. Server geclaimt von `Xeridos`; Smart-TVs greifen weiter ueber WLAN-LAN per mDNS/Plex-GDM direkt zu. `PublishServerOnPlexOnlineKey=0` (Plex Remote Access aus), `RelayEnabled` ebenfalls aus. |
|
||||
| `nextcloud-postgres` | Nextcloud-Datenbank | `apps/nextcloud/docker-compose.yml` | intern | `nextcloud_internal` | `/mnt/user/appdata/nextcloud/postgres`, `nextcloud_postgres_password.txt` | `nextcloud.dump`, raw DB nicht primaerer Restore-Weg | nein | interne DB |
|
||||
| `nextcloud-redis` | Nextcloud Cache/Locking | `apps/nextcloud/docker-compose.yml` | intern | `nextcloud_internal` | `/mnt/user/appdata/nextcloud/redis` | Teil von Nextcloud-Restore | nein | interne Redis |
|
||||
| `plex` | Medienserver mit LAN-/Client-Discovery | `host-services/plex/docker-compose.yml` | Plex native, **LAN/Tailscale-only**, Remote Access deaktiviert | Host-Netz | `/mnt/user/appdata/plex/config`, `/mnt/user/appdata/plex/transcode`, `/mnt/user/media`, `/mnt/user/photos` | Tier 2, Appdata + Medienpfade im Borg-/Share-Scope | nein | Repo-Compose-Stack; `network_mode: host` bleibt dokumentierte Discovery-Ausnahme. Server geclaimt von `Xeridos` (Reclaim 2026-05-28 nach Preferences-Reset vom 18.05.). Smart-TVs greifen ueber WLAN-LAN per mDNS/Plex-GDM direkt zu. `PublishServerOnPlexOnlineKey=0` (Remote Access aus), `RelayEnabled` ebenfalls aus. |
|
||||
| `ntfy` | Push-Benachrichtigungen | `apps/ntfy/docker-compose.yml` | `https://ntfy.kaleschke.info` | Traefik, upstream mobile push | `/mnt/user/appdata/ntfy` | Tier 2 | ja | `NTFY_BEHIND_PROXY=true`; Problem-Alerts gehen gebuendelt an `homelab-alerts`, optionale Erfolgsmeldungen an `homelab-info` |
|
||||
| `bentopdf` | PDF-Tooling / Ersatz fuer Stirling-PDF | `apps/bentopdf/docker-compose.yml` | `https://pdf.kaleschke.info` | Traefik + Authelia | keine kritische Persistenz im Compose | Tier 3, rebuildbar | ja + Authelia | COOP/COEP per Middleware. **Behalten-Entscheidung 2026-05-28:** Container bleibt aktiv als situatives Tool, auch wenn aktuell keine Traefik-Zugriffe in der Woche. Resource-Footprint vernachlaessigbar (~4 MB RAM). |
|
||||
| `super-productivity` | Persoenliche Produktivitaets-/Task-PWA (Operator), konsumiert Gitea-Issues aus `Micha/mails` | `apps/super-productivity/docker-compose.yml` | `https://sp.kaleschke.info` | Traefik + Authelia, Gitea `Micha/mails` (Polling vom Client) | statisches Frontend, kein Server-State; Browser-IndexedDB plus optionaler WebDAV-Sync gegen Nextcloud | Tier 3, rebuildbar | ja + Authelia | Reine Static-PWA; SP synchronisiert client-seitig ueber Gitea-API (Scope `assigned`, Repo `Micha/mails`, User `Micha`). |
|
||||
|
||||
## Operations / Monitoring / Admin
|
||||
|
||||
@@ -66,7 +65,7 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
|
||||
| `speedtest-tracker` | Speedtest-Monitoring | `ops/speedtest/docker-compose.yml` | `https://speedtest.kaleschke.info` | Traefik + Authelia | `/mnt/user/appdata/speedtest-tracker/config` | Tier 3, `speedtest-tracker.sqlite.dump` | ja + Authelia | `APP_KEY`, `ADMIN_PASSWORD` Stack ENV |
|
||||
| `filebrowser` | Datei-Browser fuer Documents/Photos/Projekte | `ops/filebrowser/docker-compose.yml` | `https://files.kaleschke.info` | Traefik + Authelia | `/mnt/user/appdata/filebrowser/*`, `/mnt/user/documents`, `/mnt/user/photos`, `/mnt/user/projekte` | Tier 3, `filebrowser.bolt.dump` + Share | ja + Authelia | Breiter Appdata-Mount entfernt; Secrets und Traefik-Dynamic-Config sind nicht mehr ueber Filebrowser gemountet |
|
||||
| `code-server` | Web-Editor / Operations Workspace | `ops/code-server/docker-compose.yml` | `https://code.kaleschke.info` | Traefik + Authelia | `/mnt/user/appdata/code-server`, `/mnt/user/services/dev` | Tier 3 | ja + Authelia | Passwort ueber LSIO `FILE__PASSWORD`; Workspaces beachten |
|
||||
| `monitoring-grafana` | zentrale Observability-UI fuer Metriken, Logs und InfluxDB | `monitoring/docker-compose.yml` | `https://monitoring.kaleschke.info` | Traefik + Authelia, Prometheus, Loki, InfluxDB 3 Core | named volume `grafana_data`, Provisioning unter `monitoring/grafana/provisioning`, Dashboards unter `monitoring/grafana/dashboards` | Tier 3, named volume | ja + Authelia | Admin-Passwort ueber `monitoring_grafana_admin_password.txt`; Zielbestand: `Homelab / Availability`, `Homelab / Host Overview`, `Homelab / Containers + Logs`, `Homelab / Family Status`, `Traefik Official Standalone Dashboard`; Dashboard-Importer ist optionales `bootstrap`-Profil fuer Traefik |
|
||||
| `monitoring-grafana` | zentrale Observability-UI fuer Metriken, Logs und InfluxDB | `monitoring/docker-compose.yml` | `https://monitoring.kaleschke.info` | Traefik + Authelia, Prometheus, Loki, InfluxDB 3 Core | named volume `grafana_data`, Provisioning unter `monitoring/grafana/provisioning`, Dashboards unter `monitoring/grafana/dashboards` | Tier 3, named volume | ja + Authelia | Admin-Passwort ueber `monitoring_grafana_admin_password.txt`; Zielbestand: `Homelab / Availability`, `Homelab / Host Overview`, `Homelab / Containers + Logs`, `Traefik Official Standalone Dashboard`; Dashboard-Importer ist optionales `bootstrap`-Profil fuer Traefik |
|
||||
| `monitoring-prometheus` | Metrik-Speicher fuer Homelab-Monitoring | `monitoring/docker-compose.yml`, `monitoring/prometheus/prometheus.yml`, `monitoring/prometheus/alerts.yml` | intern `http://prometheus:9090` | `monitoring_net`, node-exporter, cAdvisor, Traefik-Metrics, Blackbox Exporter, Alertmanager | named volume `prometheus_data` | Tier 3, transiente Metriken mit 30 Tagen Retention | nein | Scrapes: Prometheus, node-exporter, cAdvisor, Traefik `:8082`, `blackbox-http`; Prometheus-Regeln senden an Alertmanager und von dort nach ntfy |
|
||||
| `monitoring-alertmanager` | Alert-Routing fuer Prometheus-Regeln | `monitoring/docker-compose.yml`, `monitoring/alertmanager/alertmanager.yml` | intern `:9093` | Prometheus, ntfy Bridge | named volume `alertmanager_data` | Tier 3 | nein | sendet firing und resolved Alerts an `monitoring-alertmanager-ntfy-bridge` |
|
||||
| `monitoring-alertmanager-ntfy-bridge` | Alertmanager-Webhook nach ntfy Push | `monitoring/docker-compose.yml`, `monitoring/alertmanager-ntfy-bridge/bridge.py` | intern `:8080` | Alertmanager, `https://ntfy.kaleschke.info/homelab-alerts` | kein kritischer Zustand | rebuildbar | nein | formatiert Alertmanager JSON als ntfy Titel, Nachricht, Priority und Tags; keine Secrets |
|
||||
@@ -75,24 +74,16 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
|
||||
| `monitoring-promtail` | Docker-Log-Collector fuer Monitoring-Loki | `monitoring/docker-compose.yml`, `monitoring/promtail/promtail-config.yml` | intern | Docker socket read-only, Docker json-file Logs, Loki | named volume `promtail_positions` | rebuildbar | nein | Dokumentierte Host-Observability-Ausnahme: `/var/run/docker.sock:/var/run/docker.sock:ro` und `/var/lib/docker/containers:ro`; keine Appdaten, nur Log-Discovery |
|
||||
| `monitoring-node-exporter` | Host-Metriken fuer Prometheus | `monitoring/docker-compose.yml` | intern `:9100` | Host `/proc`, `/sys`, `/` read-only, Prometheus | kein kritischer Zustand | rebuildbar | nein | Host-Observability-Ausnahme mit read-only Rootfs/Proc/Sys-Mounts |
|
||||
| `monitoring-cadvisor` | Container-Metriken fuer Prometheus | `monitoring/docker-compose.yml` | intern `:8080` | Docker/Host read-only Mounts, Prometheus | kein kritischer Zustand | rebuildbar | nein | Host-Observability-Ausnahme fuer Container-Metriken; keine direkten Ports |
|
||||
| `monitoring-influxdb3-core` | InfluxDB 3 Core fuer Home-Assistant-/Ecowitt-Langzeitdaten | `monitoring/docker-compose.yml` | Host-Port `8181` je `INFLUXDB_BIND_IP`, keine Public URL | Monitoring-Grafana, Home Assistant Writer | `/mnt/user/appdata/influxdb3/data`, `/mnt/user/appdata/influxdb3/plugins` | Tier 3 | nein | 2026-05-31 effektiv auf `127.0.0.1:8181` gebunden, also nicht LAN-exponiert; vor dem HA-Writer muss entschieden werden, ob `INFLUXDB_BIND_IP` auf eine LAN-IP geht oder HA gezielt ein gemeinsames internes Netz mit InfluxDB bekommt. `user: "0"` ist fuer den lokalen Object-Store-Pfad dokumentiert; `401 Unauthorized` beim Curl ohne Token ist erwarteter Reachability-Test |
|
||||
| `monitoring-influxdb3-core` | InfluxDB 3 Core fuer Home-Assistant-/Ecowitt-Langzeitdaten | `monitoring/docker-compose.yml` | LAN `8181` je `INFLUXDB_BIND_IP`, keine Public URL | Monitoring-Grafana, Home Assistant Writer | `/mnt/user/appdata/influxdb3/data`, `/mnt/user/appdata/influxdb3/plugins` | Tier 3 | nein | LAN-only Host-Port-Ausnahme; `user: "0"` ist fuer den lokalen Object-Store-Pfad dokumentiert; uebernimmt den bisherigen InfluxDB-Daten-/Token-Katalog; `401 Unauthorized` beim Curl ohne Token ist erwarteter Reachability-Test |
|
||||
| `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. |
|
||||
|
||||
## Smart Home
|
||||
|
||||
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| `homeassistant` | Zentrale Smart-Home-Steuerung, Energy Dashboard, Integrations-Hub | Runtime: `smart-home/docker-compose.yml`; Fachkonfiguration: Repo `smart-home-kalli` | `https://home.kaleschke.info`; kein direkter Host-Port in Phase 1 | Traefik, `frontend_net`, `smarthome_net`, `smarthome-mosquitto`, Fachrepo unter `/mnt/user/services/smart-home-kalli` | `/mnt/user/appdata/homeassistant` inkl. `.storage`, `secrets.yaml`, `trusted_proxies.yaml`; YAML-Fachdateien read-only aus `/mnt/user/services/smart-home-kalli/home-assistant` | Tier 2, Borg + HA-native Backups; Restore-Probe Pflicht vor produktiven Energie-Automationen | ja, native HA-Auth | HA Container statt HAOS-VM; keine Add-ons, keine Supervised-Installation. `configuration.yaml` kommt aus dem Fachrepo, `.storage` wird nicht versioniert. `http.use_x_forwarded_for` und `trusted_proxies` muessen zur Traefik-Route passen. Ecowitt-HTTP bleibt Phase-2-Entscheidung wegen globalem Traefik-Redirect. |
|
||||
| `smarthome-mosquitto` | MQTT-Broker fuer HA, spaeter ESPHome und Zigbee2MQTT | `smart-home/docker-compose.yml`, `smart-home/mosquitto/config/mosquitto.conf` | intern `smarthome_net:1883`; kein LAN-Port in Phase 1 | `smarthome_net`, Passwort-/ACL-Dateien in Appdata | `/mnt/user/appdata/mosquitto/config`, `/mnt/user/appdata/mosquitto/data`, `/mnt/user/appdata/mosquitto/log` | Tier 2, Borg; Passwortdatei, ACLs und persistente Broker-Daten relevant | nein | LAN-Port `1883` erst in ESPHome-Phase mit ACLs und per-Device-Usern. |
|
||||
|
||||
## Host Operations
|
||||
|
||||
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| `posture-check` | Host-Posture-Audit fuer Filesystem, Mover-Drift, NVMe-SMART, Fuellstand und Authelia-Repo<->Host-Drift | `services/posture-check/posture-check.sh` | Unraid User-Script / Cron / Borg Pre-Hook | `findmnt`, `df`, `nvme`, optional `curl` fuer ntfy; ruft `services/authelia-diff.sh` fuer `authelia_config_drift` auf | `/mnt/user/services/posture-check/last.json` | Repo-Skript + letzter JSON-Status | nein | Muss auf dem Unraid-Host bei Boot, stuendlich und vor Borg laufen; Disk1-NTFS ist nach Disk1 Phase 2 nicht mehr erlaubt (`ALLOW_DISK1_NTFS=0` Standard); Warning/Critical alarmieren via ntfy nur bei neuer Ursache oder nach `ALERT_REPEAT_SECONDS`. Authelia-Drift-Check braucht einen Repo-Spiegel unter `/mnt/user/services/homelab-infra/` (siehe `docs/WORKFLOW.md` Sektion "Ausnahme: Authelia configuration.yml") |
|
||||
| `docker-critical-events` | Live-Alarmierung fuer Docker `die`/`oom`/`kill` Events | `services/posture-check/docker-critical-events.sh`, Supervisor `services/posture-check/docker-critical-events-supervisor.sh` | Unraid User-Script / Hintergrundprozess | Docker CLI, ntfy | `/mnt/user/services/posture-check/docker-critical-events-last.log`, PID/Outfile unter `/mnt/user/services/posture-check/` | Repo-Skript + letzter Event-Log | nein | Optional als Unraid User-Script `at array start` starten; Supervisor kann `start`, `stop`, `status`, `smoke`; sendet nach `homelab-alerts` |
|
||||
| `posture-check` | Host-Posture-Audit fuer Filesystem, Mover-Drift, NVMe-SMART und Fuellstand | `services/posture-check/posture-check.sh` | Unraid User-Script / Cron / Borg Pre-Hook | `findmnt`, `df`, `nvme`, optional `curl` fuer ntfy | `/mnt/user/services/posture-check/last.json` | Repo-Skript + letzter JSON-Status | nein | Muss auf dem Unraid-Host bei Boot, stuendlich und vor Borg laufen; Disk1-NTFS ist nach Disk1 Phase 2 nicht mehr erlaubt (`ALLOW_DISK1_NTFS=0` Standard); Warning/Critical alarmieren via ntfy nur bei neuer Ursache oder nach `ALERT_REPEAT_SECONDS` |
|
||||
| `docker-critical-events` | Live-Alarmierung fuer Docker `die`/`oom`/`kill` Events | `services/posture-check/docker-critical-events.sh` | Unraid User-Script / Hintergrundprozess | Docker CLI, ntfy | `/mnt/user/services/posture-check/docker-critical-events-last.log` | Repo-Skript + letzter Event-Log | nein | Optional als Unraid User-Script `at array start` starten; sendet nach `homelab-alerts` |
|
||||
|
||||
## Backup- und Restore-Hinweise
|
||||
|
||||
|
||||
+34
-4
@@ -42,7 +42,7 @@ Es ist **vor** jeder Storage- oder Compose-Änderung zu lesen. Wenn ein neuer St
|
||||
| Disk1 (Array) | WDC WD60EFAX-68JH4N1 (`WD-WX32D90PC0V0`) | **XFS** auf `md1p1` | 5.5T nutzbar | Nutzdaten, Backups, Services | NTFS-zu-XFS-Migration Phase 2 abgeschlossen am 2026-05-25 |
|
||||
| Parity | TOSHIBA HDWG480 (`2460A03VFA3H`) | — (keine FS) | 7.3T | Redundanz für Array | Unverändert |
|
||||
| Boot | Samsung Flash Drive (`0375125090000587`) | FAT32 | 59.8G | Unraid-OS, Konfiguration | Regelmäßig per Flash-Backup gesichert |
|
||||
| Externe Backup-Platte | H:/ `Externe HDD` am Windows-PC | NTFS | 8.0T | Nearline-Pull-Ziel für kritische Restore-Artefakte | Kein Off-site-/Airgap-Ersatz; Pull-Workflow in `ops/h-drive-nearline/README.md` |
|
||||
| Externe Backup-Platte | H:/ `Externe HDD` am Windows-PC | NTFS | 8.0T | Nearline-Pull-Ziel für kritische Restore-Artefakte | Kein Off-site-/Airgap-Ersatz; Pull-Workflow in `docs/H_DRIVE_NEARLINE_PULL.md` |
|
||||
|
||||
Physikalische Basisdaten sind aus `docs/HARDWARE_INVENTORY.md` und dem Host-Readout vom 2026-05-27 übernommen. Detailwerte zu SMART/Health bleiben dort die autoritative Quelle; dieses Dokument hält die Storage-Policy.
|
||||
|
||||
@@ -380,8 +380,38 @@ Wenn Hermes-Worker auf weiteren Hosts skaliert: dieser Storage-Layout-Plan gilt
|
||||
- `docs/AI_CONTEXT.md` — Kontext für AI-Assistenten
|
||||
- `docs/HARDWARE_INVENTORY.md` — physische Host-, Disk- und Health-Baseline
|
||||
|
||||
## 18. Status
|
||||
## 18. Changelog
|
||||
|
||||
Status: **Active v1.4 seit 2026-05-27**.
|
||||
| Version | Datum | Änderung | Autor |
|
||||
|---------|-------|----------|-------|
|
||||
| 1.0 (Draft) | 2026-05-15 | Initialfassung nach Incident 2026-05-11. Ursprung: NTFS-Cache-Korruption, fehlende Posture-Checks, ungeplante Backup-Strategie. | Operator + AI-Assistenten |
|
||||
| 1.1 (Draft) | 2026-05-15 | Operator-Review-Feedback eingearbeitet: `system`/`domains` auf `only`, `services` als recovery-kritisch markiert, `data/`-Behandlung pro Stack klassifiziert (statt blanket Exclude), Backup-Tooling Ist/Soll explizit getrennt, Posture-Check zusätzlich bei Boot/vor Backup/nach Mover, Hard Rules 11+12 ergänzt (Restore-Pfad-Pflicht, Posture-vor-Backup), Alarmziel-Optionen benannt, Review-Items in eigene Sektion §20 verschoben. | Operator + AI-Assistenten |
|
||||
| 1.2 (Draft) | 2026-05-15 | Operator-Entscheidungen #3, #4, #6, #9, #11 eingearbeitet: Backrest abgeschaltet (Borg alleinige Backup-Technologie), persönliche Daten vollständig im Pflicht-Backup-Scope, ntfy als Alarmziel verbindlich, kebab-case-Migration im Rahmen der Recovery-Phase, Mirror-Backup für Gitea-Repo-Inhalte als verbindliche Spec (Implementierung in `SERVICES_RECOVERY.md` zu detaillieren). Offen: Items #1, #2, #5, #7, #8, #10. | Operator + AI-Assistenten |
|
||||
| 1.3 (Draft) | 2026-05-15 | Operator-Entscheidungen #1, #7, #8 eingearbeitet: Disk-Größen/-Modelle als Deferred via Posture-Check-Detection (kein Blocker), optionale Stacks (Filebrowser, code-server, Speedtest, Scrutiny, Uptime-Kuma) bleiben im Layout und sind produktiv, Network-Verweis auf MASTER_V2 bestätigt. Damit alle akuten Items entschieden. Verbleibend: Items #2, #5, #10 (Retention, Schwellen-Kalibrierung, RESTORE_MATRIX-Klassifikation) — alle als Folge-Aufgaben über Inkraftsetzung hinaus, kein Commit-Blocker. | Operator + AI-Assistenten |
|
||||
| 1.4 (Active) | 2026-05-27 | Datei von `docs/STORAGE_LAYOUT.draft.md` auf `docs/STORAGE_LAYOUT.md` gehoben; Hardware-/Diskwerte aus `docs/HARDWARE_INVENTORY.md` übernommen; Gitea-Bundle-Mirror und H:/ Nearline-Pull als umgesetzte Folgepfade referenziert. Verbleibend: Retention-Kalibrierung, Monitoring-Schwellen und RESTORE_MATRIX-Detailklassifikation als normale Folgeaufgaben. | Operator + AI-Assistenten |
|
||||
|
||||
Detailhistorie und alte Review-Tabellen liegen in der Git-Historie. Aktuelle Folgepunkte stehen nicht mehr hier, sondern in `docs/MASTER_TODO.md`.
|
||||
## 19. Inkraftsetzung
|
||||
|
||||
Dieses Dokument tritt in Kraft mit dem Commit der finalen Fassung in `master`-Branch des Repos `homelab-infra`. Ab Inkraftsetzung gelten alle Hard Rules; Soft Rules werden im Rahmen der laufenden Recovery-Arbeit etabliert; Posture-Check muss innerhalb von 14 Tagen nach Inkraftsetzung produktiv laufen.
|
||||
|
||||
Erste Audit-Review dieses Dokuments: spätestens 90 Tage nach Inkraftsetzung. Danach jährlich oder bei jeder strukturellen Änderung des Storage-Layouts.
|
||||
|
||||
## 20. Review Items und Folgeaufgaben
|
||||
|
||||
Diese Sektion dokumentiert erledigte Review-Punkte und verbleibende Folgeaufgaben nach Aktivierung des Dokuments.
|
||||
|
||||
| Nr. | Item | Status | Verantwortung |
|
||||
|-----|------|--------|---------------|
|
||||
| 1 | Disk-Größen und Modelle in §3 (Disk1, Parity, externe Backup-Platte) | **ERLEDIGT 2026-05-27** — Werte aus `docs/HARDWARE_INVENTORY.md` übernommen; Disk1-Filesystem ist seit 2026-05-25 XFS | Operator + Posture-Check |
|
||||
| 2 | Retention-Werte in §8.1 (Borg-Repos lokal/remote) — abhängig von tatsächlicher Storage-Kapazität | Vorschlag steht, anzupassen | Operator |
|
||||
| 3 | Backup-Tooling: Backrest abschalten, Borg alleinige Backup-Technologie | **ENTSCHIEDEN 2026-05-15** | erledigt (siehe §8.0) |
|
||||
| 4 | Backup-Scope für persönliche Daten: `documents`, `photos`, `finance`, `projekte` (und `media` falls behalten) **vollständig** im Pflicht-Scope | **ENTSCHIEDEN 2026-05-15** | erledigt (siehe §8.2) |
|
||||
| 5 | Posture-Check-Schwellen in §11 — Vorschlag konservativ, nach erstem Monitoring kalibrieren | Vorschlag steht | Operator nach 30 Tagen |
|
||||
| 6 | Alarmziel: ntfy als primärer Push-Kanal, Mail-Fallback als Folge-Erweiterung optional | **ENTSCHIEDEN 2026-05-15** | erledigt (siehe §11) |
|
||||
| 7 | Optionale Stacks (Filebrowser, code-server, Speedtest, Scrutiny, Uptime-Kuma) — bleiben im Layout, sind produktiv im Scope, folgen den Standard-Konventionen aus §5 und Backup-Pflichten aus §8.2 | **ENTSCHIEDEN 2026-05-15** | erledigt |
|
||||
| 8 | Verweis auf `HOMELAB_ARCHITECTURE_MASTER_V2.md` für Network-Architektur (§10) — Net-Architektur steht dort authoritativ, Verweis ist ausreichend | **ENTSCHIEDEN 2026-05-15** | erledigt (siehe §10) |
|
||||
| 9 | Naming-Konvention: kebab-case durchziehen, Migration im Rahmen der Recovery-Phase | **ENTSCHIEDEN 2026-05-15** | erledigt (siehe §6); pro Stack in RESTORE_MATRIX.md zu dokumentieren |
|
||||
| 10 | Pro-Stack-Klassifizierung in `RESTORE_MATRIX.md` (DB-Typ, Nutzdaten in `data/`, Dump-Verfahren, letzter Restore-Test, kebab-case-Migrationsname) — als Folge-Aufgabe aus Hard Rule §12.11 | Folge-Aufgabe | Operator + Recovery-Phase |
|
||||
| 11 | Mirror-Backup für `services/gitea/git/repositories/` auf zweites Medium, ≤ 6 h Frequenz, konkrete Implementierung in `docs/SERVICES_RECOVERY.md` zu erstellen | **ERLEDIGT 2026-05-26** — `ops/borg-ui/scripts/gitea-bundle-mirror.sh` erzeugt verifizierte Bundles; Host-Erstlauf mit 4 Bundles und `git fsck` erfolgreich | Operator + Folge-Doc |
|
||||
|
||||
Das Dokument ist mit Version 1.4 als Active geführt. Offene Punkte 2, 5 und 10 bleiben normale Folgeaufgaben und blockieren die Gültigkeit der Hard Rules nicht.
|
||||
|
||||
+4
-45
@@ -269,42 +269,6 @@ Diese Ausnahme bleibt bewusst bestehen. Der File-Provider wird weiterhin nur fue
|
||||
|
||||
---
|
||||
|
||||
## Ausnahme: Authelia configuration.yml
|
||||
|
||||
> **Diese Datei wird von Komodo nicht automatisch deployed.**
|
||||
|
||||
`security/authelia/configuration.yml` ist die Repo-Baseline fuer nicht geheime Einstellungen (Access-Control, Session, Storage-Struktur, Notifier, TOTP). Die produktive Host-Datei darf zusaetzlich OIDC-Clients und hostseitige Identity-Provider-Konfiguration enthalten. Secret-Werte und die User-Datenbank bleiben grundsaetzlich ausserhalb von Git.
|
||||
|
||||
| Git-Pfad | Host-Pfad (NAS) |
|
||||
|---|---|
|
||||
| `security/authelia/configuration.yml` | `/mnt/user/appdata/authelia/config/configuration.yml` |
|
||||
|
||||
### Pflicht-Workflow bei Aenderungen an `configuration.yml`
|
||||
|
||||
1. Datei im Git-Repo (`security/authelia/`) aendern.
|
||||
2. Commit + Push.
|
||||
3. Aenderung manuell in die Host-Datei mergen, OIDC-/Identity-Provider-Sektionen erhalten.
|
||||
4. `docker restart authelia` und Login-Smoke-Test auf einer ACL-betroffenen Domain.
|
||||
5. `services/authelia-diff.sh` (Default-Aufruf) muss `exit 0` liefern.
|
||||
|
||||
### Automatische Drift-Erkennung
|
||||
|
||||
`services/authelia-diff.sh` vergleicht die `access_control:`-Sektion zwischen Repo-Baseline und Host-Datei. Der Posture-Check (`services/posture-check/posture-check.sh`) ruft das Skript als Check `authelia_config_drift` auf und meldet Drift als Warning via ntfy.
|
||||
|
||||
Konfigurierbare Variablen (Defaults sind das produktive Zielbild):
|
||||
|
||||
- `AUTHELIA_REPO_BASELINE` — Pfad zur Repo-Datei auf dem Host, Default `/mnt/user/services/homelab-infra/security/authelia/configuration.yml`
|
||||
- `AUTHELIA_HOST_CONFIG` — Pfad zur produktiven Host-Datei, Default `/mnt/user/appdata/authelia/config/configuration.yml`
|
||||
- `AUTHELIA_DIFF_SECTIONS` — Komma-Liste der zu vergleichenden Top-Level-Sektionen, Default `access_control`
|
||||
- `AUTHELIA_DIFF_SCRIPT` — Pfad zum Diff-Skript fuer den Posture-Check, Default `/mnt/user/services/homelab-infra/services/authelia-diff.sh`
|
||||
- `SKIP_AUTHELIA_DRIFT=1` — Check im Posture-Check ueberspringen
|
||||
|
||||
Pflicht-Setup auf dem Host: Repo-Spiegel unter `/mnt/user/services/homelab-infra/` (Read-only-Clone von Gitea `Micha/homelab-infra`, regelmaessig `git pull --ff-only`). Ohne Repo-Spiegel meldet der Check Warning, weil die Baseline-Datei fehlt — Critical wird der Check bewusst nicht.
|
||||
|
||||
> **Merksatz:** Push allein reicht hier nicht. Ohne den manuellen Merge ins Host-Configfile wirkt die Aenderung nicht, und der Drift-Check wuerde Warning melden.
|
||||
|
||||
---
|
||||
|
||||
## Secrets-Regeln
|
||||
|
||||
- Secrets liegen niemals im Repository
|
||||
@@ -361,7 +325,7 @@ Pflicht-Schritte vor dem Schliessen:
|
||||
6. Authelia ACL-Eintrag in `security/authelia/configuration.yml` und auf dem Host bereinigen.
|
||||
7. Monitoring: Blackbox-Target in `monitoring/blackbox/blackbox.yml` entfernen, Cert-Check-Liste pruefen.
|
||||
8. **Borg-UI Source-Liste**: `https://borg.kaleschke.info` -> Repository `appdata-critical` -> Source Directories -> alle `/local/appdata/<name>` und ggf. `/local/<name>`-Eintraege loeschen. Sonst kommen daily `HomelabBorgLastJobCompletedWithWarnings`-Push-Nachrichten mit `BackupFileNotFoundError` im Logfile.
|
||||
9. `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md` und `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 7.8 (Entfernt) nachziehen.
|
||||
9. `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md`, `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 7.8 (Entfernt), `docs/MIGRATION_LOG.md` nachziehen.
|
||||
|
||||
Wenn ein Stack `webhook_enabled` in Komodo hatte, zusaetzlich pruefen, ob der zugehoerige Gitea-Hook deaktiviert oder geloescht wurde.
|
||||
|
||||
@@ -369,14 +333,9 @@ Wenn ein Stack `webhook_enabled` in Komodo hatte, zusaetzlich pruefen, ob der zu
|
||||
|
||||
## Dokumentationspflicht
|
||||
|
||||
Es gilt "ein Fakt, ein Zuhause" (`docs/REPO_MAP.md` Doku-Regeln): aktualisiert
|
||||
wird das jeweils zustaendige Dokument plus `docs/README.md`-Index, nicht
|
||||
mehrere Kopien. Nach jeder relevanten Aenderung pruefen, **welche** dieser
|
||||
Zuhause betroffen sind:
|
||||
|
||||
- `docs/DECISIONS.md` falls eine bewusste Entscheidung getroffen oder revidiert wurde
|
||||
- `docs/MASTER_TODO.md` falls sich der Status offener Punkte aendert
|
||||
Nach jeder erfolgreichen Migration oder relevanten Aenderung muessen diese Dateien geprueft werden:
|
||||
|
||||
- `docs/MIGRATION_LOG.md`
|
||||
- `docs/SECRETS_MAP.md`
|
||||
- `docs/ROLLBACK.md`
|
||||
- `docs/SERVICES_RECOVERY.md` falls `/mnt/user/services`, Gitea, Komodo oder Host-Automation betroffen sind
|
||||
@@ -408,7 +367,7 @@ Wenn mit einer KI gearbeitet wird, gilt immer:
|
||||
> 1. `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
> 2. `docs/WORKFLOW.md`
|
||||
> 3. die betroffene Compose-Datei
|
||||
> 4. die relevante Betriebsdoku aus `docs/README.md`
|
||||
> 4. ggf. `docs/MIGRATION_LOG.md`
|
||||
|
||||
Erst danach duerfen Aenderungen vorgeschlagen werden.
|
||||
|
||||
|
||||
@@ -1,504 +0,0 @@
|
||||
# DR Tabletop Drill - 2026-06-03
|
||||
|
||||
Trockenlauf gegen `docs/DISASTER_RECOVERY.md` Phase 0 bis 5 plus referenzierte
|
||||
Runbooks (`SERVICES_RECOVERY.md`, `RESTORE_MATRIX.md`, `SECRETS_MAP.md`,
|
||||
`RESTORE_HANDBOOK.md`, `EXTERNAL_DEPENDENCIES.md`).
|
||||
|
||||
Szenario: Bare-Metal-Ausfall. Unraid-Host und alle lokalen Festplatten sind
|
||||
weg. Operator hat: Laptop, Hetzner-Account, Vaultwarden-Export, Repo-Doku.
|
||||
Soft-Recovery (Host laeuft, Appdata futsch) ist eine Teilmenge dieser
|
||||
Findings.
|
||||
|
||||
Methode: kalter Lesetest. Kein Container gestartet, keine Skripte
|
||||
ausgefuehrt. Jeder Befund ist mit Repo-Datei und Zeile belegt. Spekulative
|
||||
"vielleicht unklar"-Befunde sind weggelassen.
|
||||
|
||||
Severity:
|
||||
|
||||
- **CRITICAL** - blockiert Wiederanlauf, ohne Workaround nicht loesbar
|
||||
- **HIGH** - blockiert eine Phase, Workaround moeglich aber undokumentiert
|
||||
- **MED** - kostet Zeit oder fuehrt zu vermeidbarem Fehler
|
||||
- **LOW** - Konsistenz / Stil
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| ID | Phase | Severity | Thema |
|
||||
|---|---|---|---|
|
||||
| P0-1 | 0 | HIGH | Brueckenpfad Windows-Clone -> frischer Unraid-Host fehlt |
|
||||
| P0-2 | 0 | HIGH | GitHub-Mirror-Zugang im DR ist nicht eigenstaendig dokumentiert |
|
||||
| P1-1 | 1 | CRITICAL | Unraid-Flash-Restore: kein dokumentierter Extract-Pfad ohne laufenden Host |
|
||||
| P1-2 | 1 | MED | Unraid-OS-Flash-Restore-Test laut Matrix nie real getestet |
|
||||
| P2-1 | 2 | HIGH | KOMODO_* externe Operator-Notiz ist Pflichtquelle, Existenz nicht verifizierbar |
|
||||
| P2-2 | 2 | HIGH | DR.md Phase 4 vs. SERVICES_RECOVERY.md Bootstrap-Reihenfolge widerspruechlich |
|
||||
| P2-3 | 2 | MED | `homelab_smtp_password.txt` fehlt in DR.md Phase 2.6.1 |
|
||||
| P2-4 | 2 | MED | `n8n_encryption_key.txt` fehlt in DR.md Phase 2.6.1 |
|
||||
| P2-5 | 2 | LOW | Monitoring-/Filebrowser-Secrets fehlen in DR.md Phase 2.6.1 |
|
||||
| P3-1 | 3 | HIGH | Borg-Client ohne `borg-ui`-Container ist nicht dokumentiert |
|
||||
| P3-2 | 3 | HIGH | Borg-Passphrase-Bootstrap aus Offline-Sicherung nicht als expliziter Schritt |
|
||||
| P3-3 | 3 | MED | Hetzner-Maintenance-Key aus Vaultwarden ist Henne-Ei im Bare-Metal |
|
||||
| P4-1 | 4 | HIGH | Externe Docker-Netze in DR.md Phase 4 Stufe 1 nicht erwaehnt |
|
||||
| P4-2 | 4 | HIGH | Cloudflare-LE-Rate-Limit-Risiko bei verlorenem `letsencrypt`-State |
|
||||
| P4-3 | 4 | MED | `traefik/dynamic/*` als Phase-4-Pre-Check fehlt in der Reihenfolge |
|
||||
| P4-4 | 4 | HIGH | Authelia "frische Postgres ohne Dump"-Pfad nicht beschrieben |
|
||||
| P4-5 | 4 | LOW | Gitea in Stufe 2 hinter Postgres ist faktisch nicht noetig (SQLite) |
|
||||
| P4-6 | 4 | HIGH | Komodo-Mongo Passwort-Lockout-Risiko bei restauriertem Datadir |
|
||||
| P4-7 | 4 | MED | Komodo `extra_hosts` mit hardgecodeter LAN-IP bricht bei IP-Wechsel |
|
||||
| P4-8 | 4 | HIGH | Stack-ENV-Wiederherstellung in Komodo praktisch nur manueller UI-Eintrag |
|
||||
| P5-1 | 5 | LOW | Smoke-Tests in Phase 5 weniger streng als RESTORE_MATRIX |
|
||||
| P5-2 | 5 | MED | Kein Verifikationspunkt fuer App-zu-DB-Verbindung nach Stack-ENV-Restore |
|
||||
| X-1 | uebergreifend | HIGH | Nextcloud-Restore-Skript ist da, aber noch nie real ausgefuehrt |
|
||||
|
||||
## Phase 0 - Repo-Zugang
|
||||
|
||||
### P0-1 (HIGH) - Brueckenpfad Windows-Clone -> frischer Unraid fehlt
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:88-93` listet als Repo-Quellen: GitHub-Mirror,
|
||||
lokaler Bare-Clone, lokaler Arbeits-Clone. `SERVICES_RECOVERY.md:67-68`
|
||||
nennt den lokalen Operator-Clone unter `G:\Gitea_Clone\homelab-infra\` als
|
||||
Vorzug.
|
||||
|
||||
Luecke: der Pfad "wie kommt der Windows-Clone auf einen frisch installierten
|
||||
Unraid-Host" ist nicht beschrieben. Implizit: SMB-Share, USB-Stick, scp ueber
|
||||
LAN. Aber auf einem frisch aufgesetzten Unraid existiert noch keine
|
||||
funktionierende SMB-Konfiguration; SSH-Key vom Operator-PC ist nicht
|
||||
vorbereitet.
|
||||
|
||||
Vorschlag: Zwei Saetze in `DISASTER_RECOVERY.md` Phase 0 ergaenzen, wie der
|
||||
Operator-Clone konkret zum Host kommt (USB-Stick + `mkdir -p
|
||||
/mnt/user/services/homelab-infra && rsync -a` aus Operator-Windows-PC, oder
|
||||
direkt vom GitHub-Mirror per `git clone https://github.com/...` auf dem
|
||||
Unraid-Host).
|
||||
|
||||
### P0-2 (HIGH) - GitHub-Mirror-Zugang im DR
|
||||
|
||||
`SECRETS_MAP.md:42` sagt, der GitHub-Push-Mirror-PAT liegt in den
|
||||
Gitea-Mirror-Settings persistent unter `/mnt/user/services/gitea/data`.
|
||||
`EXTERNAL_DEPENDENCIES.md:18` nennt den Mirror als `michaelkaleschke-spec/
|
||||
homelab-infra` und betont "privater" Push-Mirror.
|
||||
|
||||
Luecke: Wenn der Mirror **privat** ist, scheitert ein anonymer `git clone`
|
||||
im DR-Bootstrap. Es gibt keine dokumentierte Notfall-Quelle fuer einen
|
||||
Read-PAT/SSH-Key, der lokal beim Operator (nicht in Gitea, nicht im Repo)
|
||||
verfuegbar ist.
|
||||
|
||||
Vorschlag in `EXTERNAL_DEPENDENCIES.md`: entweder explizit dokumentieren,
|
||||
dass der Mirror lesend `Public` ist (DR-fit), oder einen Read-PAT in der
|
||||
Vaultwarden-/Offline-Notiz neben der Borg-Passphrase als Bootstrap-Voraussetzung
|
||||
benennen.
|
||||
|
||||
## Phase 1 - Unraid und Shares
|
||||
|
||||
### P1-1 (CRITICAL) - Unraid-Flash-Restore ohne laufenden Host
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:107` sagt: "Primaere lokale/off-site
|
||||
Restore-Quelle fuer die bestehende Flash-Konfiguration ist das
|
||||
Borg-Artefakt `unraid-flash-config.tar.gz` aus
|
||||
`/mnt/user/backups/borg/dumps/latest`."
|
||||
|
||||
Henne-Ei: der Pfad ist auf den verlorenen Shares oder auf Hetzner. Hetzner-
|
||||
Zugriff braucht einen funktionierenden Linux-Host mit Borg-Client und
|
||||
Passphrase. Im Bare-Metal-Fall ist genau das nicht da. RESTORE_MATRIX.md
|
||||
Tier 1 Zeile `Unraid OS Flash` (`docs/RESTORE_MATRIX.md:29`) sagt nur "Unraid
|
||||
USB Flash Creator / neuer Boot-Stick" - das beschreibt die Stick-Erzeugung,
|
||||
nicht den Extract des Borg-Artefakts.
|
||||
|
||||
Operativ: Operator braucht einen Laptop mit Borg-Client + Passphrase +
|
||||
SSH-Key fuer die Hetzner-Storage-Box. Das ist eine **separat zu pflegende
|
||||
Operator-Workstation-Voraussetzung** und ist in keinem Repo-Dokument als
|
||||
DR-Vorbedingung gelistet.
|
||||
|
||||
Vorschlag: In `EXTERNAL_DEPENDENCIES.md` oder `DISASTER_RECOVERY.md`
|
||||
Abschnitt 3 als Pflichtposten aufnehmen: "Operator-Laptop mit installiertem
|
||||
Borg-Client, SSH-Key fuer Hetzner und Zugriff auf die offline gesicherte
|
||||
Passphrase". Inklusive Test, dass der Operator den Extract tatsaechlich
|
||||
durchfuehren kann.
|
||||
|
||||
### P1-2 (MED) - Unraid-OS-Flash-Restore-Test nie gelaufen
|
||||
|
||||
`docs/RESTORE_MATRIX.md:140` Spalte "Letzter Restore-Test" fuer Unraid OS
|
||||
Flash: `-` (kein Test). Das ist die Grundlage fuer Phase 1 und ist nie als
|
||||
Smoke verifiziert. Empfehlung: einmaliger Test, der die Tar-Archiv-Struktur
|
||||
gegen die erwarteten Flash-Pfade prueft (kein echter Boot-Test noetig).
|
||||
|
||||
## Phase 2 - Secrets und Stack-ENV
|
||||
|
||||
### P2-1 (HIGH) - KOMODO_* externe Operator-Notiz als Pflichtquelle
|
||||
|
||||
`docs/SECRETS_MAP.md:132,138-143` macht den Komodo-Sonderfall klar: die
|
||||
KOMODO_*-Secrets sind aus dem eigenen Mongo-Dump nicht rekonstruierbar,
|
||||
solange Komodo nicht laeuft. Quellen: Vaultwarden ODER externe Notiz.
|
||||
|
||||
Im Bare-Metal-Fall ist Vaultwarden in DR.md Phase 4 Stufe 4, Komodo in
|
||||
Phase 4 Stufe 3. Damit ist die **externe Operator-Notiz** die einzige
|
||||
Pflichtquelle in der Reihenfolge.
|
||||
|
||||
Luecke: ob diese Notiz wirklich existiert und die 5 Werte
|
||||
(KOMODO_SECRET_KEY, KOMODO_WEBHOOK_SECRET, KOMODO_JWT_SECRET,
|
||||
KOMODO_MONGO_PASSWORD, KOMODO_PERIPHERY_PASSKEY) enthaelt, ist in keinem
|
||||
Repo-Dokument bestaetigt. Die Borg-Passphrase ist als "Operator-Bestaetigung
|
||||
2026-05-26" dokumentiert; eine analoge Bestaetigung fuer die KOMODO_*-Notiz
|
||||
fehlt.
|
||||
|
||||
Vorschlag: gleiche Form wie Borg-Passphrase - eine Zeile in
|
||||
`EXTERNAL_DEPENDENCIES.md` "Komodo-Stack-ENV-Notiz offline gesichert,
|
||||
Operator-Bestaetigung YYYY-MM-DD".
|
||||
|
||||
### P2-2 (HIGH) - Reihenfolgen-Inkonsistenz DR vs. SERVICES_RECOVERY
|
||||
|
||||
`docs/SERVICES_RECOVERY.md:102` (Stufe C, Komodo-Bootstrap): "Vaultwarden
|
||||
(sobald restauriert), externe Operator-Notiz, oder Komodo-Mongo-Dump (nur
|
||||
wenn Mongo separat bereits gestartet ...)".
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:247-301` (Phase 4): Stufe 3 = Komodo, Stufe 4 =
|
||||
Vaultwarden.
|
||||
|
||||
Wenn ein Leser sich an DR.md Phase 4 haelt, ist Vaultwarden nach Komodo
|
||||
fertig. Aber SERVICES_RECOVERY.md Stufe C setzt Vaultwarden als optionale
|
||||
Vorab-Quelle voraus. Ohne externe Notiz heisst das praktisch: Komodo kann
|
||||
nicht starten. Die Konsequenz steht nirgendwo explizit in DR.md.
|
||||
|
||||
Vorschlag: In `DISASTER_RECOVERY.md` Phase 4 Stufe 3 einen Hinweisblock
|
||||
ergaenzen: "KOMODO_*-Werte muessen vor Stufe 3 aus externer Notiz oder
|
||||
einer in Stufe 2 voraus gezogenen Vaultwarden-Instanz vorliegen. Default-
|
||||
Pfad: externe Notiz."
|
||||
|
||||
### P2-3 (MED) - `homelab_smtp_password.txt` fehlt in DR.md 6.1
|
||||
|
||||
`docs/SECRETS_MAP.md:20` listet `/mnt/user/appdata/secrets/
|
||||
homelab_smtp_password.txt` fuer Vaultwarden-SMTP. In `DISASTER_RECOVERY.md`
|
||||
Abschnitt 6.1 (`docs/DISASTER_RECOVERY.md:136-151`) ist sie nicht
|
||||
aufgefuehrt. Vaultwarden startet ohne, kann aber keine Einladungs-/
|
||||
Benachrichtigungs-Mails versenden. Klein, aber unsichtbarer Folgefehler im
|
||||
Familien-Onboarding-Pfad.
|
||||
|
||||
### P2-4 (MED) - `n8n_encryption_key.txt` fehlt in DR.md 6.1
|
||||
|
||||
`docs/SECRETS_MAP.md:58` listet `/mnt/user/appdata/secrets/
|
||||
n8n_encryption_key.txt`. In DR.md 6.1 fehlt sie komplett.
|
||||
`SECRETS_MAP.md:135` macht die Folgen explizit: "Bei Verlust aller
|
||||
Quellen: n8n startet, aber alle gespeicherten Credentials sind unbrauchbar".
|
||||
Da n8n den GMX-Mail-Workflow fuer das Gitea-`Micha/mails`-Repo betreibt,
|
||||
ist das ein direkter Workflow-Ausfall.
|
||||
|
||||
### P2-5 (LOW) - Monitoring-/Filebrowser-Secrets fehlen in DR.md 6.1
|
||||
|
||||
`docs/SECRETS_MAP.md:53-55`: `influxdb3_admin_token.json`,
|
||||
`monitoring_grafana_admin_password.txt`,
|
||||
`monitoring_grafana_influxdb_token.txt` sowie
|
||||
`filebrowser_admin_password.txt` sind nicht in DR.md 6.1. Tier-3-Apps,
|
||||
Folge ist nur ein UI-Initialisierungs-Schritt nach Wiederanlauf. Keine
|
||||
Critical-Konsequenz, aber Inkonsistenz.
|
||||
|
||||
## Phase 3 - Borg-Extract
|
||||
|
||||
### P3-1 (HIGH) - Borg-Client ohne `borg-ui`-Container
|
||||
|
||||
`docs/RESTORE_HANDBOOK.md:30-33` sagt explizit: "Borg-Zugriff laeuft ueber
|
||||
den vorhandenen `borg-ui`-Container".
|
||||
|
||||
Im Bare-Metal-Fall ist `borg-ui` selbst kalt (Tier 3, DR.md Phase 4 Stufe 5).
|
||||
Es gibt keinen dokumentierten Pfad, wie der erste Borg-Extract ohne diesen
|
||||
Container laeuft. Implizite Optionen: nativer Borg auf Unraid (Plugin),
|
||||
`docker run --rm borgbackup/borg`, oder Operator-Laptop. Keine davon ist
|
||||
benannt.
|
||||
|
||||
Vorschlag: In `RESTORE_HANDBOOK.md` Abschnitt 2 einen "Bare-Metal-Vorlauf"
|
||||
ergaenzen, der den initialen Borg-Extract ohne borg-ui-Container
|
||||
beschreibt - z. B. `docker run --rm -v
|
||||
/mnt/user/backups/restore-lab:/restore borgbackup/borg ...`.
|
||||
|
||||
### P3-2 (HIGH) - Borg-Passphrase-Bootstrap nicht als expliziter Schritt
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:68`: "Host-Secret-Datei vorhanden und fuer
|
||||
Borg-Zugriff verifiziert; externe Offline-Hinterlegung vom Operator am
|
||||
2026-05-26 bestaetigt."
|
||||
|
||||
Praktisch heisst das: im Bare-Metal-Fall liest der Operator die Passphrase
|
||||
aus einem analogen Medium und tippt sie in den Borg-Client. Das ist ein
|
||||
**Bootstrap-Schritt**, der nicht als Schritt dokumentiert ist. Er steckt
|
||||
implizit in "extern bestaetigt".
|
||||
|
||||
Vorschlag: Ein nummerierter Bullet in `DISASTER_RECOVERY.md` Phase 3 ("Wenn
|
||||
echte Daten aus Borg benoetigt werden"): "Schritt 1: Borg-Passphrase aus
|
||||
Offline-Sicherung beschaffen. Wert wird nicht in Skripte oder Tickets
|
||||
kopiert; nur in den interaktiven Borg-Aufruf eingegeben."
|
||||
|
||||
### P3-3 (MED) - Hetzner-Maintenance-Key im Bare-Metal
|
||||
|
||||
`docs/EXTERNAL_DEPENDENCIES.md:17`: "Maintenance-Key liegt in Vaultwarden".
|
||||
|
||||
Im Bare-Metal-Bootstrap ist Vaultwarden Phase 4 Stufe 4. Damit ist der Key
|
||||
fuer die initiale Phase-3-Hetzner-Verbindung nicht zugaenglich. Implizit
|
||||
muss er ebenfalls offline gesichert sein (analog Borg-Passphrase).
|
||||
|
||||
Vorschlag: gleiche Form wie Borg-Passphrase - eine Operator-Bestaetigung
|
||||
in `EXTERNAL_DEPENDENCIES.md`, dass der Hetzner-SSH-Key auch ausserhalb von
|
||||
Vaultwarden offline verfuegbar ist. Sonst ist die "Vaultwarden"-Aussage
|
||||
fuer Bare-Metal eine Falle.
|
||||
|
||||
## Phase 4 - Bootstrap-Reihenfolge
|
||||
|
||||
### P4-1 (HIGH) - Externe Docker-Netze in DR.md Phase 4 Stufe 1 nicht erwaehnt
|
||||
|
||||
`docs/SERVICES_RECOVERY.md:82-84` Stufe A schreibt explizit: "Externe
|
||||
Docker-Netze existieren oder werden erzeugt (`frontend_net`, `backend_net`).
|
||||
Wenn nicht vorhanden: `docker network create --driver bridge frontend_net`
|
||||
bzw. `... --internal backend_net`."
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:252-260` Phase 4 Stufe 1 nennt nur Traefik,
|
||||
AdGuard, Tailscale. Kein Hinweis auf externe Netze.
|
||||
|
||||
`traefik/docker-compose.yml:70-76` deklariert `frontend_net`, `backend_net`,
|
||||
`monitoring_net` als `external: true`. Ohne vorab erstellte Netze scheitert
|
||||
der erste `docker compose up` mit "network frontend_net not found".
|
||||
|
||||
Vorschlag: In `DISASTER_RECOVERY.md` Phase 4 vor Stufe 1 einen Vorlauf
|
||||
"Stufe 0 - Docker-Grundlage" einfuegen, der die Netzwerk-Erzeugung wie in
|
||||
`SERVICES_RECOVERY.md` Stufe A explizit listet.
|
||||
|
||||
### P4-2 (HIGH) - Cloudflare-LE-Rate-Limit-Risiko
|
||||
|
||||
`docs/RESTORE_MATRIX.md:30` markiert `letsencrypt` korrekt als
|
||||
Restore-relevant. `docs/DISASTER_RECOVERY.md:240` listet
|
||||
`/mnt/user/appdata/traefik/letsencrypt` ebenfalls als kritischen
|
||||
Borg-Restore-Pfad.
|
||||
|
||||
Luecke: kein Hinweis auf den Praxisfall "LE-State verloren, frischer
|
||||
Acme-Run". Let's Encrypt hat ein Rate-Limit von 50 Zertifikaten/Domain/
|
||||
Woche und 5 Duplicate-Zertifikate/Woche. Bei einer Multi-Sub-Domain-
|
||||
Konstellation wie `*.kaleschke.info` (15+ Hostnames) ist das beim
|
||||
hektischen DR-Bootstrap erreichbar.
|
||||
|
||||
Vorschlag: In `DISASTER_RECOVERY.md` Phase 4 Stufe 1 einen Hinweis: "Bei
|
||||
verlorenem oder unklarem `acme.json` zuerst gegen
|
||||
`acme-staging-v02.api.letsencrypt.org` ausstellen lassen, erst nach
|
||||
gruenem Smoke auf Production-CA umschalten." Ist eine Praesentations-
|
||||
Aenderung in den Compose-Args, kein neuer Code.
|
||||
|
||||
### P4-3 (MED) - `traefik/dynamic/*` als Pre-Check fehlt
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:357-365` Sektion 10 beschreibt die manuelle
|
||||
Sonderregel fuer `traefik/dynamic/*`. Korrekt.
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:252-260` Phase 4 Stufe 1 verweist nicht auf
|
||||
diese Sonderregel. Wer der Reihenfolge folgt und Sektion 10 nicht liest,
|
||||
startet Traefik ohne Middlewares - alle 2FA-Routen brechen still.
|
||||
|
||||
Vorschlag: Cross-Reference in Phase 4 Stufe 1: "Vor `docker compose up
|
||||
traefik` pruefen, dass `/mnt/user/appdata/traefik/dynamic/middlewares.yml`,
|
||||
`tls.yml`, `dashboards.yml` vorhanden sind (Sonderregel Sektion 10)."
|
||||
|
||||
### P4-4 (HIGH) - Authelia "frische Postgres ohne Dump"-Pfad fehlt
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:267-275` Phase 4 Stufe 2 startet Postgres und
|
||||
Authelia. Authelia erwartet eine Rolle `authelia` mit dem Passwort aus
|
||||
`authelia_postgres_password.txt`. Im Restore-Pfad mit `pg_dumpall --globals-
|
||||
only` ist die Rolle abgedeckt.
|
||||
|
||||
Bei einem **fresh-start** (keine alten Daten, nur Container hochfahren) ist
|
||||
die Rolle nicht da. Postgres-Image legt sie nicht automatisch an. Authelia
|
||||
schlaegt mit "FATAL: role authelia does not exist" fehl.
|
||||
|
||||
Luecke: Der Initialisierungspfad fuer eine frische Postgres ohne
|
||||
pg_dumpall ist in der Doku nicht beschrieben. Im echten DR mit Borg ist
|
||||
das unwahrscheinlich, aber im Soft-Recovery oder Migrations-Drill schon.
|
||||
|
||||
Vorschlag: In `DISASTER_RECOVERY.md` Phase 4 Stufe 2 eine optionale
|
||||
Anweisung: "Falls Postgres frisch ist (kein Dump-Restore), `infra/
|
||||
postgresql17/init/`-Skripte oder manuelle `CREATE ROLE`/`CREATE DATABASE`-
|
||||
Schritte ergaenzen."
|
||||
|
||||
### P4-5 (LOW) - Gitea nach Postgres ist faktisch unnoetig
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:267-275` Phase 4 Stufe 2 ordnet Gitea hinter
|
||||
Postgres ein. Gitea nutzt SQLite (`gitea.sqlite.dump`), nicht den shared
|
||||
Postgres. Reihenfolge ist nicht falsch, aber irrefuehrend. Nicht kritisch.
|
||||
|
||||
### P4-6 (HIGH) - Komodo-Mongo Passwort-Lockout-Risiko
|
||||
|
||||
`ops/komodo/docker-compose.yml:18-20` zeigt: `komodo-mongo` initialisiert
|
||||
sich bei leerem Datadir mit `MONGO_INITDB_ROOT_PASSWORD_FILE` aus
|
||||
`/mnt/user/appdata/secrets/komodo_mongo_password.txt`.
|
||||
|
||||
Restore-Fall: Datadir aus Borg restauriert, Secret-Datei aus Borg
|
||||
restauriert - beide aus demselben Snapshot. OK.
|
||||
|
||||
Riskanter Fall: Datadir aus Borg, aber Secret-Datei aus einer anderen
|
||||
(neueren oder aelteren) Quelle. Mongo akzeptiert den Login nicht, Komodo
|
||||
laeuft nicht. Lockout. Doku erwaehnt diesen Pin-Punkt nicht.
|
||||
|
||||
Vorschlag: Hinweis in `DISASTER_RECOVERY.md` Phase 4 Stufe 3: "Mongo-
|
||||
Datadir und `komodo_mongo_password.txt` muessen aus demselben Snapshot
|
||||
kommen. Bei Mismatch: leeren Datadir und Re-Init, dann Daten aus
|
||||
`komodo-mongo.archive.gz` per `mongorestore`."
|
||||
|
||||
### P4-7 (MED) - Hardgecodete LAN-IP in `extra_hosts`
|
||||
|
||||
`ops/komodo/docker-compose.yml:50` und `:101` haben:
|
||||
`"git.kaleschke.info:192.168.178.58"`.
|
||||
|
||||
Bare-Metal-Recovery auf anderer Hardware oder veraenderter LAN-IP fuehrt
|
||||
zu stummem Fehler: Komodo-Core kann Gitea nicht ueber den Override
|
||||
erreichen, faellt auf AdGuard-DNS zurueck (wenn der schon laeuft) oder
|
||||
scheitert.
|
||||
|
||||
Vorschlag: kurzer Hinweis in `DISASTER_RECOVERY.md` Phase 4 Stufe 3: "Bei
|
||||
geaenderter Host-LAN-IP `extra_hosts`-Werte in `ops/komodo/docker-compose.
|
||||
yml` vor `compose up` anpassen oder ueber `.env` parametrisieren."
|
||||
|
||||
### P4-8 (HIGH) - Stack-ENV-Wiederherstellung praktisch manuell
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:188-195` sagt: "Wenn `komodo-mongo.archive.gz`
|
||||
frisch ist, koennen die Werte beim Komodo-Restart aus dem Dump
|
||||
zurueckgespielt werden, ohne dass jemand sie sieht."
|
||||
|
||||
`docs/RESTORE_HANDBOOK.md:73-74` und `docs/AUDIT_2026-05-25_TODO.md:20`
|
||||
machen den Daten-Mongo-Restore als "erledigt 2026-06-03" sichtbar - aber
|
||||
NICHT als Teil des DR-Bootstraps. Komodo-Bootstrap im Trockenlauf benutzt
|
||||
Wegwerf-Werte.
|
||||
|
||||
Praktisch heisst das: Im DR-Bootstrap (Phase 4 Stufe 3) startet Komodo
|
||||
**ohne** den Mongo-Daten-Restore. Die `KOMODO_*` kommen aus externer
|
||||
Notiz. Aber die Stack-ENVs fuer `paperless`/`immich`/`mail-archiver`/
|
||||
`speedtest` (PAPERLESS_DBPASS etc.) **muessen vor Stufe 4** wieder in
|
||||
Komodo eingetragen sein. Wenn der Mongo-Daten-Restore nicht direkt nach
|
||||
Komodo-Start passiert, gehen diese Werte manuell in die Komodo-UI.
|
||||
|
||||
Vorschlag: Klarstellung in `DISASTER_RECOVERY.md` Phase 4 zwischen Stufe
|
||||
3 und Stufe 4: "Optionaler Mongo-Daten-Restore aus `komodo-mongo.archive.
|
||||
gz` per `ops/restore-tests/komodo-mongo-restore-test.sh`-Muster - dann
|
||||
sind alle Stack-ENVs zurueck. Alternativ: Stack-ENVs manuell in Komodo-
|
||||
UI eintragen, Quelle Vaultwarden (sobald Stufe 4 Vaultwarden laeuft -
|
||||
Henne-Ei mit Paperless: Paperless-Start dann erst nach Vaultwarden, nicht
|
||||
parallel)."
|
||||
|
||||
## Phase 5 - Verifikation
|
||||
|
||||
### P5-1 (LOW) - Smoke-Tests in DR.md weniger streng als Matrix
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:337-345` Phase 5.3 sagt z. B. "Vaultwarden
|
||||
startet und ist erreichbar". `docs/RESTORE_MATRIX.md:39` sagt: "Login-
|
||||
Seite erreichbar, Tresor-Daten sichtbar". Das zweite ist faktisch der
|
||||
echte Smoke-Test.
|
||||
|
||||
Geschmackssache, kein Bug. Empfehlung: DR.md auf die Matrix-Smokes
|
||||
verweisen statt eigene Kurzversion.
|
||||
|
||||
### P5-2 (MED) - Kein Verifikationspunkt App-zu-DB-Verbindung
|
||||
|
||||
`docs/DISASTER_RECOVERY.md:337-345` prueft App-Start, nicht DB-Auth-
|
||||
Erfolg. Bei falschem `PAPERLESS_DBPASS`-Stack-ENV startet Paperless
|
||||
moeglicherweise mit Error-Log und ist via Traefik nicht antwortend - aber
|
||||
das fehlt als Pruefpunkt.
|
||||
|
||||
Vorschlag: Phase 5.3 ergaenzen: "Pro App: `docker logs <app>` zeigt keine
|
||||
`password authentication failed`/`FATAL: role does not exist`-Eintraege."
|
||||
|
||||
## Uebergreifende Findings
|
||||
|
||||
### X-1 (HIGH) - Nextcloud-Restore-Skript existiert, ist aber ungetestet
|
||||
|
||||
`ops/restore-tests/nextcloud-restore-test.sh` und
|
||||
`ops/restore-tests/nextcloud-compose.test.yml` existieren im Repo.
|
||||
`docs/RESTORE_MATRIX.md:147` Spalte "Letzter Restore-Test" fuer Nextcloud:
|
||||
`-`, naechster Lauf `**hoechste Prio**`. `docs/AUDIT_2026-05-25_TODO.md:18`
|
||||
fuehrt es als P1 "offen".
|
||||
|
||||
Damit ist der echte Tabletop-Gewinn: der Test ist nicht "noch zu bauen",
|
||||
sondern "noch nie ausgefuehrt". Ein `bash /mnt/user/services/homelab-
|
||||
infra/ops/restore-tests/nextcloud-restore-test.sh` schliesst die letzte
|
||||
Tier-2-Luecke.
|
||||
|
||||
## Nicht-Findings
|
||||
|
||||
Was ich gepruft und als sauber verifiziert habe:
|
||||
|
||||
- Referenzierte Skripte existieren alle: `pre-backup-dumps.sh`,
|
||||
`gitea-bundle-mirror.sh`, `run-restore-checks.sh`,
|
||||
`komodo-bootstrap-test.sh`, `posture-check.sh`, alle Restore-Test-
|
||||
Skripte fuer Tier-1 und Tier-2.
|
||||
- Pfadverweise zwischen DR.md, RESTORE_MATRIX.md, SECRETS_MAP.md,
|
||||
SERVICES_RECOVERY.md sind konsistent (Borg-Dumps unter `/mnt/user/
|
||||
backups/borg/dumps/latest`, Secrets unter `/mnt/user/appdata/secrets`).
|
||||
- Drift-Erkennung Authelia (`services/authelia-diff.sh`) ist in
|
||||
`posture-check` integriert (`WORKFLOW.md:292`).
|
||||
- GitHub-Mirror-Pfad und Gitea-Bundle-Mirror als Repo-Bootstrap-Quellen
|
||||
sind dreifach abgesichert (lokaler Clone, GitHub, Bundle).
|
||||
- Tier-1-Postgres-Restore-Drill ist 2026-06-03 erfolgreich gelaufen
|
||||
(`AUDIT_2026-05-25_TODO.md:19`).
|
||||
- `ops/komodo/docker-compose.yml` ist als Recovery-Anker getestet
|
||||
(`SERVICES_RECOVERY.md:142-166`).
|
||||
- Borg-Passphrase und Hetzner-Account-Hygiene sind Operator-bestaetigt
|
||||
(`AUDIT_2026-05-25_TODO.md:46-47`).
|
||||
|
||||
## Vorschlag fuer Reihenfolge der Folge-Arbeit
|
||||
|
||||
1. **CRITICAL P1-1 zuerst** - Operator-Laptop-Voraussetzung als
|
||||
DR-Pflichtposten dokumentieren. Eine Dokuzeile.
|
||||
2. **HIGH P0-2 + P3-3** - klaeren, ob GitHub-Mirror lesend public ist und
|
||||
wo der Hetzner-Maintenance-Key offline liegt. Zwei Dokuzeilen oder
|
||||
eine echte Setup-Entscheidung.
|
||||
3. **HIGH P2-1** - Operator-Bestaetigung "KOMODO_*-Notiz offline
|
||||
gesichert YYYY-MM-DD" in `EXTERNAL_DEPENDENCIES.md` ergaenzen (sobald
|
||||
real angelegt).
|
||||
4. **HIGH P4-1 + P4-2** - Vorlauf "Stufe 0 - Docker-Grundlage" und
|
||||
LE-Staging-Hinweis in DR.md Phase 4 einfuegen. Etwa 10 Zeilen Doku.
|
||||
5. **HIGH X-1** - `nextcloud-restore-test.sh` einmal scharf ausfuehren.
|
||||
Vermutlich ein Vormittag inklusive Report-Review.
|
||||
6. **HIGH P2-2 + P4-8** - Reihenfolgen-Konsistenz Komodo/Vaultwarden in
|
||||
DR.md eindeutig aufloesen.
|
||||
7. Rest in der Reihenfolge der Tabelle.
|
||||
|
||||
Punkte 1-4 sind reine Doku-Arbeit, keine Compose-/Runtime-Aenderung.
|
||||
Punkt 5 ist ein echter Restore-Lauf mit Report. Punkt 6 ist die
|
||||
substanziellste Doku-Aenderung in DR.md.
|
||||
|
||||
## Folge-Iteration 2026-06-03 (Doku-Fixes im selben Aenderungsblock)
|
||||
|
||||
Direkt nach dem Drill und nach Operator-Antworten auf vier offene Fragen wurden folgende Findings im Repo adressiert. Operator-Aufgaben, die ich nicht selbst tun kann, sind als P1 in `docs/AUDIT_2026-05-25_TODO.md` aufgenommen.
|
||||
|
||||
| ID | Massnahme |
|
||||
|---|---|
|
||||
| P0-1 | DR.md Phase 0 ergaenzt um "Operativer Pfad fuer den Repo auf den frisch installierten Unraid-Host" (USB/SMB/rsync); DR.md Abschnitt 3 mit Zeile "Operator-DR-Workstation"; `EXTERNAL_DEPENDENCIES.md` neuer Abschnitt "DR-Workstation Bare-Metal-Kit" |
|
||||
| P0-2 | `EXTERNAL_DEPENDENCIES.md` GitHub-Mirror-Zeile praezisiert (privat, Read-PAT/Deploy-Key Pflicht); DR.md Phase 0 verweist explizit darauf; offene Operator-Aufgabe in Audit-Restliste |
|
||||
| P1-1 | Operator-DR-Workstation als Voraussetzung in DR.md Abschnitt 3 und in `EXTERNAL_DEPENDENCIES.md`; konkrete Pflichtbestandteile (WSL2, Borg, SSH-Key) gelistet |
|
||||
| P1-2 | Bleibt offen als P3-Test in Restore-Backlog (kein Doku-Fix moeglich) |
|
||||
| P2-1 | KOMODO_*-Notiz als kritische Secret-Zeile in `EXTERNAL_DEPENDENCIES.md` mit Status "noch nicht angelegt"; Operator-Aufgabe in Audit-Restliste |
|
||||
| P2-2 | DR.md Phase 4 Stufe 3 ergaenzt um expliziten Hinweis "KOMODO_* aus externer Notiz oder voraus gezogener Vaultwarden" |
|
||||
| P2-3 | DR.md Abschnitt 6.1 um `homelab_smtp_password.txt` erweitert |
|
||||
| P2-4 | DR.md Abschnitt 6.1 um `n8n_encryption_key.txt` erweitert |
|
||||
| P2-5 | DR.md Abschnitt 6.1 um Monitoring-Grafana/InfluxDB-/Filebrowser-Secrets erweitert |
|
||||
| P3-1 | DR.md neuer Abschnitt 7.3 "Borg-Extract ohne `borg-ui`-Container" mit DR-Workstation- und Docker-Variante |
|
||||
| P3-2 | DR.md Abschnitt 7.3 nennt Passphrase-Eingabe explizit als interaktiven Bootstrap-Schritt |
|
||||
| P3-3 | `EXTERNAL_DEPENDENCIES.md` Review-Zeile 2026-06-03: Hetzner-Maintenance-Key auch offline bestaetigt |
|
||||
| P4-1 | DR.md Phase 4 neue Stufe 0 "Docker-Grundlage" mit `docker network create` Befehlen |
|
||||
| P4-2 | DR.md Phase 4 Stufe 1 LE-Staging-Hinweis bei verlorenem `acme.json` |
|
||||
| P4-3 | DR.md Phase 4 Stufe 0 nennt `traefik/dynamic/*` als Pre-Check |
|
||||
| P4-4 | Wird mit fresh-Postgres-Initialisierungsskripten ohne Doku-Aenderung nicht sinnvoll abgedeckt; bleibt als Doku-Hinweis offen, ist im realen Restore-Pfad mit `pg_dumpall --globals-only` abgedeckt |
|
||||
| P4-5 | LOW, nicht angepasst (Reihenfolge nicht falsch, nur irrefuehrend) |
|
||||
| P4-6 | DR.md Phase 4 Stufe 3 "Wichtige Stolperfallen": Mongo-Datadir/Secret-Mismatch und Re-Init-Pfad |
|
||||
| P4-7 | DR.md Phase 4 Stufe 3 "Wichtige Stolperfallen": `extra_hosts`-Anpassung bei IP-Wechsel |
|
||||
| P4-8 | DR.md Phase 4 Stufe 3 "Wichtige Stolperfallen": Stack-ENV-Wiederherstellung per `mongorestore` oder manuell |
|
||||
| P5-1 | LOW, nicht angepasst |
|
||||
| P5-2 | DR.md Phase 5.3 um `docker logs`-Verifikation der App-zu-DB-Verbindung erweitert |
|
||||
| X-1 | **erledigt 2026-06-03**: Nextcloud-Restore-Test scharf gelaufen, drei Iterationen (zwei Skript-Bugs gefixt), Endresultat SUCCESS mit HTTP 200, occ status ok, 126 DB-Tabellen. Damit ist Tier-2 vollstaendig belegt. |
|
||||
|
||||
Nicht angefasst: P1-2 (kein Doku-Fix moeglich), P4-4 (im echten Restore-Pfad ohnehin abgedeckt), P4-5 und P5-1 (LOW). Die offenen Operator-Aufgaben (KOMODO_*-Notiz, Read-PAT, DR-Workstation, Nextcloud-Restore) stehen jetzt in `docs/AUDIT_2026-05-25_TODO.md` als P1.
|
||||
|
||||
## Reproduktion dieses Drills
|
||||
|
||||
```text
|
||||
Methode: kalter Lesetest gegen
|
||||
- docs/DISASTER_RECOVERY.md
|
||||
- docs/RESTORE_MATRIX.md
|
||||
- docs/SECRETS_MAP.md
|
||||
- docs/SERVICES_RECOVERY.md
|
||||
- docs/RESTORE_HANDBOOK.md
|
||||
- docs/EXTERNAL_DEPENDENCIES.md
|
||||
- ops/komodo/docker-compose.yml
|
||||
- traefik/docker-compose.yml
|
||||
Verifizierte Skript-Existenz: ops/borg-ui/scripts/*, ops/restore-tests/*,
|
||||
services/posture-check/*
|
||||
Kein Container gestartet, kein Skript ausgefuehrt, keine produktiven
|
||||
Pfade beruehrt.
|
||||
```
|
||||
@@ -1,86 +0,0 @@
|
||||
# baerchen App-/Lizenz-Readiness - 2026-06-06
|
||||
|
||||
Automatisch erzeugter lokaler Check. Keine Lizenzkeys, Passwoerter, Tokens oder Recovery-Code-Werte wurden ausgelesen oder ins Repo geschrieben.
|
||||
|
||||
## Ergebnis
|
||||
|
||||
- Technische Inventarisierung: erledigt
|
||||
- Manuelle Konto-/Recovery-Bestaetigung: erledigt laut Operator-Bestaetigung 2026-06-06 ("alle Dienste laufen")
|
||||
|
||||
## Installierte Programme
|
||||
|
||||
### Passwortmanager / Browser
|
||||
|
||||
| DisplayName | DisplayVersion | Publisher | InstallDate |
|
||||
| --- | --- | --- | --- |
|
||||
| Brave | 149.1.91.168 | Die Brave-Autoren | 20260604 |
|
||||
| Google Chrome | 149.0.7827.54 | Google LLC | 20260604 |
|
||||
| Microsoft Edge | 148.0.3967.96 | Microsoft Corporation | 20260604 |
|
||||
| Microsoft Edge WebView2-Laufzeit | 148.0.3967.96 | Microsoft Corporation | 20260604 |
|
||||
|
||||
### Banking4 / Subsembly
|
||||
|
||||
| DisplayName | DisplayVersion | Publisher | InstallDate |
|
||||
| --- | --- | --- | --- |
|
||||
| Banking4 Home | | Subsembly GmbH | |
|
||||
|
||||
### WISO / Buhl
|
||||
|
||||
| DisplayName | DisplayVersion | Publisher | InstallDate |
|
||||
| --- | --- | --- | --- |
|
||||
| WISO Steuer 2026 | 33.07.3410 | Buhl Data Service GmbH | 20260604 |
|
||||
|
||||
### Microsoft 365 / Office / OneDrive
|
||||
|
||||
| DisplayName | DisplayVersion | Publisher | InstallDate |
|
||||
| --- | --- | --- | --- |
|
||||
| Microsoft 365 - de-de | 16.0.20026.20140 | Microsoft Corporation | |
|
||||
| Microsoft 365 - en-us | 16.0.20026.20140 | Microsoft Corporation | |
|
||||
| Microsoft OneDrive | 23.038.0219.0001 | Microsoft Corporation | |
|
||||
| Office 16 Click-to-Run Extensibility Component | 16.0.20026.20076 | Microsoft Corporation | 20260604 |
|
||||
| Office 16 Click-to-Run Localization Component | 16.0.20026.20140 | Microsoft Corporation | 20260604 |
|
||||
|
||||
## Relevante Datenpfade
|
||||
|
||||
| Path | Exists | Type | LastWriteTime | Bytes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| C:\Users\michi\AppData\Local\Subsembly | True | Directory | 2026-06-04T12:23:43 | 43360359 |
|
||||
| C:\Users\michi\AppData\Local\Buhl | True | Directory | 2026-06-04T12:55:57 | 680833 |
|
||||
| C:\Users\michi\AppData\Local\Buhl Data Service GmbH | False | | | |
|
||||
| C:\ProgramData\Buhl Data Service GmbH | True | Directory | 2026-06-04T12:57:08 | 6037194 |
|
||||
| C:\Users\michi\Documents\steuer | True | Directory | 2026-01-26T11:21:44 | 13069132 |
|
||||
| C:\Users\michi\Desktop\Banking | False | | | |
|
||||
| C:\Users\michi\OneDrive | True | Directory | 2026-06-04T12:39:24 | 39370265 |
|
||||
| D:\30_Finanzen | True | Directory | 2026-06-04T20:14:26 | 128994854 |
|
||||
| D:\30_Finanzen\Recovery-Codes | False | | | |
|
||||
| D:\30_Finanzen\BitLocker-RecoveryKey-baerchen-2026-06-06.txt | False | | | |
|
||||
|
||||
## OneDrive / Microsoft 365 Indikatoren
|
||||
|
||||
### OneDrive Prozess
|
||||
|
||||
_Keine Treffer._
|
||||
|
||||
### OneDrive Accounts Registry
|
||||
|
||||
| PSChildName |
|
||||
| --- |
|
||||
| Business1 |
|
||||
| Personal |
|
||||
|
||||
### Office Aktivierungsindikatoren
|
||||
|
||||
_Keine Office-OSPP-Aktivierungsdaten gefunden oder Office nicht klassisch installiert._
|
||||
|
||||
## Manuell noch zu bestaetigen
|
||||
|
||||
- [x] Passwortmanager laesst sich oeffnen und enthaelt Homelab-/Banking-/Provider-Eintraege.
|
||||
- [x] 2FA-Recovery-Codes fuer Microsoft, Hetzner, Cloudflare, Tailscale, Gitea/GitHub und Banken sind offline oder in Vaultwarden auffindbar.
|
||||
- [x] Banking4 oeffnet den aktuellen Datentresor; ein frischer Backup-/Exportpfad ist bekannt.
|
||||
- [x] WISO Steuer 2026 oeffnet, Buhl-Konto/Lizenz ist aktiv, Steuerdateien unter `C:\Users\michi\Documents\steuer` bzw. neuem Zielpfad sind sichtbar.
|
||||
- [x] Microsoft-Konto zeigt aktives M365/Office-Installationsrecht.
|
||||
- [x] OneDrive-Sync ist angemeldet und synchronisiert die erwarteten Ordner.
|
||||
|
||||
## Bewertung
|
||||
|
||||
Dieses Dokument belegt die technische Inventarisierung und die Operator-Bestaetigung vom 2026-06-06. Secret-Werte, Lizenzkeys und Recovery-Code-Werte wurden nicht dokumentiert.
|
||||
@@ -1,132 +0,0 @@
|
||||
# Boot-Cleanup-Plan 2026-06-04
|
||||
|
||||
## Ziel
|
||||
|
||||
`F:` ist das alte Windows und soll spaeter verschwinden. Vor Loeschen/Formatieren/Resize muss das neue Windows beweisen, dass es ohne `F:` bootet und keine BCD-/Resume-Abhaengigkeit mehr auf `F:` zeigt.
|
||||
|
||||
Noch keine Partition wird geloescht, formatiert oder erweitert.
|
||||
|
||||
## Aktueller Befund
|
||||
|
||||
- Neues Windows: `C:\WINDOWS`
|
||||
- Alter Loader: `Windows 11 Alt`
|
||||
- Alter Loader zeigt auf `partition=F:`
|
||||
- Alter Resume-Eintrag zeigt auf `partition=F:` und `F:\hiberfil.sys`
|
||||
- Boot Manager referenziert aktuell noch den alten Resume-Eintrag.
|
||||
- Aktives Pagefile ist nur `C:\pagefile.sys`.
|
||||
- `D:\pagefile.sys` und `E:\pagefile.sys` sind inaktive Altlasten, lassen sich aber ohne Adminrechte nicht entfernen.
|
||||
|
||||
## Vorbereitete Skripte
|
||||
|
||||
Im Arbeitsordner `C:\Users\michi\Documents\Neues Windows`:
|
||||
|
||||
- `boot-cleanup-freigabe-f-vorbereitung.ps1`
|
||||
- `start-boot-cleanup-admin.cmd`
|
||||
|
||||
Der Syntaxcheck des PowerShell-Skripts wurde ausgefuehrt. Es laedt korrekt und stoppt ohne Adminrechte erwartbar mit:
|
||||
|
||||
```text
|
||||
Dieses Skript muss als Administrator laufen.
|
||||
```
|
||||
|
||||
## Geplanter Admin-Block
|
||||
|
||||
Das Skript fuehrt mit Adminrechten aus:
|
||||
|
||||
1. Backupordner unter `C:\Temp\boot_cleanup_<timestamp>` anlegen.
|
||||
2. BCD, WinRE, Volumes, Partitionen und Pagefiles vor der Aenderung protokollieren.
|
||||
3. BCD exportieren nach `BCD-before-cleanup.bak`.
|
||||
4. `{bootmgr}` `resumeobject` auf den aktuellen C:-Resume-Eintrag setzen.
|
||||
5. Alten Loader `Windows 11 Alt` aus der Boot-Anzeige entfernen.
|
||||
6. Alten Loader loeschen.
|
||||
7. Alten F:-Resume-Eintrag loeschen.
|
||||
8. Inaktive Alt-Pagefiles `D:\pagefile.sys` und `E:\pagefile.sys` entfernen.
|
||||
9. BCD, WinRE und Pagefiles danach erneut protokollieren.
|
||||
|
||||
## Nicht enthalten
|
||||
|
||||
- Kein Loeschen von `F:`.
|
||||
- Kein Formatieren von `E:`.
|
||||
- Kein Resize von Partitionen.
|
||||
- Kein Entfernen von Recovery-Partitionen.
|
||||
- Kein Veraendern von `G:` / Homelab / EFI-Systempartition.
|
||||
|
||||
## Danach notwendig
|
||||
|
||||
1. Neustart.
|
||||
2. Pruefen, ob Windows sauber bootet.
|
||||
3. `bcdedit /enum all` pruefen: keine `partition=F:` Referenz mehr.
|
||||
4. Pagefiles pruefen: nur `C:\pagefile.sys` aktiv, `D:\pagefile.sys` und `E:\pagefile.sys` weg.
|
||||
5. Erst danach `F:` als technisch freigegeben markieren.
|
||||
|
||||
## Ausgefuehrt 2026-06-04 17:25
|
||||
|
||||
Der Admin-Block wurde ausgefuehrt. Log-/Backup-Ordner:
|
||||
|
||||
- `C:\Temp\boot_cleanup_20260604_172547`
|
||||
- BCD-Backup: `C:\Temp\boot_cleanup_20260604_172547\BCD-before-cleanup.bak`
|
||||
- Log: `C:\Temp\boot_cleanup_20260604_172547\boot_cleanup_log.txt`
|
||||
|
||||
Ergebnis laut Admin-Log:
|
||||
|
||||
- `{bootmgr}` `resumeobject` wurde auf den aktuellen C:-Resume-Eintrag `{f6daf1c6-6f16-11f0-992f-bc6ee2f9d6ec}` gesetzt.
|
||||
- `Windows 11 Alt` wurde aus `displayorder` entfernt.
|
||||
- Alter Loader `{f6daf1bd-6f16-11f0-992f-bc6ee2f9d6ec}` wurde geloescht.
|
||||
- Alter F:-Resume-Eintrag `{f6daf1bc-6f16-11f0-992f-bc6ee2f9d6ec}` war nach dem Loader-Cleanup bereits nicht mehr auffindbar.
|
||||
- `D:\pagefile.sys` wurde entfernt.
|
||||
- `E:\pagefile.sys` wurde entfernt.
|
||||
|
||||
After-BCD aus Admin-Log:
|
||||
|
||||
- `displayorder` enthaelt nur noch `{current}`.
|
||||
- `Windows 11 Neu` zeigt auf `device partition=C:` und `osdevice partition=C:`.
|
||||
- Resume zeigt auf `partition=C:`.
|
||||
- Im After-BCD-Log sind keine `partition=F:`-Eintraege mehr sichtbar.
|
||||
|
||||
After-Pagefiles:
|
||||
|
||||
- Aktiv: `C:\pagefile.sys`
|
||||
- Vorhanden: `C:\hiberfil.sys`, `C:\pagefile.sys`, `C:\swapfile.sys`
|
||||
- Alte Dateien auf `D:` und `E:` sind weg.
|
||||
- Auf `F:` liegen weiterhin alte `hiberfil.sys`/`swapfile.sys` des alten Windows; diese bleiben bis zur finalen F:-Bereinigung unangetastet.
|
||||
|
||||
Unabhaengige Nachpruefung aus normaler Codex-Shell:
|
||||
|
||||
- `D:` frei: ca. 126.3 GB
|
||||
- `E:` frei: ca. 629.5 GB
|
||||
- `Get-CimInstance Win32_PageFileUsage` meldet nur `C:\pagefile.sys`
|
||||
|
||||
Verbleibend nach Neustarttest:
|
||||
|
||||
- `F:` ist nach erfolgreichem Neustarttest technisch von der Boot-Konfiguration entkoppelt.
|
||||
- WinRE war nach dem Cleanup `Disabled`. **Erledigt 2026-06-05:** WinRE wurde im Admin-Nachlauf (siehe `laufwerks-neustruktur-2026-06-04.md` Abschnitt "Admin-Nachlauf 2026-06-05") mit `reagentc /setreimage` und `reagentc /enable` repariert und aktiviert. `Windows RE-Status: Enabled`, Version `10.0.26100.8455`.
|
||||
|
||||
## Neustarttest 2026-06-04 17:27
|
||||
|
||||
Nach dem Cleanup wurde Windows erfolgreich neu gestartet.
|
||||
|
||||
Post-Reboot-Status:
|
||||
|
||||
- `LastBootUpTime`: 2026-06-04 17:27:56
|
||||
- Neues Windows laeuft weiter von `C:\WINDOWS`.
|
||||
- `D:\pagefile.sys` und `E:\pagefile.sys` sind weiterhin weg.
|
||||
- Aktives Pagefile: `C:\pagefile.sys`
|
||||
|
||||
Post-Reboot-Bootreport:
|
||||
|
||||
- `C:\Temp\bcd_post_reboot_latest.txt`
|
||||
- `C:\Temp\winre_post_reboot_latest.txt`
|
||||
|
||||
Ergebnis:
|
||||
|
||||
- Keine sichtbare `partition=F:`-Referenz im BCD-Post-Reboot-Report.
|
||||
- `displayorder` enthaelt nur `{current}`.
|
||||
- `Windows 11 Neu` zeigt auf `device partition=C:` und `osdevice partition=C:`.
|
||||
- Resume zeigt auf `partition=C:`.
|
||||
- Historischer Post-Reboot-Stand war: WinRE blieb `Disabled`. Nachlauf
|
||||
2026-06-05: WinRE ist `Enabled`; siehe Erledigt-Hinweis oben.
|
||||
|
||||
Bewertung:
|
||||
|
||||
- `F:` ist aus Boot-/Resume-Sicht technisch freigegeben.
|
||||
- Partitionen wurden weiterhin nicht geloescht, formatiert oder erweitert.
|
||||
@@ -1,137 +0,0 @@
|
||||
# DR-Workstation Readiness - 2026-06-06
|
||||
|
||||
Automatisch erzeugter lokaler Readiness-Check fuer den Operator-PC. Es wurden keine Secret-Werte, Passphrases oder Private-Key-Inhalte ausgegeben.
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
| Check | Ergebnis |
|
||||
|---|---|
|
||||
| WSL2 Ubuntu | vorhanden (`Ubuntu 24.04`, WSL Version 2) |
|
||||
| SSH/Git in WSL | vorhanden |
|
||||
| GitHub-Read-Smoke mit DR-Key | ok |
|
||||
| Borg Client | installiert |
|
||||
| Hetzner Storage Box mit DR-Key | ok |
|
||||
| `~/dr-smoke.sh` | vorhanden |
|
||||
| Finaler Borg-Smoke | ok, Operator-Bestaetigung 2026-06-06 10:05:30 |
|
||||
| WSL sudo ohne Passwortprompt | nein, Operator muss Passwort eingeben |
|
||||
|
||||
## Bewertung
|
||||
|
||||
- Der lokale WSL2-/Ubuntu-Unterbau ist vorhanden.
|
||||
- Die DR-Key-Arbeitskopien liegen in WSL unter `~/.ssh/dr-readonly` und `~/.ssh/dr-hetzner`.
|
||||
- GitHub-Read-Smoke und Hetzner-SSH-Smoke sind erfolgreich.
|
||||
- `borgbackup` ist installiert.
|
||||
- Der vollstaendige Bare-Metal-DR-Smoke ist erfolgreich abgeschlossen.
|
||||
|
||||
## Finaler Borg-Smoke
|
||||
|
||||
Operator-Bestaetigung vom 2026-06-06:
|
||||
|
||||
- Befehl: `bash ~/dr-smoke.sh`
|
||||
- GitHub Deploy-Key: HEAD `3a263a4...`
|
||||
- Hetzner SSH-Login: Repos `backup`, `backup2`, `hetzner_borg_appdata`, `hetzner_borg_appdata_critical` sichtbar
|
||||
- Borg-Repo: `ssh://u565255@u565255.your-storagebox.de/./hetzner_borg_appdata_critical`
|
||||
- Repository ID: `5dd9b949...`
|
||||
- Encryption: `Yes (repokey)`
|
||||
- Borg-Statistik: `Original size 1.16 TB`, `Compressed size 1.13 TB`, `Deduplicated size 35.92 GB`
|
||||
- Ergebnis: `DR-Smoke OK (2026-06-06 10:05:30)`
|
||||
|
||||
Die Borg-Passphrase wurde nur interaktiv eingegeben und nicht dauerhaft auf `baerchen` gespeichert.
|
||||
|
||||
## Rohchecks
|
||||
|
||||
### wsl_status
|
||||
|
||||
- ExitCode: `0`
|
||||
|
||||
```text
|
||||
Standarddistribution: Ubuntu
|
||||
|
||||
Standardversion: 2
|
||||
|
||||
|
||||
```
|
||||
|
||||
### wsl_list
|
||||
|
||||
- ExitCode: `0`
|
||||
|
||||
```text
|
||||
NAME STATE VERSION
|
||||
|
||||
* Ubuntu Stopped 2
|
||||
|
||||
docker-desktop Stopped 2
|
||||
|
||||
|
||||
```
|
||||
|
||||
### ubuntu_os
|
||||
|
||||
- ExitCode: `0`
|
||||
|
||||
```text
|
||||
Distributor ID: Ubuntu
|
||||
Description: Ubuntu 24.04.4 LTS
|
||||
Release: 24.04
|
||||
Codename: noble
|
||||
6.6.114.1-microsoft-standard-WSL2
|
||||
```
|
||||
|
||||
### tools
|
||||
|
||||
- ExitCode: `0`
|
||||
|
||||
```text
|
||||
/usr/bin/borg
|
||||
borg 1.2.8
|
||||
/usr/bin/ssh
|
||||
OpenSSH_9.6p1 Ubuntu-3ubuntu13.16, OpenSSL 3.0.13 30 Jan 2024
|
||||
/usr/bin/git
|
||||
git version 2.43.0
|
||||
```
|
||||
|
||||
### sudo
|
||||
|
||||
- ExitCode: `0`
|
||||
|
||||
```text
|
||||
sudo-password-needed
|
||||
```
|
||||
|
||||
### wsl_ssh_files
|
||||
|
||||
- ExitCode: `0`
|
||||
|
||||
```text
|
||||
total 40
|
||||
drwx------ 2 michi michi 4096 Jun 6 09:14 .
|
||||
drwxr-x--- 5 michi michi 4096 Jun 6 08:37 ..
|
||||
-rw------- 1 michi michi 411 Jun 6 09:14 dr-hetzner
|
||||
-rw------- 1 michi michi 419 Jun 6 09:14 dr-readonly
|
||||
-rw------- 1 michi michi 411 Apr 4 19:29 id_ed25519
|
||||
-rw-r--r-- 1 michi michi 97 Apr 4 19:29 id_ed25519.pub
|
||||
-rw------- 1 michi michi 6358 Jun 6 09:14 known_hosts
|
||||
-rw------- 1 michi michi 3013 Apr 20 20:13 known_hosts.old
|
||||
-rw------- 1 michi michi 3858 Apr 24 08:27 known_hosts.pre-port222-20260604-122031.bak
|
||||
-rwxr-xr-x 1 michi michi 1311 Jun 6 08:37 /home/michi/dr-smoke.sh
|
||||
```
|
||||
|
||||
### github_dr_key_smoke
|
||||
|
||||
- ExitCode: `0`
|
||||
|
||||
```text
|
||||
68d3ace598ee4d1cdad3ed94b63ae5046ac187fb HEAD
|
||||
```
|
||||
|
||||
### hetzner_dr_key_smoke
|
||||
|
||||
- ExitCode: `0`
|
||||
|
||||
```text
|
||||
backup
|
||||
backup2
|
||||
hetzner_borg_appdata
|
||||
hetzner_borg_appdata_critical
|
||||
```
|
||||
@@ -1,401 +0,0 @@
|
||||
# Homelab-Doku-Optimierung — Analyse und Vorschlag 2026-06-11
|
||||
|
||||
Typ: Analyse / Optimierungsvorschlag · Stand: 2026-06-11 · Status: **umgesetzt am 2026-06-11** (archiviert; siehe `docs/DECISIONS.md` Eintrag 2026-06-11). Nicht umgesetzt blieben nur: Hermes-README-Kuerzung (beim Review 2026-07-25), PDF-Ablage extern (Operator), optionale Projekte aus Abschnitt 13.
|
||||
|
||||
Read-only-Analyse der gesamten Markdown-Dokumentation (Stand `master`, lokale
|
||||
Arbeitskopie 2026-06-11). Es wurde nichts gelöscht, verschoben oder verändert;
|
||||
dieses Dokument ist der einzige neue Inhalt. Abgrenzung: `docs/homelab-optimierung.md`
|
||||
(2026-06-10) bewertet die **technische** Betriebsebene; dieses Dokument bewertet
|
||||
ausschließlich die **Dokumentation und ihre Regeln**.
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
Die Doku ist inhaltlich exzellent und ungewöhnlich diszipliniert gepflegt —
|
||||
das Problem ist nicht Qualität oder Veralterung, sondern **Volumen, Mehrfachpflege
|
||||
und fehlende Lebenszyklus-Regeln**. Kennzahlen:
|
||||
|
||||
- **74 versionierte Markdown-Dateien, ~9.400 Zeilen** (davon `docs/`: 35 Dateien / ~5.050 Zeilen, `ops/`: 34 Dateien).
|
||||
- Praktisch alle Dateien wurden in den letzten 4 Wochen angefasst — es gibt **kein Stale-Problem, aber ein Pflegelast-Problem**.
|
||||
- Ein einzelner Sachverhalt wird heute an **6–9 Stellen** dokumentiert (Beispiele in Abschnitt 3.1). Jede Änderung erzeugt dadurch eine Update-Kaskade über viele Dateien.
|
||||
- Vier parallele Status-/To-do-Listen plus Done-Logs in fast jedem Dokument.
|
||||
- Abgeschlossene Sprints, Audits und Pläne bleiben als aktive Dateien liegen, obwohl `docs/README.md` (Zeile 5) genau das verbietet — die Policy existiert, wird aber nicht durchgesetzt.
|
||||
|
||||
Kernempfehlung in einem Satz: **Nicht umstrukturieren, sondern konsolidieren** —
|
||||
jeder Fakt bekommt genau ein Zuhause, Erledigtes verlässt die Arbeitskopie,
|
||||
und ein neues Entscheidungs-Register (`docs/DECISIONS.md`) ersetzt die heute
|
||||
über fünf Dateien verteilten Entscheidungs-Logs. Realistisches Ziel: **docs/ von
|
||||
35 auf ~22 aktive Dateien, Gesamtbestand von ~9.400 auf ~6.500 Zeilen**, ohne
|
||||
Wissensverlust (Git-Historie bleibt vollständig).
|
||||
|
||||
---
|
||||
|
||||
## 2. Aktueller Eindruck
|
||||
|
||||
### 2.1 Bestandsaufnahme
|
||||
|
||||
| Bereich | Dateien | Charakter |
|
||||
|---|---:|---|
|
||||
| Root (`README.md`, `CLAUDE.md`, `HOMELAB_ARCHITECTURE_MASTER_V2.md`) | 3 | Einstieg, KI-Regeln, Architektur-Master (502 Zeilen) |
|
||||
| `docs/` flach | 31 | Runbooks, Inventare, Statuslisten, Pläne, Snapshots — gemischt |
|
||||
| `docs/audit/` | 2 | Audit-Snapshots (Workstation-Audit, DR-Readiness) |
|
||||
| `docs/runbooks/` | 1 | neue Konvention, erst ein Dokument (`komodo-bulk-deploy-dns.md`) |
|
||||
| `ops/restore-tests/` | 14 | README, schedule, 6× plan.md, 4× runbook.md, Hilfsdoku |
|
||||
| `ops/windows-reinstall/docs/` | 8 | Workstation-Neuaufsetzen-Projekt vom Mai 2026, weitgehend abgeschlossen |
|
||||
| `ops/borg-ui/`, `ops/policy-checks/`, übrige `ops/` | 12 | Tool-Doku, teils mit historischen Audits und generierten Reports |
|
||||
| `monitoring/`, `services/` | 2 | Stack-/Skript-README |
|
||||
|
||||
`memory/` und `.serena/` sind gitignored (Tool-Caches) und nicht Teil des Korpus.
|
||||
|
||||
### 2.2 Stärken (bewusst erhalten)
|
||||
|
||||
- `docs/README.md` als gepflegter Index mit expliziter Aktiv-vs.-Historie-Policy.
|
||||
- `docs/REPO_MAP.md` enthält bereits eine Anti-Wildwuchs-Arbeitsregel ("Neue Doku nur, wenn dauerhaft als Runbook, Inventar oder Restliste gebraucht").
|
||||
- `docs/MASTER_TODO.md` hat Status-Kategorien (Aktiv/Entscheidung/Geparkt/Blockiert) mit Review-Triggern — das ist Best Practice.
|
||||
- Runbooks sind hochwertig: konkrete Kommandos, Erfolgskriterien, Rollback (z. B. `docs/GITOPS_DRIFT_RUNBOOK.md`, `docs/GUEST_IOT_NETWORK.md`).
|
||||
- Inventare trennen sauber Ist-Werte von Entscheidungen (`docs/HARDWARE_INVENTORY.md` "Betreiber-Entscheidungen").
|
||||
- Secret-Hygiene ist durchgängig: nur Namen/Pfade, nie Werte.
|
||||
- Konsistente Verweis-Kultur ("Verwandte Dokumente"-Blöcke).
|
||||
|
||||
Das eigentliche Asset — die Doku-Disziplin — soll erhalten bleiben. Die Optimierung
|
||||
zielt darauf, dass dieselbe Disziplin **weniger Schreibarbeit pro Ereignis** kostet.
|
||||
|
||||
---
|
||||
|
||||
## 3. Wichtigste Probleme
|
||||
|
||||
### 3.1 P1 — Mehrfachpflege: ein Fakt, viele Heimaten (Hauptproblem)
|
||||
|
||||
Gemessene Beispiele aus dem aktuellen Bestand:
|
||||
|
||||
| Sachverhalt | Anzahl Stellen | Fundorte |
|
||||
|---|---:|---|
|
||||
| Tailscale-Docker-Stack-Abbau (2026-06-06) | **9** | `CLAUDE.md` (Ausnahmen), `HOMELAB_ARCHITECTURE_MASTER_V2.md` (§7.1 + §10), `docs/SERVICE_CATALOG.md`, `docs/RESTORE_MATRIX.md`, `docs/DISASTER_RECOVERY.md` (Phase-4-Hinweis), `docs/NETWORK_INVENTORY.md`, `docs/MASTER_TODO.md` (Done-Log), `docs/AI_CONTEXT.md` |
|
||||
| Veeam-Erstbackup `baerchen` (53,8 GB / 0:11:31) | **8** | `docs/AI_CONTEXT.md`, `docs/MASTER_TODO.md` (2×), `docs/WEEKEND_STATUS_2026-06-05.md` (2×), `docs/WEEKEND_EXECUTION_PLAN_2026-06-05.md`, `docs/RESTORE_MATRIX.md`, `docs/DISASTER_RECOVERY.md` §10, `ops/windows-reinstall/docs/windows-image-backup-baseline.md` |
|
||||
| Leseliste / GitOps-Hierarchie | **7** | `README.md`, `CLAUDE.md`, `docs/AI_CONTEXT.md`, `docs/WORKFLOW.md`, `HOMELAB_ARCHITECTURE_MASTER_V2.md` (§11.4 + §12), `docs/README.md`, `docs/REPO_MAP.md` |
|
||||
| DR-Workstation-Smoke (2026-06-06) | **6** | `docs/EXTERNAL_DEPENDENCIES.md` (Review-Log), `docs/AUDIT_2026-05-25_TODO.md`, `docs/MASTER_TODO.md`, `docs/AI_CONTEXT.md`, `docs/audit/dr-workstation-readiness-2026-06-06.md`, `docs/DR_WORKSTATION_SETUP.md` (Einschub Schritt 6) |
|
||||
| Liste der dokumentierten Ausnahmen | **5** | `CLAUDE.md`, `docs/AI_CONTEXT.md`, `HOMELAB_ARCHITECTURE_MASTER_V2.md` §10 (autoritativ), `docs/SERVICE_CATALOG.md` (Spalten), `ops/policy-checks/` (kodiert) |
|
||||
| Restore-Test-Status je Dienst | **4–5** | `docs/RESTORE_MATRIX.md` (Reifegrad-Tabelle), `docs/RESTORE_HANDBOOK.md` §3, `ops/restore-tests/README.md` (Status), Done-Logs in `MASTER_TODO`/`AUDIT_2026-05-25_TODO` |
|
||||
| Komodo-Kaltstart | **3–4** | `docs/DISASTER_RECOVERY.md` Phase 4 Stufe 3, `docs/SERVICES_RECOVERY.md` Stufen A–F, `ops/restore-tests/komodo-bootstrap-runbook.md` (+ `-plan.md`) |
|
||||
|
||||
Ursache ist eine "Beleg-Kultur": jedes erledigte Ereignis wird als Nachweis in
|
||||
alle thematisch berührten Dokumente kopiert, statt einmal dokumentiert und
|
||||
verlinkt. Die Folge ist genau die Update-Kaskade, die `docs/WORKFLOW.md`
|
||||
("Dokumentationspflicht": 7 Dateien prüfen pro Änderung) institutionalisiert.
|
||||
|
||||
### 3.2 P2 — Vier parallele Statuslisten plus verteilte Done-Logs
|
||||
|
||||
- `docs/MASTER_TODO.md` erklärt sich selbst zur führenden Liste — richtig.
|
||||
- `docs/AUDIT_2026-05-25_TODO.md` bestätigt selbst, nur noch deckungsgleiche Restliste zu sein (1 offener Punkt); existiert faktisch nur als historische Hülle.
|
||||
- `docs/WEEKEND_EXECUTION_PLAN_2026-06-05.md` + `docs/WEEKEND_STATUS_2026-06-05.md`: Sprint ist seit 2026-06-07 vorbei, alle Punkte erledigt; `WEEKEND_STATUS` nennt sich selbst "kurzlebig".
|
||||
- `docs/AI_CONTEXT.md` führt einen eigenen Status-Block ("Aktuelle Restpunkte", "Letzte Bestaetigung", Zeilen 44–84), der `MASTER_TODO` dupliziert und bei jedem Ereignis mitgepflegt werden muss.
|
||||
- Dazu eigene To-do-/Backlog-Abschnitte in `docs/DISASTER_RECOVERY.md` (§11), `docs/RESTORE_HANDBOOK.md` (§11), `docs/SERVICES_RECOVERY.md` ("Naechste Aufgaben" — alle erledigt), `docs/SERVICE_CATALOG.md` ("Bekannte offene Fragen").
|
||||
- Done-Logs wachsen unbegrenzt: `MASTER_TODO` besteht zu ~60 % aus dem Erledigt-Block; `docs/EXTERNAL_DEPENDENCIES.md` trägt 11 Review-Zeilen, die dieselben Ereignisse erneut erzählen.
|
||||
|
||||
### 3.3 P3 — Restore-/DR-Wissen auf zu viele Schichten verteilt
|
||||
|
||||
Sechs `docs/`-Dateien (`DISASTER_RECOVERY`, `RESTORE_MATRIX`, `RESTORE_HANDBOOK`,
|
||||
`SERVICES_RECOVERY`, `ROLLBACK`, `GITOPS_DRIFT_RUNBOOK`) plus 14 Dateien unter
|
||||
`ops/restore-tests/`. Konkrete Überschneidungen:
|
||||
|
||||
- `docs/RESTORE_MATRIX.md` enthält ab Zeile 178 **eingebettete Runbook-Entwürfe** (Unraid-Flash, AdGuard, Tailscale, Redis) — dasselbe Genre, das unter `ops/restore-tests/*-runbook.md` bereits ein Zuhause hat. AdGuard und Redis sind dort inzwischen sogar als Skript automatisiert und validiert; die Matrix-Abschnitte sind damit doppelt.
|
||||
- `docs/RESTORE_HANDBOOK.md` und `ops/restore-tests/README.md` beantworten zu ~80 % dieselben Fragen (Grundmuster, Verzeichnisse, Status je Dienst, Schnellstart) — zwei Pflegeorte für einen Prozess.
|
||||
- Die `*-plan.md`-Dateien (6 Stück) waren Vor-Erstlauf-Planung; nach erfolgreichem Erstlauf sind Runbook + Skript die Wahrheit, die Pläne sind Historie (z. B. `gitea-plan.md` "Noch offen vor dem ersten echten Lauf" — der Lauf war am 2026-05-07).
|
||||
- Restore-Kadenz steht dreifach: `RESTORE_HANDBOOK` §5, `ops/restore-tests/schedule.md`, `ops/restore-tests/unraid-user-scripts.md`.
|
||||
|
||||
### 3.4 P4 — Historische Snapshots leben als aktive Doku weiter
|
||||
|
||||
Trotz klarer Policy in `docs/README.md` ("Erledigte Audits, Chat-Handoffs ...
|
||||
bleiben in der Git-Historie, aber nicht als dauerhafte Arbeitskopie"):
|
||||
|
||||
- `docs/DR_DRILL_2026-06-03.md` (392 Zeilen): Findings sind laut `AUDIT_2026-05-25_TODO` vollständig in DR.md/EXTERNAL_DEPENDENCIES eingearbeitet — reines Belegmaterial.
|
||||
- `docs/audit/system-audit-2026-06-05.md` (229 Zeilen): Windows-Workstation-Audit, thematisch nicht einmal Homelab-Betrieb.
|
||||
- `docs/audit/dr-workstation-readiness-2026-06-06.md`: automatisch erzeugter Check-Output inkl. Rohblöcken.
|
||||
- `docs/WEEKEND_*_2026-06-05.md` (2 Dateien): abgeschlossener Sprint.
|
||||
- `docs/KalliLab_CORE_Audit_2026-06-06.pdf` (untracked): Binär-Report im `docs/`-Ordner.
|
||||
- `ops/borg-ui/BACKUP_AUDIT_STATUS_QUO.md` (Stand 2026-04-15): Vor-Migrations-Ist-Aufnahme, von `BACKUP_SCOPE.md` abgelöst.
|
||||
- `ops/policy-checks/last-report.md`: **generierter** Report, eingecheckt — bei jedem Lauf entsteht Diff-Rauschen.
|
||||
- `ops/windows-reinstall/docs/` (8 Dateien, ~1.400 Zeilen): Projekt Mai 2026 ist abgeschlossen; aktiv gebraucht wird davon im Betrieb nur `windows-image-backup-baseline.md` (Veeam-Restore-Runbook, von `RESTORE_MATRIX` referenziert) und ggf. `laufwerks-neustruktur-2026-06-04.md` als Soll-Referenz.
|
||||
|
||||
Es fehlt eine gelebte Archiv-Konvention — entweder konsequentes Löschen (Policy
|
||||
existiert) oder ein sichtbares `docs/archive/`.
|
||||
|
||||
### 3.5 P5 — Architektur-Master vermischt Zielbild und Entscheidungs-Log
|
||||
|
||||
`HOMELAB_ARCHITECTURE_MASTER_V2.md` (502 Zeilen) ist Pflichtlektüre Nr. 1, trägt
|
||||
aber in §13 ein unbegrenzt wachsendes Betriebs-/Entscheidungs-Log (FCP-Incident,
|
||||
Plex-Reclaim-Erzählung, Digest-Pinning-Historie ...). Entscheidungen liegen
|
||||
zusätzlich in `MASTER_TODO` (Geparkt-Tabelle mit Triggern),
|
||||
`HARDWARE_INVENTORY` (Betreiber-Entscheidungen), `AUDIT_2026-05-25_TODO`
|
||||
("Bewusst geparkt") und den Review-Logs der Inventare. Ein zentrales,
|
||||
chronologisches Entscheidungs-Register (ADR-light) fehlt —
|
||||
`docs/runbooks/komodo-bulk-deploy-dns.md` nennt sich bereits selbst
|
||||
"Runbook / ADR-light" und zeigt den Bedarf.
|
||||
|
||||
### 3.6 P6 — Einstiegs-Redundanz
|
||||
|
||||
`README.md`, `CLAUDE.md`, `docs/AI_CONTEXT.md`, `docs/README.md`,
|
||||
`docs/REPO_MAP.md`, `docs/WORKFLOW.md` (KI-Arbeitsregel) und
|
||||
`HOMELAB_ARCHITECTURE_MASTER_V2.md` (§11/§12) wiederholen alle dieselben
|
||||
Grundregeln (Quelle der Wahrheit, Leselisten, Ausnahmen) in leicht
|
||||
unterschiedlichen Fassungen. Bei Regeländerungen müssen bis zu 7 Dateien
|
||||
angefasst werden; die Leselisten weichen bereits leicht voneinander ab.
|
||||
|
||||
### 3.7 P7 — Flacher Namensraum mit gemischten Typen und Zielgruppen
|
||||
|
||||
In `docs/` liegen 31 Dateien flach nebeneinander: Familien-Doku
|
||||
(`FAMILY_ONBOARDING.md`) neben Bare-Metal-DR, Statuslisten neben Inventaren,
|
||||
Snapshots neben Dauer-Runbooks. Die begonnene Untergliederung
|
||||
(`docs/runbooks/` mit 1 Datei, `docs/audit/` mit 2) ist inkonsistent: ~10
|
||||
Runbook-artige Dokumente liegen weiter flach. Namensstile mischen sich
|
||||
(`SCREAMING_SNAKE.md` vs. `homelab-optimierung.md` vs. `komodo-bulk-deploy-dns.md`).
|
||||
|
||||
### 3.8 P8 — Punktuelle Doppel-Dokumente
|
||||
|
||||
- `docs/H_DRIVE_NEARLINE_PULL.md` (Pull-Workflow + Befund-Historie) vs. neues, untracked `ops/h-drive-nearline/README.md` (Struktur + Betrieb + Aufräum-Historie) vs. H:/-Abschnitt in `docs/CAPACITY_AND_LIFECYCLE.md` — drei Orte für ein Thema.
|
||||
- `ops/restore-tests/README.md` pflegt eine manuelle Datei-Auflistung des eigenen Verzeichnisses ("Geplante Struktur", ~35 Zeilen) — das Verzeichnis listet sich selbst.
|
||||
- `ops/hermes-agent/README.md` (367 Zeilen) ist überwiegend "Phase 1 Documentation Analysis" für einen Dienst, der bis mindestens 2026-07-25 deaktiviert geparkt ist.
|
||||
|
||||
---
|
||||
|
||||
## 4. Best-Practice-Abgleich (Kurzfassung)
|
||||
|
||||
| Prinzip | Heute | Lücke |
|
||||
|---|---|---|
|
||||
| Single Source of Truth pro Fakt | Git als SSoT für Konfig ✅; für Doku-Fakten ❌ (6–9 Kopien) | Regel "ein Fakt, ein Zuhause" fehlt |
|
||||
| Trennung Architektur / Runbook / Entscheidung / Status | teilweise; Mischformen wie `RESTORE_MATRIX` (Referenz + Runbooks + Status) und Master §13 | Dokumenttypen nicht explizit definiert |
|
||||
| README als Einstieg | ✅ vorhanden und gut | nur Redundanz mit 6 weiteren Einstiegen |
|
||||
| ADRs für Entscheidungen | verteilt auf 5 Orte | zentrales Register fehlt |
|
||||
| Runbooks für Wiederholbares | ✅ stark | doppelt gepflegt (Matrix-Einbettungen, Handbook vs. README) |
|
||||
| Kurze Dokumente statt Sammeldateien | gemischt; Master 502 Z., DR 400 Z., Matrix 261 Z. | Status-/Historien-Anteile aufblähen Kerndokumente |
|
||||
| Archivierung Veralteter Inhalte | Policy existiert (`docs/README.md`) | wird nicht durchgesetzt; kein `archive/` |
|
||||
| Namenskonventionen | de facto SCREAMING_SNAKE | nicht dokumentiert, neue Dateien weichen ab |
|
||||
| Ownership / Aktualisierungsrhythmus | Ein-Operator-Modell, Review-Trigger teils vorhanden | kein definierter Doku-Review-Rhythmus |
|
||||
|
||||
---
|
||||
|
||||
## 5. Konkrete Verschlankungsvorschläge
|
||||
|
||||
Bewertungslegende: Mehrwert (niedrig/mittel/hoch/sehr hoch) · Aufwand
|
||||
(klein/mittel/groß) · Risiko (niedrig/mittel/hoch) · Ü = Wirkung Übersichtlichkeit,
|
||||
W = Wirkung Wartbarkeit (–/+/++/+++).
|
||||
|
||||
### 5.1 Statuslisten auf genau eine reduzieren
|
||||
|
||||
| Maßnahme | Mehrwert | Aufwand | Risiko | Ü | W |
|
||||
|---|---|---|---|---|---|
|
||||
| `WEEKEND_EXECUTION_PLAN_2026-06-05.md` + `WEEKEND_STATUS_2026-06-05.md` löschen/archivieren (Inhalt vollständig in `MASTER_TODO` Done-Log) | hoch | klein | niedrig | ++ | + |
|
||||
| `AUDIT_2026-05-25_TODO.md` auflösen: den 1 offenen Punkt + "Bewusst geparkt" in `MASTER_TODO` übernehmen, Datei löschen | hoch | klein | niedrig | ++ | ++ |
|
||||
| `AI_CONTEXT.md` Status-Block (Z. 44–84) streichen; nur Pointer "Authoritativ: `docs/MASTER_TODO.md`" behalten → Datei schrumpft auf ~35 Zeilen reine Regeln/Pointer | hoch | klein | niedrig | + | +++ |
|
||||
| `MASTER_TODO` Done-Log auf die letzten ~5 Einträge begrenzen; ältere Einträge ersatzlos streichen (Git-Historie + Host-Reports sind der Beleg) | hoch | klein | niedrig | ++ | +++ |
|
||||
| To-do-Restabschnitte in Detail-Dokumenten entfernen: `SERVICES_RECOVERY` "Naechste Aufgaben" (alles erledigt), `RESTORE_HANDBOOK` §11 → als Einzeiler nach `MASTER_TODO` | mittel | klein | niedrig | + | ++ |
|
||||
|
||||
### 5.2 Restore-/DR-Cluster konsolidieren
|
||||
|
||||
| Maßnahme | Mehrwert | Aufwand | Risiko | Ü | W |
|
||||
|---|---|---|---|---|---|
|
||||
| `RESTORE_MATRIX.md` auf Referenz reduzieren: eingebettete Runbook-Entwürfe (Z. 178–343) nach `ops/restore-tests/` verschieben bzw. löschen, wo Skript + Runbook schon existieren (AdGuard, Redis); Matrix behält nur Tier-Tabellen + Reifegrad | hoch | mittel | niedrig | ++ | ++ |
|
||||
| `RESTORE_HANDBOOK.md` und `ops/restore-tests/README.md` zu **einem** Betriebsdokument zusammenführen (Empfehlung: `ops/restore-tests/README.md` als Zuhause, da Skripte dort liegen; `docs/README.md`-Index verlinkt) | hoch | mittel | niedrig | ++ | ++ |
|
||||
| Die 6 `*-plan.md` unter `ops/restore-tests/` archivieren/löschen — Runbook + Skript sind seit den Erstläufen die Wahrheit | mittel | klein | niedrig | + | + |
|
||||
| Restore-Status nur noch in der Reifegrad-Tabelle der `RESTORE_MATRIX` führen; `ops/restore-tests/README.md` "Status"-Abschnitt durch Link ersetzen | mittel | klein | niedrig | + | ++ |
|
||||
| Komodo-Kaltstart: `SERVICES_RECOVERY.md` bleibt kanonisch (Stufen A–F); `DISASTER_RECOVERY.md` Phase 4 Stufe 3 auf Verweis + 3 Kern-Stolperfallen kürzen | mittel | klein | niedrig | + | ++ |
|
||||
| `ROLLBACK.md`: abgeschlossene Service-Rollbacks (Uptime-Kuma, Grafana/InfluxDB-Altstack, BentoPDF/Stirling) streichen — Rollback-Pfade für entfernte Dienste gehören in die Git-Historie | mittel | klein | niedrig | + | + |
|
||||
|
||||
### 5.3 Entscheidungs-Register einführen (wichtigste strukturelle Maßnahme)
|
||||
|
||||
| Maßnahme | Mehrwert | Aufwand | Risiko | Ü | W |
|
||||
|---|---|---|---|---|---|
|
||||
| Neues `docs/DECISIONS.md` (ADR-light, eine Datei, neueste oben): Datum, Entscheidung, Kontext, Alternativen, Review-Trigger — je Eintrag 5–15 Zeilen | sehr hoch | mittel | niedrig | ++ | +++ |
|
||||
| `HOMELAB_ARCHITECTURE_MASTER_V2.md` §13 dorthin migrieren; §9 (historische Migration) auf 3 Zeilen kürzen → Master schrumpft von 502 auf ~300 Zeilen reines Zielbild | sehr hoch | mittel | mittel* | +++ | +++ |
|
||||
| Künftige Entscheidungen **nur noch** dort; `MASTER_TODO` "Geparkt" verlinkt auf DECISIONS-Einträge statt sie zu wiederholen | hoch | klein | niedrig | ++ | +++ |
|
||||
|
||||
*Risiko "mittel" nur, weil der Master Pflichtlektüre für alle Agenten ist —
|
||||
Migration als ein sauberer Commit mit Verweis im Master ("Entscheidungs-Log:
|
||||
siehe `docs/DECISIONS.md`") entschärft das vollständig.
|
||||
|
||||
### 5.4 Historisches archivieren
|
||||
|
||||
| Maßnahme | Mehrwert | Aufwand | Risiko | Ü | W |
|
||||
|---|---|---|---|---|---|
|
||||
| `docs/archive/` anlegen (oder konsequent löschen — Operator-Frage 1); dorthin: `DR_DRILL_2026-06-03.md`, `docs/audit/*` (beide), `HOME_ASSISTANT_INFLUXDB_ECOWITT.md` (selbst als archiviert markiert), Weekend-Dateien | hoch | klein | niedrig | +++ | ++ |
|
||||
| `ops/windows-reinstall/docs/`: nur `windows-image-backup-baseline.md` (aktives Veeam-DR-Runbook) und `laufwerks-neustruktur-2026-06-04.md` (Soll-Referenz) bleiben aktiv; die übrigen 6 Dateien archivieren | mittel | klein | niedrig | ++ | + |
|
||||
| `ops/borg-ui/BACKUP_AUDIT_STATUS_QUO.md` archivieren (`BACKUP_SCOPE.md` ist das aktive Zielbild) | mittel | klein | niedrig | + | + |
|
||||
| `ops/policy-checks/last-report.md` aus Git entfernen und in `.gitignore` aufnehmen (generiertes Artefakt) | mittel | klein | niedrig | + | ++ |
|
||||
| `docs/KalliLab_CORE_Audit_2026-06-06.pdf` nicht committen; Ablage auf Share/H: statt im GitOps-Repo | mittel | klein | niedrig | + | + |
|
||||
|
||||
### 5.5 Punktuelle Zusammenführungen
|
||||
|
||||
| Maßnahme | Mehrwert | Aufwand | Risiko | Ü | W |
|
||||
|---|---|---|---|---|---|
|
||||
| H:/-Thema: `ops/h-drive-nearline/README.md` (neu, derzeit untracked) committen und zur einzigen H:/-Doku machen; `docs/H_DRIVE_NEARLINE_PULL.md` auf Kurzverweis reduzieren oder auflösen; Befund-Historie 2026-05/06 → `DECISIONS.md` oder Git | mittel | klein | niedrig | + | ++ |
|
||||
| `ops/restore-tests/README.md`: manuelle Datei-Auflistung ("Geplante Struktur") auf die 5 Einstiegs-Skripte kürzen | niedrig–mittel | klein | niedrig | + | + |
|
||||
| `ops/hermes-agent/README.md` beim Hermes-Review (Deadline 2026-07-25) von 367 auf ~60 Zeilen Betriebs-README kürzen oder mit dem Stack entfernen | niedrig | klein | niedrig | + | + |
|
||||
| Leselisten vereinheitlichen: `README.md` und `CLAUDE.md` behalten je **eine** Leseliste; `WORKFLOW`/`Master §12`/`AI_CONTEXT` verweisen nur noch darauf | mittel | klein | niedrig | + | ++ |
|
||||
|
||||
---
|
||||
|
||||
## 6. Vorgeschlagene Zielstruktur
|
||||
|
||||
Bewusst **keine** Big-Bang-Umordnung: Massen-Verschiebungen brechen die
|
||||
Querverweise in ~30 Dokumenten, die Pflicht-Leselisten in `CLAUDE.md` und die
|
||||
Pfade im Host-Spiegel. Die Struktur bleibt erkennbar, wird aber dünner und
|
||||
bekommt drei neue Sammelpunkte:
|
||||
|
||||
```text
|
||||
/ (unverändert)
|
||||
├── README.md Einstieg, eine Leseliste
|
||||
├── CLAUDE.md KI-Arbeitsregeln (verweist statt wiederholt)
|
||||
├── HOMELAB_ARCHITECTURE_MASTER_V2.md nur noch Zielbild (~300 Z.)
|
||||
├── docs/
|
||||
│ ├── README.md Index (Pflicht, wie heute)
|
||||
│ ├── MASTER_TODO.md EINZIGE Statusliste
|
||||
│ ├── DECISIONS.md NEU: Entscheidungs-Register (ADR-light)
|
||||
│ ├── AI_CONTEXT.md verschlankt: Regeln + Pointer, kein Status
|
||||
│ ├── WORKFLOW.md / REPO_MAP.md unverändert
|
||||
│ ├── SERVICE_CATALOG.md Referenz (unverändert)
|
||||
│ ├── Inventare (6): HARDWARE_, NETWORK_, STORAGE_LAYOUT,
|
||||
│ │ EXTERNAL_DEPENDENCIES, CAPACITY_, SECRETS_MAP
|
||||
│ ├── Runbooks (flach, Bestand): DISASTER_RECOVERY, RESTORE_MATRIX (schlank),
|
||||
│ │ SERVICES_RECOVERY, ROLLBACK, GITOPS_DRIFT_RUNBOOK,
|
||||
│ │ GUEST_IOT_NETWORK, EXTERNAL_OPERATOR_RUNBOOK,
|
||||
│ │ DR_WORKSTATION_SETUP, AUTHELIA_OIDC_PLAN,
|
||||
│ │ FAMILY_ONBOARDING, RENOVATE, ALERT_RULES
|
||||
│ ├── runbooks/ NEUE themenspezifische Runbooks (kebab-case),
|
||||
│ │ Bestand bleibt wo er ist
|
||||
│ └── archive/ NEU: abgeschlossene Snapshots/Drills/Audits
|
||||
└── ops/<tool>/ Tool-Doku bleibt beim Tool (README + Runbook)
|
||||
```
|
||||
|
||||
Netto-Effekt: `docs/` aktiv 35 → ~22 Dateien; Gesamtbestand ~74 → ~50 aktive
|
||||
Dateien; geschätzt ~2.900 Zeilen weniger Pflegefläche.
|
||||
|
||||
---
|
||||
|
||||
## 7. Empfohlene Dokumenttypen
|
||||
|
||||
Jede Datei bekommt genau einen Typ (im Kopf deklariert):
|
||||
|
||||
| Typ | Zweck | Beispiele (Bestand) | Lebenszyklus |
|
||||
|---|---|---|---|
|
||||
| **Einstieg/Index** | Navigation, Regeln | `README.md`, `docs/README.md`, `CLAUDE.md` | dauerhaft, klein halten |
|
||||
| **Architektur/Zielbild** | Soll-Zustand, Prinzipien, Ausnahmen | `HOMELAB_ARCHITECTURE_MASTER_V2.md` | dauerhaft; Änderungen via DECISIONS begründet |
|
||||
| **Inventar/Referenz** | Ist-Werte, Kataloge, Matrizen | `SERVICE_CATALOG`, `NETWORK_INVENTORY`, `RESTORE_MATRIX` | dauerhaft; nur Ist-Stand, keine Verlaufserzählung |
|
||||
| **Runbook** | wiederholbare Abläufe mit Erfolgskriterium + Rollback | `GITOPS_DRIFT_RUNBOOK`, `DR_WORKSTATION_SETUP`, `ops/restore-tests/*-runbook.md` | dauerhaft; bei Ablösung archivieren |
|
||||
| **Entscheidung (ADR-light)** | Was, warum, Alternativen, Review-Trigger | NEU: `docs/DECISIONS.md` | append-only, neueste oben |
|
||||
| **Status/To-do** | offene Arbeit | `MASTER_TODO.md` (einzige Instanz) | lebend; Done-Einträge max. ~5 |
|
||||
| **Snapshot/Beleg** | Audits, Drills, Sprint-Boards, Messungen | `DR_DRILL_*`, `audit/*`, `WEEKEND_*`, `mem-limits-baseline` | **befristet**: nach Einarbeitung → `archive/` oder löschen |
|
||||
|
||||
---
|
||||
|
||||
## 8. Merge-/Archivierungs-Kandidaten (Gesamtliste, priorisiert)
|
||||
|
||||
| # | Kandidat | Aktion | Prio |
|
||||
|---|---|---|---|
|
||||
| 1 | `docs/WEEKEND_EXECUTION_PLAN_2026-06-05.md`, `docs/WEEKEND_STATUS_2026-06-05.md` | löschen/archivieren | sofort |
|
||||
| 2 | `docs/AUDIT_2026-05-25_TODO.md` | Rest in `MASTER_TODO` mergen, löschen | sofort |
|
||||
| 3 | `docs/AI_CONTEXT.md` Z. 44–84 | streichen (Pointer auf MASTER_TODO) | sofort |
|
||||
| 4 | `ops/policy-checks/last-report.md` | entgitten + `.gitignore` | sofort |
|
||||
| 5 | `docs/KalliLab_CORE_Audit_2026-06-06.pdf` (untracked) | nicht committen, extern ablegen | sofort |
|
||||
| 6 | `docs/DR_DRILL_2026-06-03.md`, `docs/audit/*` (2), `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md` | → `docs/archive/` | Woche 1 |
|
||||
| 7 | `ops/h-drive-nearline/README.md` + `docs/H_DRIVE_NEARLINE_PULL.md` | committen + zu einem Dokument | Woche 1 |
|
||||
| 8 | `HOMELAB_ARCHITECTURE_MASTER_V2.md` §13 (+§9 kürzen) | → neues `docs/DECISIONS.md` | Woche 2 |
|
||||
| 9 | `docs/ROLLBACK.md` historische Service-Abschnitte | streichen | Woche 2 |
|
||||
| 10 | `docs/RESTORE_HANDBOOK.md` + `ops/restore-tests/README.md` | zu einem Dokument | Woche 3 |
|
||||
| 11 | `docs/RESTORE_MATRIX.md` eingebettete Runbooks (Z. 178–343) | ausgliedern/löschen | Woche 3 |
|
||||
| 12 | `ops/restore-tests/*-plan.md` (6) | archivieren/löschen | Woche 3 |
|
||||
| 13 | `docs/SERVICES_RECOVERY.md` Done-Tabelle; `RESTORE_HANDBOOK` §11-Backlog | streichen / nach MASTER_TODO | Woche 3 |
|
||||
| 14 | `ops/windows-reinstall/docs/` (6 von 8 Dateien) | archivieren | Woche 4 |
|
||||
| 15 | `ops/borg-ui/BACKUP_AUDIT_STATUS_QUO.md` | archivieren | Woche 4 |
|
||||
| 16 | `MASTER_TODO` Done-Log, `EXTERNAL_DEPENDENCIES` Review-Log | auf jüngste Einträge kürzen | Woche 4 |
|
||||
| 17 | `ops/hermes-agent/README.md` | beim Hermes-Review 2026-07-25 kürzen/entfernen | später |
|
||||
|
||||
---
|
||||
|
||||
## 9. Empfohlene Namenskonventionen
|
||||
|
||||
1. **Bestand nicht umbenennen.** `SCREAMING_SNAKE.md` bleibt für die etablierte Kern-Doku in `docs/` — Renames erzeugen nur Link-Brüche ohne Informationsgewinn.
|
||||
2. **Neue Dateien in Unterordnern in `kebab-case.md`** (so wie `docs/runbooks/komodo-bulk-deploy-dns.md` es bereits vormacht).
|
||||
3. **Datum im Dateinamen nur für Snapshots** (`YYYY-MM-DD`), und Snapshots gehören nach `docs/archive/YYYY/`. Eine datierte Datei im `docs/`-Root ist künftig per Definition ein Aufräum-Kandidat.
|
||||
4. **Kopfzeilen-Konvention** (3 Felder, eine Zeile, wie in diesem Dokument): `Typ: … · Stand: YYYY-MM-DD · Status: aktiv | geparkt (Trigger: …) | archiviert`. Viele Dokumente haben "Stand:" bereits — nur Typ/Status ergänzen.
|
||||
5. **Archiv-Pfad:** `docs/archive/YYYY/<datum>-<thema>.md`, oben ein Einzeiler "Archiviert am …, abgelöst durch …".
|
||||
|
||||
---
|
||||
|
||||
## 10. Minimale Doku-Regeln für die Zukunft
|
||||
|
||||
Vorschlag als Ersatz/Ergänzung der bestehenden Arbeitsregel in `docs/REPO_MAP.md`
|
||||
(und Kurzfassung in `CLAUDE.md`):
|
||||
|
||||
1. **Ein Fakt, ein Zuhause.** Status → `MASTER_TODO`. Entscheidung → `DECISIONS`. Zielbild → Architektur/Inventar/Katalog. Ablauf → genau ein Runbook. Beleg → Host-Report (`/mnt/user/backups/restore-reports/`) oder Git-Commit. Alle anderen Stellen **verlinken**.
|
||||
2. **Erledigt = raus aus der Arbeitskopie.** Abgeschlossene Pläne, Sprints, Audits und Drill-Reports wandern nach `docs/archive/` oder werden gelöscht — Git ist das Archiv (bestehende Policy aus `docs/README.md`, jetzt durchgesetzt).
|
||||
3. **Neue Datei nur, wenn sie einem der 7 Typen aus Abschnitt 7 entspricht** — sonst ist es ein Eintrag in einer bestehenden Datei.
|
||||
4. **Done-Einträge maximal 3 Zeilen.** Wer mehr Beleg braucht, verlinkt Commit oder Report. Done-Logs werden bei >5 Einträgen gekürzt.
|
||||
5. **Snapshot-Dateien tragen ihr Ablaufdatum** ("Status: befristet bis …") und werden danach archiviert.
|
||||
6. **Index-Pflicht bleibt:** jede neue/gelöschte Datei aktualisiert `docs/README.md` im selben Commit.
|
||||
7. **Quartals-Gärtnern (15 min):** datierte Dateien im `docs/`-Root archivieren, Done-Logs kürzen, tote Links prüfen — passt zum bestehenden Quartals-Rhythmus (DR-Smoke, Restore-Drills).
|
||||
|
||||
---
|
||||
|
||||
## 11. 30-Tage-Plan
|
||||
|
||||
**Woche 1 — Quick Wins + Archiv-Fundament** (alles klein, risikolos):
|
||||
Uncommitted Arbeitskopie klären (6 modifizierte Dateien, 2 untracked — deckt
|
||||
sich mit `docs/homelab-optimierung.md` Empfehlung 9) · Kandidaten #1–#7 aus
|
||||
Abschnitt 8 · `docs/archive/` anlegen.
|
||||
|
||||
**Woche 2 — Entscheidungs-Register:**
|
||||
`docs/DECISIONS.md` anlegen (Vorlage: 5 Felder) · Master §13 migrieren, §9
|
||||
kürzen, Verweis im Master setzen · `ROLLBACK.md` entschlacken · verstreute
|
||||
"Bewusst geparkt"-Entscheidungen als DECISIONS-Einträge mit Review-Trigger
|
||||
zusammenziehen.
|
||||
|
||||
**Woche 3 — Restore-Cluster:**
|
||||
`RESTORE_HANDBOOK` ↔ `ops/restore-tests/README.md` zusammenführen ·
|
||||
`RESTORE_MATRIX` auf Tabellen reduzieren, Runbook-Entwürfe ausgliedern ·
|
||||
`*-plan.md` archivieren · Restore-Status auf einen Ort (Reifegrad-Tabelle).
|
||||
|
||||
**Woche 4 — Regeln verankern + Abschluss:**
|
||||
Regeln aus Abschnitt 10 in `REPO_MAP.md`/`CLAUDE.md` einarbeiten · Leselisten
|
||||
vereinheitlichen · `windows-reinstall`-Doku abschließen/archivieren ·
|
||||
Done-/Review-Logs kürzen · `docs/README.md`-Index final neu aufbauen ·
|
||||
dieses Dokument selbst nach `docs/archive/` verschieben (Regel 2 gilt auch hier).
|
||||
|
||||
Jeder Schritt ist ein eigener kleiner Commit → Rollback ist immer ein
|
||||
`git revert`; keine produktiven Pfade, keine Compose-Dateien betroffen.
|
||||
|
||||
---
|
||||
|
||||
## 12. Quick Wins unter 30 Minuten
|
||||
|
||||
| Quick Win | Wirkung |
|
||||
|---|---|
|
||||
| Weekend-Dateien (2) löschen | −161 Zeilen, eine Statusliste weniger |
|
||||
| `AUDIT_2026-05-25_TODO.md` in `MASTER_TODO` auflösen | −57 Zeilen, Sync-Pflicht entfällt dauerhaft |
|
||||
| `AI_CONTEXT` Status-Block streichen | KI-Kontext wird wartungsfrei |
|
||||
| `last-report.md` entgitten + `.gitignore` | kein Diff-Rauschen pro Policy-Lauf |
|
||||
| `docs/archive/` anlegen + 5 Snapshots verschieben | `docs/`-Root zeigt nur noch Aktives |
|
||||
| `ops/h-drive-nearline/README.md` committen, `H_DRIVE_NEARLINE_PULL` zum Pointer machen | H:/-Thema hat ein Zuhause |
|
||||
| PDF aus `docs/` entfernen (extern ablegen) | keine Binärdateien im GitOps-Repo |
|
||||
| `MASTER_TODO` Done-Log auf 5 Einträge kürzen | −60 Zeilen in der führenden Liste |
|
||||
|
||||
---
|
||||
|
||||
## 13. Größere Aufräumprojekte (später, bewusst optional)
|
||||
|
||||
1. **Ordner-Restruktur `docs/{runbooks,inventory}/`** für den Bestand: nur angehen, wenn der flache Namensraum nach der Konsolidierung noch stört. Aufwand groß (Link-Churn in ~30 Dateien, `CLAUDE.md`-Leselisten, Host-Spiegel), Mehrwert nach der Verschlankung nur noch mittel, Risiko mittel.
|
||||
2. **Doku-Linter im Policy-Check:** `ops/policy-checks/check_repo.ps1` um DOC-Checks erweitern — tote relative Links, datierte Dateien im `docs/`-Root, fehlende Typ/Stand-Kopfzeile. Passt zur bestehenden Check-Kultur; Aufwand mittel, Mehrwert hoch für die Dauerhaftigkeit der Regeln.
|
||||
3. **Index-Generierung:** `docs/README.md`-Tabellen aus den Kopfzeilen generieren statt manuell pflegen. Nice-to-have für ein Ein-Personen-Lab; erst nach 2.
|
||||
4. **Workstation-Doku entflechten:** prüfen, ob `baerchen`-Lifecycle-Doku (windows-reinstall, System-Audits) langfristig in ein eigenes Repo gehört; im Homelab-Repo bleibt nur das DR-relevante Veeam-Runbook. Mehrwert mittel, Aufwand mittel.
|
||||
5. **Master-Diät Stufe 2:** Spalten-Überlappung zwischen Master §7-Tabellen und `SERVICE_CATALOG` reduzieren (Status/Netze doppelt). Vorsichtig angehen — beide sind Pflichtlektüre; erst nachdem DECISIONS etabliert ist.
|
||||
|
||||
---
|
||||
|
||||
## 14. Offene Fragen an den Operator
|
||||
|
||||
1. **Archivieren oder löschen?** `docs/archive/` macht Historie sichtbar, widerspricht aber der bestehenden "Git-Historie reicht"-Policy. Präferenz? (Empfehlung: `archive/` für Drill-/Audit-Belege mit Referenzwert, Löschen für Sprint-Boards und erledigte Pläne.)
|
||||
2. **Wer konsumiert `docs/AI_CONTEXT.md`** außer Claude (Codex? Hermes? Gemini-Sessions)? Wenn nur Claude: mit `CLAUDE.md` zusammenlegen und eine Datei einsparen. Wenn mehrere: schlank behalten wie vorgeschlagen.
|
||||
3. **`docs/audit/` als dauerhafte Konvention?** Sollen künftige Audit-Snapshots überhaupt ins Repo, oder reichen Host-Reports unter `/mnt/user/backups/restore-reports/` plus ein DECISIONS-/TODO-Eintrag?
|
||||
4. **Folder-Restruktur (Projekt 13.1) gewünscht oder bewusst nie?** Eine klare Nein-Entscheidung wäre auch ein legitimer DECISIONS-Eintrag und beendet das Thema.
|
||||
5. **Die 6 uncommitteten Doku-Änderungen** in der Arbeitskopie (u. a. `AI_CONTEXT`, `AUDIT_2026-05-25_TODO`, `WEEKEND_STATUS`, windows-reinstall-Dateien): committen oder verwerfen? Das sollte vor Umsetzung der Wochen-1-Schritte geklärt sein, damit Merges sauber bleiben.
|
||||
6. **Soll `docs/WORKFLOW.md` "Dokumentationspflicht"** (7 Dateien pro Änderung prüfen) nach Einführung von Regel 1 ("ein Fakt, ein Zuhause") entsprechend verkürzt werden? Empfehlung: ja — die Prüfliste schrumpft auf "betroffenes Zuhause + Index".
|
||||
@@ -1,148 +0,0 @@
|
||||
# PostDelta 2026-06-04
|
||||
|
||||
Diese Datei dokumentiert das Delta, das nach dem urspruenglichen Windows-Neuaufsetzen-Plan und nach `_Delta_2026-05-19` entstanden ist.
|
||||
|
||||
Sie ist die Git-Repo-Kopie von:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\HANDOFF_2026-06-04.md
|
||||
```
|
||||
|
||||
## Kontext
|
||||
|
||||
- Der Benutzer war am 2026-06-04 noch im alten Windows gebootet.
|
||||
- Aus Sicht des alten Windows war:
|
||||
- altes Windows = `C:\WINDOWS`
|
||||
- neues Windows vermutlich = `D:\Windows`
|
||||
- Nach Boot ins neue Windows koennen sich Laufwerksbuchstaben aendern.
|
||||
- Vor jedem Restore oder Cleanup zuerst `Get-Volume`, `Get-Disk`, `Get-Partition`, `$env:SystemDrive` und `$env:windir` pruefen.
|
||||
|
||||
## Relevante Backup-Schichten
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup
|
||||
H:\Windows-Neuaufsetzen-Backup\_Delta_2026-05-19
|
||||
H:\Windows-Neuaufsetzen-Backup\_PostDelta_2026-06-04_100146
|
||||
```
|
||||
|
||||
Das PostDelta ist fuer aktuelle Daten zwingend mitzuberuecksichtigen.
|
||||
|
||||
## PostDelta-Inhalte
|
||||
|
||||
PostDelta-Ziel:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\_PostDelta_2026-06-04_100146
|
||||
```
|
||||
|
||||
Wichtige Unterordner:
|
||||
|
||||
- `00_Kritisch_Direkt`
|
||||
- `01_Desktop`
|
||||
- `02_Dokumente`
|
||||
- `03_Bilder`
|
||||
- `05_Downloads`
|
||||
- `09_Programme_Settings_Lizenzen`
|
||||
- `16_Overwatch2_Config`
|
||||
- `17_Maus_Settings`
|
||||
- `18_D_Users_michi_AdminCheck`
|
||||
|
||||
## Banking4
|
||||
|
||||
Aktuellster bekannter Tresor:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\_PostDelta_2026-06-04_100146\00_Kritisch_Direkt\Mein Datentresor.sub
|
||||
H:\Windows-Neuaufsetzen-Backup\_PostDelta_2026-06-04_100146\00_Kritisch_Direkt\.Mein Datentresor.sub.att
|
||||
```
|
||||
|
||||
Hash-verifiziert:
|
||||
|
||||
```text
|
||||
Mein Datentresor.sub
|
||||
SHA256 F22224B7A765046D4B76D71C1E296DA59D8D8A849A41A12E5C10254DF0EC71AD
|
||||
|
||||
.Mein Datentresor.sub.att
|
||||
SHA256 3FC5D0BD8B673975F9C42F4ED53278CFF434ED21E266B8B60589288A2FF9F4D8
|
||||
```
|
||||
|
||||
Der aeltere Banking4-Tresor aus Hauptbackup/Delta ist nicht mehr der neueste Stand.
|
||||
|
||||
Lizenz:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\09_Programme_Settings_Lizenzen\keys_exporte\banking4_license_private.txt
|
||||
```
|
||||
|
||||
## WISO Steuer
|
||||
|
||||
Hauptbackup:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\07_Banking_Finanzen\WISO_Steuer_Dokumente
|
||||
```
|
||||
|
||||
PostDelta:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\_PostDelta_2026-06-04_100146\02_Dokumente\steuer
|
||||
```
|
||||
|
||||
PostDelta enthaelt 8 Steuerdateien inklusive einer Pia-Marie-Datei.
|
||||
|
||||
## Overwatch 2
|
||||
|
||||
PostDelta:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\_PostDelta_2026-06-04_100146\16_Overwatch2_Config
|
||||
```
|
||||
|
||||
Wichtig:
|
||||
|
||||
```text
|
||||
16_Overwatch2_Config\Documents_Overwatch\Settings\Settings_v0.ini
|
||||
```
|
||||
|
||||
Beim Backup war nur `Overwatch.log` gesperrt; das ist eine Logdatei.
|
||||
|
||||
## Maus / iCUE
|
||||
|
||||
PostDelta:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\_PostDelta_2026-06-04_100146\17_Maus_Settings
|
||||
```
|
||||
|
||||
Enthaelt Corsair/iCUE-bezogene AppData/ProgramData, Registry-Exports und Windows-Mauswerte.
|
||||
|
||||
## D:\Users\michi Admincheck
|
||||
|
||||
Bericht:
|
||||
|
||||
```text
|
||||
H:\Windows-Neuaufsetzen-Backup\_PostDelta_2026-06-04_100146\18_D_Users_michi_AdminCheck
|
||||
```
|
||||
|
||||
Ergebnis:
|
||||
|
||||
- 6565 Dateien
|
||||
- 2950 Ordner
|
||||
- ca. 1.58 GB
|
||||
- 0 rekursive Zugriffsfehler
|
||||
- Standardordner praktisch leer
|
||||
- fast alles AppData/Windows-Package-Kram
|
||||
|
||||
Interpretation: aus alter Windows-Sicht keine wichtigen persoenlichen Daten in `D:\Users\michi`.
|
||||
|
||||
## Reihenfolge im neuen Windows
|
||||
|
||||
1. Laufwerksbuchstaben und gebootetes Windows pruefen.
|
||||
2. Alle drei Backup-Schichten pruefen.
|
||||
3. Banking4 mit PostDelta-Tresor wiederherstellen.
|
||||
4. WISO mit Hauptbackup plus PostDelta pruefen.
|
||||
5. Dokumente/Desktop/Bilder/Downloads migrieren.
|
||||
6. Overwatch 2 und iCUE/Corsair gezielt wiederherstellen.
|
||||
7. SSH/Git/Homelab wiederherstellen.
|
||||
8. Erst danach Windows-Idealkonfiguration, Bootcleanup und Formatierungen.
|
||||
|
||||
@@ -1,255 +0,0 @@
|
||||
# Programme-Entscheidungs-Checkliste fuer den Windows-Wiederaufbau
|
||||
|
||||
Stand: 2026-06-04
|
||||
Quelle: `H:\Windows-Neuaufsetzen-Backup\12_Exportierte_Listen\installierte_programme.csv` (161 Eintraege, Registry-Export vom 2026-05-07)
|
||||
Winget-Abdeckung: `H:\Windows-Neuaufsetzen-Backup\12_Exportierte_Listen\winget-export.json`
|
||||
Uebergeordneter Kontext: [HANDOFF_2026-06-04.md](../../../../H:/Windows-Neuaufsetzen-Backup/HANDOFF_2026-06-04.md) sowie [postdelta-2026-06-04.md](postdelta-2026-06-04.md)
|
||||
|
||||
## Wofuer ist diese Datei
|
||||
|
||||
Vorgefilterte Sortierung aller 161 installierten Programme in drei Toepfe, damit der Wiederaufbau im neuen Windows nicht 161 Einzelentscheidungen braucht.
|
||||
|
||||
**So nutzt sie der neue Codex/Claude:**
|
||||
|
||||
1. **Auto-Ja** (18 Eintraege): alle winget-IDs werden in einem Skript-Lauf installiert, ein User-OK reicht.
|
||||
2. **Einzelfrage** (38 Eintraege): jeden Eintrag mit Micha durchgehen, pro Eintrag `j` / `n` / `spaeter`. Hier sitzen die Lizenzen, Logins und Config-Restores.
|
||||
3. **Auto-Skip** (105 Eintraege): nur Sichtkontrolle, default ueberspringen. Sind Treiber-Bundles, Runtimes, Duplikate, Bloatware.
|
||||
|
||||
Summe: 161 == 161, keine Duplikate doppelt klassifiziert (Registry-Hive-Duplikate landen automatisch in Auto-Skip).
|
||||
|
||||
---
|
||||
|
||||
## 1. Auto-Ja (18)
|
||||
|
||||
Standard-Tools ohne Login/Lizenz, alle ueber `winget` installierbar. Im neuen Windows als Sammel-Befehl ausfuehrbar:
|
||||
|
||||
```powershell
|
||||
winget install --exact --id Brave.Brave --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id CPUID.CPU-Z.MSI --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id CPUID.HWMonitor --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id CrystalDewWorld.CrystalDiskInfo --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id Futuremark.3DMark --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id Git.Git --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id GoLang.Go --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id Governikus.AusweisApp --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id Guru3D.RTSS --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id HulubuluSoftware.AdvancedRenamer --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id LimeTechnology.UnraidUSBCreator --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id MaxCut.MaxCut --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id OpenJS.NodeJS.LTS --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id Python.Launcher --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id Python.Python.3.13 --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id buchen.portfolio --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id den4b.ReNamer --source winget --accept-package-agreements --accept-source-agreements
|
||||
winget install --exact --id fjsoft.MyPhoneExplorer --source winget --accept-package-agreements --accept-source-agreements
|
||||
```
|
||||
|
||||
| DisplayName | Version | Publisher | winget-ID | Begruendung |
|
||||
|---|---|---|---|---|
|
||||
| 3DMark | 2.22.7359.0 | UL | Futuremark.3DMark | Benchmark, kein Login |
|
||||
| Advanced Renamer | 3.95 | Hulubulu Software | HulubuluSoftware.AdvancedRenamer | Free Rename-Tool |
|
||||
| AusweisApp | 2.4.0 | Governikus GmbH & Co. KG | Governikus.AusweisApp | Online-Ausweis, kein Login |
|
||||
| Brave | 147.1.89.145 | Die Brave-Autoren | Brave.Brave | Browser (Sync optional spaeter) |
|
||||
| CPUID CPU-Z MSI 2.03 | 2.03 | CPUID, Inc. | CPUID.CPU-Z.MSI | System-Info-Tool |
|
||||
| CPUID HWMonitor 1.60 | 1.60 | CPUID, Inc. | CPUID.HWMonitor | Hardware-Monitor |
|
||||
| CrystalDiskInfo 9.8.0 | 9.8.0 | Crystal Dew World | CrystalDewWorld.CrystalDiskInfo | SSD/HDD-Health-Check |
|
||||
| Git | 2.53.0.2 | The Git Development Community | Git.Git | Dev-Tool (SSH-Key wird separat aus Backup zurueckgeholt) |
|
||||
| Go Programming Language amd64 go1.26.1 | 1.26.1 | https://go.dev | GoLang.Go | Dev-Tool |
|
||||
| MaxCut | 2.9.3.9 | MaxCut Software Ltd | MaxCut.MaxCut | Plattenoptimierungs-Tool, free |
|
||||
| MyPhoneExplorer | 2.3 | F.J. Wechselberger | fjsoft.MyPhoneExplorer | Android-Sync-Tool |
|
||||
| Node.js | 24.15.0 | Node.js Foundation | OpenJS.NodeJS.LTS | Dev-Tool |
|
||||
| Portfolio Performance | 0.76.3 | Andreas Buchen | buchen.portfolio | Open Source, Daten aus Backup |
|
||||
| Python 3.13.3 Core Interpreter (64-bit) | 3.13.3150.0 | Python Software Foundation | Python.Python.3.13 | Python 3.13 — Python.Python.3.13 deckt das gesamte Bundle ab |
|
||||
| Python Launcher | 3.13.3150.0 | Python Software Foundation | Python.Launcher | Dev-Tool |
|
||||
| ReNamer | 7.7.0.0 | den4b Team | den4b.ReNamer | Free Rename-Tool |
|
||||
| RivaTuner Statistics Server 7.3.7 | 7.3.7 | Unwinder | Guru3D.RTSS | OSD fuer Spiele (kommt mit MSI Afterburner) |
|
||||
| Unraid USB Creator | 1.1.0 | Lime Technology, Inc | LimeTechnology.UnraidUSBCreator | Homelab-Tool |
|
||||
|
||||
---
|
||||
|
||||
## 2. Einzelfrage (38)
|
||||
|
||||
Brauchen Lizenz, Login, Konfig-Restore oder explizite Ja/Nein-Entscheidung. **Pro Eintrag mit Micha klaeren.** Die "KRITISCH"-Eintraege haben Vorrang.
|
||||
|
||||
Reihenfolge-Empfehlung (aus `HANDOFF_2026-06-04.md`):
|
||||
|
||||
1. NVIDIA App (zuerst — bringt alle NVIDIA-Komponenten im Bundle)
|
||||
2. Microsoft 365 (M-Konto)
|
||||
3. Banking4 + Tresor aus PostDelta
|
||||
4. WISO Steuer 2026 + Steuerdateien aus PostDelta
|
||||
5. WSL + Distros (Ubuntu.tar / docker-desktop.tar)
|
||||
6. Tailscale (Login)
|
||||
7. Browser (Google Chrome / Brave mit Sync)
|
||||
8. Corsair iCUE (Mausprofile aus PostDelta)
|
||||
9. Battle.net + Overwatch 2 Config aus PostDelta
|
||||
10. Rest in beliebiger Reihenfolge
|
||||
|
||||
| DisplayName | Version | Publisher | winget-ID | Begruendung |
|
||||
|---|---|---|---|---|
|
||||
| Adobe Acrobat (64-bit) | 26.001.21529 | Adobe | Adobe.Acrobat.Pro | Adobe-Lizenz/Subscription pruefen |
|
||||
| Adobe Refresh Manager | 1.8.0 | Adobe Systems Incorporated | | Adobe-Komponente, nur falls Acrobat installiert |
|
||||
| AIDA64 Extreme v6.85 | 6.85 | FinalWire Ltd. | FinalWire.AIDA64.Extreme | Kostenpflichtige Lizenz |
|
||||
| Android Studio | 2024.3 | Google LLC | Google.AndroidStudio | Sehr gross — nur falls Android-Dev gebraucht |
|
||||
| Ant Movie Catalog | 4.2.2.2 | Ant Software | | Spezial-Tool, kein winget |
|
||||
| Banking4 Home | | Subsembly GmbH | | KRITISCH: Lizenz aus 09_Programme_Settings_Lizenzen\keys_exporte\banking4_license_private.txt + Tresor aus _PostDelta_2026-06-04_100146\00_Kritisch_Direkt |
|
||||
| Battle.net | | Blizzard Entertainment | | Launcher fuer Blizzard-Spiele (Overwatch 2 + WoW + Hearthstone). Overwatch-Config aus _PostDelta\16_Overwatch2_Config |
|
||||
| Corsair iCUE5 Software | 5.44.55 | Corsair | Corsair.iCUE.5 | Mausprofile aus _PostDelta_2026-06-04_100146\17_Maus_Settings |
|
||||
| Docker Desktop | 4.67.0 | Docker Inc. | Docker.DockerDesktop | WSL2-basiert, viele Configs. Bewusste Entscheidung ob noetig |
|
||||
| EMDB Version 3.72 | 3.72 | Wicked & Wild Inc | | Spezial-Tool, kein winget |
|
||||
| Epic Games Launcher | 1.3.155.0 | Epic Games, Inc. | EpicGames.EpicGamesLauncher | Login + Spiele-Bibliothek |
|
||||
| FileBot | 5.1.5 | Point Planck Limited | PointPlanck.FileBot | Kostenpflichtige Lizenz |
|
||||
| Google Chrome | 147.0.7727.138 | Google LLC | Google.Chrome.EXE | Sync-Login (Lesezeichen/Passwords/Profile aus Backup) |
|
||||
| HP Scan - Grundlegende Software für das Gerät | 63.6.6364.25288 | HP Inc. | | HP-Drucker-Software (LAN/Netzwerk-Setup) — nur installieren wenn HP-Drucker noch da |
|
||||
| Microsoft 365 - de-de | 16.0.19929.20136 | Microsoft Corporation | Microsoft.Office | KRITISCH: ueber Microsoft-Konto / Office.com installieren |
|
||||
| Microsoft OneDrive | 26.063.0405.0002 | Microsoft Corporation | Microsoft.OneDrive | Microsoft-Konto-Login; vorher Sync-Konflikte mit altem OneDrive bedenken |
|
||||
| Movienizer 10.3 | | Movienizer.com | | Kostenpflichtig, kein winget |
|
||||
| MSI Afterburner 4.6.6 | 4.6.6 | MSI Co., LTD | Guru3D.Afterburner | Nur falls GPU-OC/Monitoring noch gebraucht wird |
|
||||
| NVIDIA App 11.0.7.237 | 11.0.7.237 | NVIDIA Corporation | Nvidia.GeForceExperience | KRITISCH ZUERST: NVIDIA-App-Bundle installiert ALLE NVIDIA-Komponenten in einem Rutsch (Treiber + Container) |
|
||||
| Octoparse 8.7.2 | 8.7.2 | Octopus Data Inc. | OctopusData.Octoparse | Web-Scraper, Account-bezogen, optional |
|
||||
| PingPlotter 5 | 5.18.0.7997 | Pingman Tools, LLC | Pingman.PingPlotter | Kostenpflichtige Lizenz, optional |
|
||||
| Plex Media Server | 1.40.3555 | Plex, Inc. | Plex.PlexMediaServer | Server-Komponente + Plex-Konto. Hinweis: am Homelab laeuft separater Plex; Desktop-Installation nur falls bewusst gewollt |
|
||||
| Razer Chroma | 4.0.662 | Razer Inc. | | Razer-Komponente — kommt mit Synapse |
|
||||
| Razer Synapse | 4.0.662 | Razer Inc. | | Hardware-Konfig (Mauspad/Beleuchtung) |
|
||||
| Rename Expert 5.31.6 | 5.31.6 | Gillmeister Software | | Kostenpflichtig, manuelle Installation |
|
||||
| Tailscale | 1.96.3 | Tailscale Inc. | Tailscale.Tailscale | Login + Tailscale-Konto (gleicher Account wie Homelab) |
|
||||
| Tesseract-OCR - open source OCR engine | 5.5.0.20241111 | Tesseract-OCR community | UB-Mannheim.TesseractOCR | OCR-Engine, open source — entscheiden ob noch genutzt |
|
||||
| WD Discovery | 4.4.407 | Western Digital Technologies, Inc. | | NAS-Discovery-Tool, nur falls WD NAS noch in Nutzung |
|
||||
| WD Drive Utilities | 2.1.0.142 | Western Digital Technologies, Inc. | | WD-HDD-Tool, nur falls WD-Platte noch in Nutzung |
|
||||
| WD My Cloud | 1.0.2.34 | Western Digital Technologies, Inc. | | WD My Cloud Login, nur falls Geraet noch in Nutzung |
|
||||
| Windows Subsystem for Linux | 2.6.3.0 | Microsoft Corporation | Microsoft.WSL | KRITISCH: WSL aktivieren, dann Distros per `wsl --import` aus 09_Programme_Settings_Lizenzen\Ubuntu.tar + docker-desktop.tar |
|
||||
| WinRAR 7.11 (64-Bit) | 7.11.0 | win.rar GmbH | RARLab.WinRAR | Lizenz (technisch Shareware) |
|
||||
| WISO Steuer 2023 | 30.10.3890 | Buhl Data Service GmbH | | Alte Version — nur falls noch reaktiviert werden soll. Steuerdateien aus 07_Banking_Finanzen\WISO_Steuer_Dokumente |
|
||||
| WISO Steuer 2024 | 31.02.3430 | Buhl Data Service GmbH | | Alte Version — nur falls noch reaktiviert werden soll |
|
||||
| WISO Steuer 2025 | 32.03.2120 | Buhl Data Service GmbH | | Alte Version — nur falls noch reaktiviert werden soll |
|
||||
| WISO Steuer 2026 | 33.05.3220 | Buhl Data Service GmbH | | KRITISCH aktuellste Version: Buhl-Konto + Steuerdateien aus _PostDelta\02_Dokumente\steuer (8 Dateien) |
|
||||
| Wondershare Recoverit(Build 14.0.13.3) | 14.0.13.3 | Wondershare Software Co.,Ltd. | | Kostenpflichtig, Datenrettungs-Tool |
|
||||
| WoodWorks 1.8.7 | 1.8.7 | Robert Denk | | Spezial-Tool, manuelle Installation |
|
||||
|
||||
---
|
||||
|
||||
## 3. Auto-Skip (105)
|
||||
|
||||
Treiber-Bundles, Runtimes, Dependencies, Duplikate, Bloatware, Spiele (kommen ueber Launcher). **Nur Sichtkontrolle, default ueberspringen.** Wenn Micha ein Item hier wider Erwarten doch will, in Einzelfrage verschieben.
|
||||
|
||||
| DisplayName | Version | Publisher | winget-ID | Begruendung |
|
||||
|---|---|---|---|---|
|
||||
| 3DMark | 2.22.7359.0 | UL | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| Apex Legends | | Respawn Entertainment | | Game — Reinstall ueber Battle.net/Steam/Epic Launcher (Einzelfrage betrifft nur den Launcher) |
|
||||
| ARC Raiders | | Embark Studios | | Game — Reinstall ueber Battle.net/Steam/Epic Launcher (Einzelfrage betrifft nur den Launcher) |
|
||||
| Bonjour | 2.0.2.0 | Apple Inc. | | Apple Bonjour — Dependency (z. B. HP), wird bei Bedarf nachgezogen |
|
||||
| Bonjour-Druckdienste | 2.0.2.0 | Apple Inc. | | Apple Bonjour — Dependency (z. B. HP), wird bei Bedarf nachgezogen |
|
||||
| Documentation Manager | 23.40.0.4 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Dynamic Application Loader Host Interface Service | 1.0.0.0 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Epic Games Launcher Prerequisites (x64) | 1.0.0.0 | Epic Games, Inc. | | Epic Games Prerequisite — kommt mit Epic Games Launcher |
|
||||
| Epic Online Services | 4.0.1 | Epic Games, Inc. | | Epic Online Services — kommt mit Epic Games Launcher |
|
||||
| Futuremark SystemInfo | 5.49.1085.0 | Futuremark | | Dependency von 3DMark — wird mit installiert |
|
||||
| Hearthstone | | Blizzard Entertainment | | Game — Reinstall ueber Battle.net/Steam/Epic Launcher (Einzelfrage betrifft nur den Launcher) |
|
||||
| HELLDIVERS™ 2 | | Arrowhead Game Studios | | Game — Reinstall ueber Battle.net/Steam/Epic Launcher (Einzelfrage betrifft nur den Launcher) |
|
||||
| HP EmailSMTP Plugin | 56.0.517.0 | HP | | HP Drucker-Plugin — kommt mit HP-Treiber/HP Smart |
|
||||
| HP OCR | 1.0.1020.0 | HP Inc. | | HP Drucker-Plugin — kommt mit HP-Treiber/HP Smart |
|
||||
| HP SFTP Plugin | 56.0.517.0 | HP Inc. | | HP Drucker-Plugin — kommt mit HP-Treiber/HP Smart |
|
||||
| HP SharePoint Plugin | 56.0.517.0 | HP | | HP Drucker-Plugin — kommt mit HP-Treiber/HP Smart |
|
||||
| Intel(R) Chipset Device Software | 10.1.19899.8597 | Intel(R) Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Intel(R) Chipset Device Software | 10.1.19899.8597 | Intel Corporation | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| Intel(R) Icls | 1.0.0.0 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Intel(R) Management Engine Components | 1.0.0.0 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Intel(R) Management Engine Components | 2425.6.26.0 | Intel Corporation | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| Intel(R) Management Engine Driver | 1.0.0.0 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Intel(R) ME WMI Provider | 1.0.0.0 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Intel(R) Serial IO | 30.100.2131.26 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Intel(R) Serial IO | 30.100.2131.26 | Intel Corporation | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| Intel(R) Wireless Bluetooth(R) | 23.40.0.2 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Intel® Software Installer | 23.40.0.4 | Intel Corporation | | Intel Treiber/Engine — kommt mit Intel Chipset-Driver-Bundle |
|
||||
| Launcher Prerequisites (x64) | 1.0.0.0 | Epic Games, Inc. | | Epic Games Prerequisite — kommt mit Epic Games Launcher |
|
||||
| MaxCut | 2.9.3.9 | MaxCut Software (Pty) Ltd | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| Microsoft Edge | 147.0.3912.98 | Microsoft Corporation | | Microsoft Edge / WebView2 — Bestandteil von Windows 11 |
|
||||
| Microsoft Edge WebView2-Laufzeit | 147.0.3912.98 | Microsoft Corporation | | Microsoft Edge / WebView2 — Bestandteil von Windows 11 |
|
||||
| Microsoft Teams Meeting Add-in for Microsoft Office | 1.26.08901 | Microsoft | | Office-Add-in — kommt mit Microsoft 365 / Teams |
|
||||
| Microsoft Update Health Tools | 5.72.0.0 | Microsoft Corporation | | Windows-Component — Windows Update |
|
||||
| Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.6161 | 9.0.30729.6161 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.6161 | 9.0.30729.6161 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2010 x86 Redistributable - 10.0.30319 | 10.0.30319 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2012 Redistributable (x64) - 11.0.61030 | 11.0.61030.0 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2012 Redistributable (x86) - 11.0.61030 | 11.0.61030.0 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2012 x64 Additional Runtime - 11.0.61030 | 11.0.61030 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2012 x64 Minimum Runtime - 11.0.61030 | 11.0.61030 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2012 x86 Additional Runtime - 11.0.61030 | 11.0.61030 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2012 x86 Minimum Runtime - 11.0.61030 | 11.0.61030 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2013 Redistributable (x64) - 12.0.30501 | 12.0.30501.0 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2013 Redistributable (x86) - 12.0.30501 | 12.0.30501.0 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2013 x64 Additional Runtime - 12.0.21005 | 12.0.21005 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2013 x64 Minimum Runtime - 12.0.21005 | 12.0.21005 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2013 x86 Additional Runtime - 12.0.21005 | 12.0.21005 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2013 x86 Minimum Runtime - 12.0.21005 | 12.0.21005 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2015-2022 Redistributable (x64) - 14.44.35211 | 14.44.35211.0 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2015-2022 Redistributable (x86) - 14.44.35211 | 14.44.35211.0 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2022 X64 Additional Runtime - 14.44.35211 | 14.44.35211 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2022 X64 Minimum Runtime - 14.44.35211 | 14.44.35211 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2022 X86 Additional Runtime - 14.44.35211 | 14.44.35211 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| Microsoft Visual C++ 2022 X86 Minimum Runtime - 14.44.35211 | 14.44.35211 | Microsoft Corporation | | VC++ Redistributable/Runtime — Dependency, wird mit Apps gezogen |
|
||||
| MSI Center SDK | 3.2026.0123.01 | MSI | | MSI Komponente — wird mit MSI Center nachgezogen |
|
||||
| NvCpl | 1.0 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA AIUser Container | 1.48 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA Backend | 11.0.7.237 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA Container | 1.48 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA FrameView SDK 1.7.12227.37421622 | 1.7.12227.37421622 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA Grafiktreiber 596.21 | 596.21 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA HD-Audiotreiber 1.4.5.7 | 1.4.5.7 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA Install Application | 2.1002.442.0 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA LocalSystem Container | 1.48 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA MessageBus 3 for NvApp | 3.21 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA NvDLISR | 1.0 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA PhysX-Systemsoftware 9.23.1019 | 9.23.1019 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA Session Container | 1.48 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA ShadowPlay 11.0.7.0 | 11.0.7.0 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA Telemetry Client | 19.5.13.0 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA User Container | 1.48 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA Virtual Audio 4.65.0.12 | 4.65.0.12 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| NVIDIA Watchdog Plugin for NvContainer | 1.48 | NVIDIA Corporation | | NVIDIA Driver-Komponente — wird mit dem NVIDIA-App-/Treiber-Bundle installiert |
|
||||
| Office 16 Click-to-Run Extensibility Component | 16.0.19929.20136 | Microsoft Corporation | | Office-Komponente — kommt mit Microsoft 365 |
|
||||
| Office 16 Click-to-Run Localization Component | 16.0.19929.20062 | Microsoft Corporation | | Office-Komponente — kommt mit Microsoft 365 |
|
||||
| Overwatch | | Blizzard Entertainment | | Game — Reinstall ueber Battle.net/Steam/Epic Launcher (Einzelfrage betrifft nur den Launcher) |
|
||||
| PingPlotter 5 | 5.18.0.7997 | Pingman Tools, LLC | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| Plex Media Server | 1.40.3.8555 | Plex, Inc. | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| PUBG: BATTLEGROUNDS | | KRAFTON, Inc. | | Game — Reinstall ueber Battle.net/Steam/Epic Launcher (Einzelfrage betrifft nur den Launcher) |
|
||||
| Python 3.13.3 Add to Path (64-bit) | 3.13.3150.0 | Python Software Foundation | | Sub-Komponente von Python 3.13 — wird mit dem Python-Hauptpaket nachgezogen |
|
||||
| Python 3.13.3 Development Libraries (64-bit) | 3.13.3150.0 | Python Software Foundation | | Sub-Komponente von Python 3.13 — wird mit dem Python-Hauptpaket nachgezogen |
|
||||
| Python 3.13.3 Documentation (64-bit) | 3.13.3150.0 | Python Software Foundation | | Sub-Komponente von Python 3.13 — wird mit dem Python-Hauptpaket nachgezogen |
|
||||
| Python 3.13.3 Executables (64-bit) | 3.13.3150.0 | Python Software Foundation | | Sub-Komponente von Python 3.13 — wird mit dem Python-Hauptpaket nachgezogen |
|
||||
| Python 3.13.3 pip Bootstrap (64-bit) | 3.13.3150.0 | Python Software Foundation | | Sub-Komponente von Python 3.13 — wird mit dem Python-Hauptpaket nachgezogen |
|
||||
| Python 3.13.3 Standard Library (64-bit) | 3.13.3150.0 | Python Software Foundation | | Sub-Komponente von Python 3.13 — wird mit dem Python-Hauptpaket nachgezogen |
|
||||
| Python 3.13.3 Tcl/Tk Support (64-bit) | 3.13.3150.0 | Python Software Foundation | | Sub-Komponente von Python 3.13 — wird mit dem Python-Hauptpaket nachgezogen |
|
||||
| Python 3.13.3 Test Suite (64-bit) | 3.13.3150.0 | Python Software Foundation | | Sub-Komponente von Python 3.13 — wird mit dem Python-Hauptpaket nachgezogen |
|
||||
| Realtek USB Audio | 6.4.0.2422 | Realtek Semiconductor Corp. | | Realtek Audio-Treiber — kommt mit Chipset-/Audio-Driver-Bundle |
|
||||
| Stopping Plex | 1.40.3555 | Plex, Inc. | | Artefakt, kein echtes Programm |
|
||||
| THX Spatial Audio USB 1532-0555 | 3.2.3.0 | THX | | THX Audio-Komponente — kommt mit Audio-/Headset-Treiber |
|
||||
| THX Spatial Audio USB 1532-0555 | 3.2.3.0 | THX | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| THX V3 APO Presets | 3.2.11.0 | THX | | THX Audio-Komponente — kommt mit Audio-/Headset-Treiber |
|
||||
| THX V3 APO Presets | 3.2.11.0 | THX | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| THX V3 APO Presets | 3.2.14.0 | THX | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| THX V3 APO Presets | 3.2.12.0 | THX | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| THX V3 APO Presets | 3.2.12.0 | THX | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| THX V3 APO Presets | 3.2.11.0 | THX | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| THX V3 APO Presets | 3.2.14.0 | THX | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| THX V3 APO Presets | 3.2.11.0 | THX | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| WD Desktop App 2.1.0.335 | 2.1.0.335 | Western Digital Corporation | | WD Desktop App (legacy) — durch WD Discovery abgeloest |
|
||||
| WD Desktop App 2.1.0.335 (x64) | 2.1.0.335 | Western Digital Corporation | | WD Desktop App (legacy) — durch WD Discovery abgeloest |
|
||||
| WD Drive Utilities | 2.1.0.142 | Western Digital Technologies, Inc. | | Duplikat (zweiter Registry-Hive-Eintrag desselben Programms, siehe oben) |
|
||||
| WD SES Driver Setup | 2.1.0 | Western Digital | | Altes WD-Driver-Setup — wird durch aktuelle WD-Tools ersetzt |
|
||||
| World of Warcraft | | Blizzard Entertainment | | Game — Reinstall ueber Battle.net/Steam/Epic Launcher (Einzelfrage betrifft nur den Launcher) |
|
||||
| World of Warcraft Classic Era | | Blizzard Entertainment | | Game — Reinstall ueber Battle.net/Steam/Epic Launcher (Einzelfrage betrifft nur den Launcher) |
|
||||
|
||||
---
|
||||
|
||||
## Verifikations-Block
|
||||
|
||||
- Eintraege total: 161
|
||||
- Auto-Ja: 18
|
||||
- Einzelfrage: 38
|
||||
- Auto-Skip: 105
|
||||
- Quelle: 161 Eintraege in `installierte_programme.csv`
|
||||
- Stimmt: 18 + 38 + 105 == 161 == 161
|
||||
|
||||
## Aenderungs-Workflow
|
||||
|
||||
Falls Micha vor der Neuinstallation noch Eintraege umsortieren will: direkt in diesem Markdown-File die Zeile zwischen den Sektionen verschieben und Begruendung anpassen. Diese Datei ist die Wahrheit fuer den Wiederaufbau-Schritt.
|
||||
@@ -1,303 +0,0 @@
|
||||
# System-Audit 2026-06-05
|
||||
|
||||
**Scope:** Windows-Host `baerchen` (frisch aufgesetzt), Read-only
|
||||
**Referenz-Doku:** `ops/windows-reinstall/docs/laufwerks-neustruktur-2026-06-04.md`, `boot-cleanup-plan-2026-06-04.md`
|
||||
**Durchgeführt:** 2026-06-05, ohne Admin-Rechte
|
||||
**Rohdaten:** `audit/raw/01_volumes_partitions.txt` bis `06_events_hardware.txt`
|
||||
|
||||
---
|
||||
|
||||
## 1. Ordner- und Laufwerksstruktur (Priorität)
|
||||
|
||||
### 1.1 Soll-Ist-Vergleich: Ordner-Existenz
|
||||
|
||||
| Pfad | Soll | Ist | Status |
|
||||
|---|---|---|---|
|
||||
| `D:\00_Inbox` | ✓ | vorhanden | OK |
|
||||
| `D:\10_Dokumente` | ✓ | vorhanden | OK |
|
||||
| `D:\11_Bilder` | ✓ | vorhanden | OK, aber ReadOnly-Attribut gesetzt |
|
||||
| `D:\12_Videos` | ✓ | vorhanden | OK |
|
||||
| `D:\13_Musik` | ✓ | vorhanden | OK |
|
||||
| `D:\14_Downloads` | ✓ | vorhanden | OK |
|
||||
| `D:\20_Projekte\aktiv` | ✓ | vorhanden | OK |
|
||||
| `D:\20_Projekte\archiv` | ✓ | vorhanden | OK |
|
||||
| `D:\30_Finanzen\Banking4` | ✓ | vorhanden | OK |
|
||||
| `D:\30_Finanzen\WISO_Steuer` | ✓ | vorhanden | OK |
|
||||
| `D:\90_Archiv` | ✓ | vorhanden | OK |
|
||||
| `E:\Steam\steamapps` | ✓ | vorhanden | OK |
|
||||
| `E:\BattleNet` | ✓ | vorhanden | OK |
|
||||
| `E:\EpicGames` | ✓ | vorhanden | OK |
|
||||
| `E:\EA` | ✓ | vorhanden | OK |
|
||||
| `E:\Riot` | ✓ | vorhanden | OK |
|
||||
| `E:\Ubisoft` | ✓ | vorhanden | OK |
|
||||
| **`E:\_Standalone`** | **✓** | **FEHLT** | **LÜCKE** |
|
||||
| `G:\repos` | ✓ | vorhanden | OK |
|
||||
| `G:\tools` | ✓ | vorhanden als `Tools` (Großbuchstabe) | OK (NTFS case-insensitive) |
|
||||
|
||||
**Nicht in Soll-Doku, aber vorhanden:**
|
||||
|
||||
| Pfad | Beurteilung |
|
||||
|---|---|
|
||||
| `D:\Micha\Videos` | Altquelle, fast leer (1 Datei), Rest wurde bereinigt |
|
||||
| `D:\WSL` | WSL-Datenpfad, nicht in Doku erwähnt, aber logisch |
|
||||
| `G:\Apps` | Zweck unklar, nicht dokumentiert |
|
||||
| `G:\Gitea_Clone` | Bewusst so (homelab-infra bleibt laut Doku unangetastet) |
|
||||
| `G:\Workspace` | Nicht dokumentiert, wahrscheinlich Dev-Workspace |
|
||||
|
||||
### 1.2 Known-Folder-Redirects
|
||||
|
||||
| Ordner | Soll (Doku) | Ist (gemessen) | Status |
|
||||
|---|---|---|---|
|
||||
| Desktop | `D:\Micha\Desktop` | `D:\00_Inbox\Desktop` | **ABWEICHUNG** |
|
||||
| Dokumente | `D:\10_Dokumente` | `D:\10_Dokumente` | OK |
|
||||
| Downloads | `D:\14_Downloads` | `D:\14_Downloads` | OK |
|
||||
| Bilder | `D:\11_Bilder` | `D:\11_Bilder` | OK |
|
||||
| Musik | `D:\13_Musik` | `D:\13_Musik` | OK |
|
||||
| Videos | `D:\12_Videos` | `D:\12_Videos` | OK |
|
||||
|
||||
**Desktop-Befund (Detail):**
|
||||
- Soll-Doku schreibt: `D:\Micha\Desktop` (als bewusster Sonderfall ohne nummerierten Ordner).
|
||||
- Ist: Desktop zeigt auf `D:\00_Inbox\Desktop` — dieser Ordner existiert, enthält 4 Dateien.
|
||||
- `D:\Micha\Desktop` existiert **nicht**.
|
||||
- `D:\Micha` enthält nur noch `Videos` (1 Datei, leer).
|
||||
- Fazit: Das Known-Folder-Ziel wurde nach der Doku-Erstellung nochmals geändert. Die Doku ist in diesem Punkt veraltet. Der Desktop liegt funktional korrekt auf D:, aber das Ziel weicht vom dokumentierten Soll ab. **Doku-Update empfohlen.**
|
||||
|
||||
### 1.3 Doppelbestand D:\Micha\* vs. neue Nummernstruktur
|
||||
|
||||
| Alt | Dateien | Neu | Dateien | Bewertung |
|
||||
|---|---|---|---|---|
|
||||
| `D:\Micha\Dokumente` | NICHT MEHR VORHANDEN | `D:\10_Dokumente` | 4011 / 595 MB | Bereinigt ✓ |
|
||||
| `D:\Micha\Bilder` | NICHT MEHR VORHANDEN | `D:\11_Bilder` | 7789 / 12,4 GB | Bereinigt ✓ |
|
||||
| `D:\Micha\Videos` | 1 Datei, ~0 MB | `D:\12_Videos` | 1 Datei, ~0 MB | Quasi-leer, kein Doppelbestand |
|
||||
| `D:\Micha\Musik` | NICHT MEHR VORHANDEN | `D:\13_Musik` | 0 Dateien | Bereinigt ✓ |
|
||||
| `D:\Micha\Downloads` | NICHT MEHR VORHANDEN | `D:\14_Downloads` | 2186 / 2,2 GB | Bereinigt ✓ |
|
||||
| `D:\Micha\Finanzen` | NICHT MEHR VORHANDEN | `D:\30_Finanzen` | 126 / 123 MB | Bereinigt ✓ |
|
||||
|
||||
**Fazit:** Der befürchtete Doppelbestand ist weitgehend aufgelöst. Nur `D:\Micha\Videos` ist noch vorhanden, ist aber inhaltlich leer. `D:\Micha` kann nach manueller Prüfung von Videos entfernt werden.
|
||||
|
||||
### 1.4 Labels
|
||||
|
||||
| Laufwerk | Soll | Ist | Status |
|
||||
|---|---|---|---|
|
||||
| D: | `Daten-Projekte` | `Daten-Projekte` | OK ✓ |
|
||||
| E: | `Games` | `Games` | OK ✓ |
|
||||
| H: | unveraendert | `Externe HDD` | OK ✓ |
|
||||
|
||||
### 1.5 Rollen-Konsistenz und Partitions-Layout
|
||||
|
||||
| Laufwerk | Soll-Rolle | Ist | Status |
|
||||
|---|---|---|---|
|
||||
| C: | Windows + kleine Programme | Disk 0, 167 GB SATA | OK |
|
||||
| D: | Daten & Projekte | Disk 1, 168 GB SATA | OK |
|
||||
| E: | Games | Disk 2, **930 GB** NVMe (nach F-Merge) | OK ✓ |
|
||||
| F: | Altes Windows (löschen) | **Nicht mehr vorhanden** | Abgeschlossen ✓ |
|
||||
| G: | Arbeits-SSD, Homelab/Dev | Disk 3, 931 GB NVMe | OK |
|
||||
| H: | Externe Backup-HDD | Disk 4, 7.28 TB USB | OK |
|
||||
|
||||
E: und das ehemalige F: sind jetzt eine einzige 930 GB Partition auf Disk 2. Layout ist sauber.
|
||||
|
||||
### 1.6 Fachliche Gesamtbewertung der Struktur
|
||||
|
||||
**Stärken:**
|
||||
- Die Nummernstruktur auf D: ist vollständig angelegt und die Known Folders zeigen bis auf Desktop korrekt dorthin.
|
||||
- Der Doppelbestand ist fast vollständig bereinigt — das war die größte Risikoquelle.
|
||||
- F: ist weg, E: ist auf volle Disk-Kapazität gewachsen — die BCD-Bereinigung und Partition-Erweiterung wurde sauber abgeschlossen.
|
||||
- Label-Benennung konsistent.
|
||||
- G: ist operational (repos, Tools, Gitea_Clone vorhanden).
|
||||
|
||||
**Lücken und Inkonsistenzen:**
|
||||
1. **Desktop-Redirect weicht von Doku ab** (Ist: `D:\00_Inbox\Desktop`, Doku: `D:\Micha\Desktop`). Da `D:\Micha\Desktop` nicht existiert und der Desktop funktioniert, ist die Doku das Problem, nicht das System.
|
||||
2. **`E:\_Standalone` fehlt** — laut Doku angelegt, tatsächlich nicht vorhanden. Kein funktionaler Schaden, aber Inkonsistenz zur Rollenbeschreibung.
|
||||
3. **`D:\11_Bilder` hat ReadOnly-Attribut** auf Ordner-Ebene gesetzt — ungewöhnlich, keine erkennbare Ursache. Kein Showstopper, aber prüfenswert.
|
||||
4. **`G:\Apps`, `G:\Workspace`** sind nicht in der Soll-Doku definiert. Kein Problem an sich, aber für spätere Audits hilfreich zu dokumentieren.
|
||||
5. **`D:\WSL`** nicht dokumentiert — WSL-Datenpfade dort gehören explizit erwähnt.
|
||||
6. **`D:\13_Musik`** ist leer (0 Dateien) — entweder war `D:\Micha\Musik` schon leer, oder die Kopie ist ausgeblieben. Zu prüfen ob Musik aus PostDelta-Backup nachgezogen werden muss.
|
||||
|
||||
**Gesamturteil:** Die Struktur ist in sich schlüssig und der Umbau ist zu ~95% abgeschlossen. Die verbleibenden Punkte sind kleine Doku-Lücken und ein fehlender Ordner, kein strukturelles Problem.
|
||||
|
||||
---
|
||||
|
||||
## 2. OS-Baseline
|
||||
|
||||
| Feld | Wert | Bewertung |
|
||||
|---|---|---|
|
||||
| Edition | Windows 11 Pro | OK |
|
||||
| Build | 26200 (Insider/Preview-Build) | Achtung: kein Stable-Channel-Build |
|
||||
| Aktivierung | OEM_DM, aktiv | OK |
|
||||
| Installiert | 2026-05-10 | ~25 Tage alt |
|
||||
| Letzter Boot | 2026-06-05 07:57 | Frisch gebootet |
|
||||
| Ausstehende Updates | 0 | OK |
|
||||
| Reboot pending | Nein | OK |
|
||||
|
||||
**Befund Build 26200:** Das ist ein Windows Insider/Canary-Channel Build, kein Produktions-Release. Für einen Nerd-Einsatz vertretbar, aber mit dem Wissen verbunden, dass Insider-Builds weniger stabil sind und keine LTS-Garantie haben.
|
||||
|
||||
---
|
||||
|
||||
## 3. Security
|
||||
|
||||
### Defender
|
||||
- Aktiv, TamperProtection an, Signaturen aktuell. **OK.**
|
||||
- Ausschlüsse und ASR-Regeln: nur als Admin lesbar — **kein Befund, aber blind spot.**
|
||||
|
||||
### Firewall
|
||||
- Alle drei Profile aktiv. DefaultInboundAction `NotConfigured` bedeutet im Windows-Default: eingehend blockieren, ausgehend erlauben. **OK.**
|
||||
- Port 27036 (Steam Remote Play) lauscht auf `0.0.0.0` — also LAN-seitig offen. Erwartetes Steam-Verhalten, aber explizit im Bewusstsein halten.
|
||||
|
||||
### BitLocker
|
||||
- Nicht prüfbar ohne Admin. **Blind spot — Empfehlung: BitLocker für C: und D: aktivieren.**
|
||||
|
||||
### Secure Boot / TPM
|
||||
- Nicht prüfbar ohne Admin. Hardware MSI MS-7D32 unterstützt beides. Status unbekannt.
|
||||
|
||||
### UAC
|
||||
- Standard-Konfiguration korrekt (Secure Desktop aktiv). **OK.**
|
||||
|
||||
### Lokale Admins
|
||||
- `Administrator` (Built-in) + `michi`. Zwei Accounts in Admins ist normal für einen Einzel-PC. OK.
|
||||
|
||||
### SSH Key Permissions
|
||||
- `id_ed25519` hat `VORDEFINIERT\Administratoren FullControl` — das ist zu weit offen.
|
||||
- SSH-Clients unter Windows tolerieren das, aber best practice ist: nur der eigene User darf lesen.
|
||||
- **Empfehlung:** `icacls` Berechtigungen auf User only setzen (als Admin ausführen).
|
||||
|
||||
---
|
||||
|
||||
## 4. Storage & Boot
|
||||
|
||||
- Alle 5 physischen Disks: **Healthy / OK.**
|
||||
- Wear-Level via `Get-StorageReliabilityCounter`: keine Ausgabe (SATA-SSDs und USB HDD liefern keine WMI-Daten). CrystalDiskInfo ist installiert — dort manuell prüfen.
|
||||
- Die zwei Intel SATA SSDs (Disk 0 + 1) sind **180 GB** — typische Einzel-Partition-Auslastung auf C: ~36% und D: ~11%, reichlich Luft.
|
||||
- **BCD:** ohne Admin nicht lesbar. Doku bestätigt sauberen Zustand nach Cleanup + Neustarttest.
|
||||
- **WinRE:** ohne Admin nicht lesbar. Doku sagt Disabled — muss vor künftiger Partitionsarbeit aktiviert werden.
|
||||
|
||||
---
|
||||
|
||||
## 5. Netzwerk
|
||||
|
||||
- Ethernet: 192.168.178.103, DNS auf Kallilabcore (AdGuard). **Korrekt.**
|
||||
- Tailscale: aktiv, dieser Rechner als `baerchen-1` online, direkter Pfad zu `kallilabcore`. **OK.**
|
||||
- Kein SSH-Config — alle SSH-Verbindungen laufen ohne Host-Aliases. Funktional, aber unpraktisch.
|
||||
- Lauschende Ports: Keine auffälligen Exposition nach außen außer SMB (139/445 — LAN-normal) und Steam 27036.
|
||||
|
||||
---
|
||||
|
||||
## 6. Remote-Management / SSH
|
||||
|
||||
- Kein `~\.ssh\config` vorhanden. Empfehlung: Host-Aliases anlegen (z.B. `Host kallilabcore`).
|
||||
- SSH-Key vorhanden und aktuell.
|
||||
- **Key-Rechte zu weit (s. Security).**
|
||||
- Docker contexts: `desktop-linux` aktiv. Docker Desktop läuft.
|
||||
- kubectl: keine Contexts — erwartet (kein k8s im Homelab).
|
||||
- Tailscale: direkter Pfad zu Homelab aktiv, SSH über Tailscale-IP funktioniert.
|
||||
|
||||
---
|
||||
|
||||
## 7. Dev-Toolchain
|
||||
|
||||
| Tool | Version | Bewertung |
|
||||
|---|---|---|
|
||||
| git | 2.54.0 | Aktuell, OK |
|
||||
| Python | 3.13.13 | Aktuell, OK |
|
||||
| Node.js | 24.16.0 (LTS) | Aktuell, OK |
|
||||
| Go | 1.26.4 | Aktuell, OK |
|
||||
| Commit-Signing | nicht konfiguriert | Optional, aber für Homelab-GitOps empfohlen |
|
||||
|
||||
WSL Ubuntu ist installiert aber gestoppt. docker-desktop läuft als WSL2-Backend.
|
||||
|
||||
---
|
||||
|
||||
## 8. Hardware & Performance
|
||||
|
||||
- i5-14600KF, 14C/20T, 31.8 GB RAM — für Homelab-Dev-Rechner gut ausgestattet.
|
||||
- Energieplan: **Ausbalanciert** — für einen Gaming- und Dev-Rechner suboptimal. `Höchstleistung` oder `Ultimative Leistung` wäre bei dauerhafter Nutzung besser.
|
||||
- Keine echten Gerätekonflikte in PnP (alle "Unknown" sind erwartet: ghosted devices, Netzwerkgeräte, VSS).
|
||||
|
||||
---
|
||||
|
||||
## 9. Autostart & Persistenz
|
||||
|
||||
Läuft automatisch: Brave Update, Steam, Razer Synapse, Docker Desktop, iCUE, Realtek Audio, Tailscale, Ollama.
|
||||
|
||||
**Auffällig:** `SoftLanding\CreativeManagementTask` — unbekannter Scheduled Task, nicht einem Standard-Produkt zuzuordnen. Sollte manuell im Task Scheduler geprüft werden (Quelle, Executable, Publisher).
|
||||
|
||||
OneDrive läuft mit drei Tasks (Startup + Update) — falls Daten-Sync nicht gewünscht ist, sollte OneDrive deaktiviert werden, da es Dokumente/Bilder/etc. stummschalten könnte (bekanntes Windows-Verhalten nach Known-Folder-Redirect).
|
||||
|
||||
---
|
||||
|
||||
## 10. Zuverlässigkeit
|
||||
|
||||
| Event ID | Anzahl | Beschreibung | Risiko |
|
||||
|---|---|---|---|
|
||||
| 20 | 70 | Defender KB4052623 Update-Fehler (0x80240016) | Niedrig — Timing, Defender aktuell |
|
||||
| 10010 | 15 | DCOM Server Timeout | Niedrig — Windows-Hintergrund |
|
||||
| 7000 | 3 | Steam Service Start fehlgeschlagen | Niedrig — Race Condition beim Boot |
|
||||
| 7023 | 3 | Windows Modules Installer beendet mit Fehler | Mittel — Update-Abbrüche prüfen |
|
||||
| **6008** | **2** | **Unerwartetes Herunterfahren 2026-05-19 13:56** | **Mittel — einmaliger BSOD/Stromausfall** |
|
||||
| 7034 | 2 | MSI Center Service Absturz | Niedrig |
|
||||
|
||||
- **Kein Crash-Dump** vorhanden (`C:\Windows\Minidump` leer). Entweder ist kein BSOD gewesen (Stromausfall), oder Dump-Einstellungen schreiben nicht.
|
||||
- Empfehlung: Dump-Einstellungen auf "Kleiner Speicherauszug" oder "Vollständiger Speicherauszug" prüfen.
|
||||
|
||||
---
|
||||
|
||||
## 11. Homelab-Server (ausstehend)
|
||||
|
||||
**Status: NICHT DURCHGEFÜHRT**
|
||||
|
||||
SSH-Config ist leer — kein Host-Alias konfiguriert. Tailscale zeigt `kallilabcore` als aktiv auf `100.80.98.33` / `192.168.178.58`.
|
||||
|
||||
**Bitte bestätigen:**
|
||||
- SSH-User für Kallilabcore (wahrscheinlich `root`?)
|
||||
- Soll ich `ssh root@192.168.178.58` oder über Tailscale-IP verwenden?
|
||||
|
||||
Nach Bestätigung wird der Homelab-Teil nachgezogen und dieser Report ergänzt.
|
||||
|
||||
---
|
||||
|
||||
## 12. Gesamt-Findings (priorisiert)
|
||||
|
||||
### Kritisch / Handlungsbedarf vor nächster Partitionsarbeit
|
||||
| # | Befund | Begründung |
|
||||
|---|---|---|
|
||||
| K1 | WinRE ist Disabled (laut Doku) | Ohne WinRE kein automatisches Recovery. Muss aktiviert werden bevor weitere Disk-Ops. |
|
||||
| K2 | BitLocker-Status unbekannt (kein Admin) | C: und D: sollten verschlüsselt sein — aktuell Blind Spot. |
|
||||
|
||||
### Mittel / Zeitnah klären
|
||||
| # | Befund |
|
||||
|---|---|
|
||||
| M1 | Desktop-Redirect zeigt auf `D:\00_Inbox\Desktop`, Doku sagt `D:\Micha\Desktop` — Doku aktualisieren |
|
||||
| M2 | `E:\_Standalone` fehlt — Ordner anlegen oder aus Doku streichen |
|
||||
| M3 | SSH Private Key Permissions zu weit (Admins haben FullControl) |
|
||||
| M4 | Energieplan "Ausbalanciert" — für Gaming/Dev `Höchstleistung` empfohlen |
|
||||
| M5 | `SoftLanding\CreativeManagementTask` unbekannt — Quelle und Publisher prüfen |
|
||||
| M6 | Unerwartetes Herunterfahren 2026-05-19 — Ursache klären (Stromausfall? BSOD ohne Dump?) |
|
||||
| M7 | `D:\11_Bilder` hat ReadOnly-Attribut — Ursache und Auswirkung prüfen |
|
||||
|
||||
### Niedrig / Nice-to-have
|
||||
| # | Befund |
|
||||
|---|---|
|
||||
| N1 | SSH-Config leer — Host-Aliases anlegen |
|
||||
| N2 | Git commit.gpgsign nicht gesetzt — für GitOps-Commits empfohlen |
|
||||
| N3 | `D:\Micha\Videos` noch vorhanden (1 leere Datei) — bereinigen |
|
||||
| N4 | `G:\Apps`, `G:\Workspace` nicht in Doku — dokumentieren oder strukturieren |
|
||||
| N5 | `D:\WSL` nicht in Doku — erwähnen |
|
||||
| N6 | `D:\13_Musik` leer — Musik aus PostDelta-Backup nachziehen? |
|
||||
| N7 | OneDrive läuft (3 Tasks) — prüfen ob Sync für D:\10_Dokumente etc. gewünscht |
|
||||
| N8 | Energiesparmodus-Dump-Einstellungen prüfen (kein Dump für 6008-Event) |
|
||||
| N9 | `D:\DumpStack.log` ist ein Artefakt aus der alten D:-Nutzung, kann bereinigt werden |
|
||||
| N10 | Insider-Build 26200 — bewusste Entscheidung, aber dokumentieren |
|
||||
|
||||
---
|
||||
|
||||
## 13. Nächste Schritte (empfohlen, nicht ausgeführt)
|
||||
|
||||
1. **Homelab-SSH-Zugang bestätigen** und Homelab-Audit nachziehen.
|
||||
2. **WinRE aktivieren** (als Admin: `reagentc /enable`) — Voraussetzung für künftige Disk-Ops.
|
||||
3. **BitLocker Status prüfen** (als Admin: `Get-BitLockerVolume`) und ggf. für C:/D: aktivieren.
|
||||
4. **SSH-Key-Permissions straffen**: `icacls $env:USERPROFILE\.ssh\id_ed25519 /inheritance:r /grant:r "$env:USERNAME:F"` (als Admin).
|
||||
5. **`SoftLanding\CreativeManagementTask` untersuchen** — im Task Scheduler Quelle und Aktion prüfen.
|
||||
6. **Doku `laufwerks-neustruktur-2026-06-04.md`** unter Abschnitt Desktop-Befund korrigieren: Ist-Ziel `D:\00_Inbox\Desktop`.
|
||||
7. **`E:\_Standalone`** anlegen falls geplant.
|
||||
8. **`D:\Micha\Videos`** prüfen und ggf. löschen.
|
||||
9. **CrystalDiskInfo** für SSD Wear-Level öffnen und Werte dokumentieren.
|
||||
10. **Energieplan** auf `Höchstleistung` oder `Ultimative Leistung` umstellen.
|
||||
@@ -1,25 +0,0 @@
|
||||
# Archiv
|
||||
|
||||
Typ: Index · Stand: 2026-06-11 · Status: aktiv
|
||||
|
||||
Abgeschlossene Snapshots, Drills, Audits und abgeloeste Plaene mit Referenzwert.
|
||||
Inhalte hier werden nicht mehr gepflegt; die fuehrenden Quellen stehen in der
|
||||
Spalte "Abgeloest durch". Sprint-Boards und erledigte Arbeitslisten werden nicht
|
||||
archiviert, sondern geloescht (Git-Historie ist das Archiv).
|
||||
|
||||
## 2026
|
||||
|
||||
| Datei | Was es war | Abgeloest durch / Ergebnis eingearbeitet in |
|
||||
|---|---|---|
|
||||
| `2026/BACKUP_AUDIT_STATUS_QUO_2026-04-15.md` | Ist-Aufnahme Backup vor der Borg-Migration | `ops/borg-ui/BACKUP_SCOPE.md` |
|
||||
| `2026/DR_DRILL_2026-06-03.md` | DR-Tabletop-Drill, 23 Befunde | Doku-Fixes in `docs/DISASTER_RECOVERY.md` und `docs/EXTERNAL_DEPENDENCIES.md` |
|
||||
| `2026/system-audit-baerchen-2026-06-05.md` | Read-only-Audit der Windows-Workstation | Befunde abgearbeitet bzw. Operator-Entscheidungen in `docs/DECISIONS.md` |
|
||||
| `2026/dr-workstation-readiness-2026-06-06.md` | Automatischer Readiness-Check DR-Workstation | `docs/EXTERNAL_DEPENDENCIES.md` Abschnitt "DR-Workstation Bare-Metal-Kit" |
|
||||
| `2026/HOME_ASSISTANT_INFLUXDB_ECOWITT.md` | Zielbild-Entwurf HA -> InfluxDB 3; HA existiert seit Crash nicht mehr | Neuaufbau braucht neue Inventur; Entwurf nur Referenz |
|
||||
| `2026/windows-neuaufsetzen-masterplan.md` | Masterplan Windows-Neuaufsetzen Mai 2026 (abgeschlossen) | Aktiv bleibt nur `ops/windows-reinstall/` (Skripte, Veeam-Baseline, Laufwerksstruktur) |
|
||||
| `2026/postdelta-2026-06-04.md` | PostDelta-Datenstand nach Neuinstallation | Projekt abgeschlossen |
|
||||
| `2026/programme-entscheidung-2026-06-04.md` | Programm-Reinstall-Entscheidungen | Projekt abgeschlossen |
|
||||
| `2026/boot-cleanup-plan-2026-06-04.md` | BCD-/Boot-Bereinigungsplan | Umgesetzt; Endzustand im System-Audit belegt |
|
||||
| `2026/postinstall-erstes-ziel-codex.md` | Postinstall-Arbeitsauftrag | Projekt abgeschlossen |
|
||||
| `2026/baerchen-app-license-readiness-2026-06-06.md` | App-/Lizenz-Readiness-Check | Projekt abgeschlossen |
|
||||
| `2026/homelab-doku-optimierung-2026-06-11.md` | Analyse + Vorschlag zur Doku-Konsolidierung | umgesetzt 2026-06-11; Regeln in `docs/REPO_MAP.md`, Entscheidung in `docs/DECISIONS.md` |
|
||||
@@ -1,228 +0,0 @@
|
||||
# Homelab-Optimierung — Assessment 2026-06-10
|
||||
|
||||
Read-only-Analyse des Repos (Stand `master`, lokale Arbeitskopie 2026-06-10).
|
||||
Keine produktiven Änderungen durchgeführt. Alle Empfehlungen sind Vorschläge
|
||||
mit Rollback-Plan; nichts wurde deployed.
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Das KalliLab-CORE-Homelab ist für ein Ein-Host-Setup ungewöhnlich reif:
|
||||
GitOps mit Gitea+Komodo, sauberes Netzmodell (frontend/backend/app-intern),
|
||||
Authelia mit 2FA-Catch-all, belegte Restore-Drills für alle Tier-1/2-Dienste,
|
||||
Off-site-Borg nach Hetzner, DR-Workstation-Kit, Monitoring mit Prometheus/
|
||||
Loki/Grafana/Alertmanager→ntfy. Die Doku-Disziplin ist das eigentliche Asset.
|
||||
|
||||
Die größten realen Lücken liegen nicht in der Architektur, sondern in der
|
||||
**Container-Betriebsebene**: 20 von 30 Stacks haben keinen Healthcheck, kein
|
||||
einziger Container hat Memory-/CPU-Limits, und mehrere Images laufen auf
|
||||
mutablen Tags (`release`, `latest`, `:2`), bei denen Renovate-Digest-Bumps
|
||||
faktisch unkontrollierte Versionssprünge sind — am kritischsten bei Immich.
|
||||
Dazu kommen zwei strukturelle Risiken: **AdGuard ist DNS-SPOF ohne Fallback**
|
||||
(hat bereits einen Teil-Deploy-Ausfall verursacht) und **Borg-Backups sind
|
||||
vom Host aus löschbar** (append-only bewusst abgelehnt, aber die kostenlose
|
||||
Kompensation — Hetzner-Storage-Box-Snapshots — ist nicht aktiviert).
|
||||
|
||||
## Gesamtbewertung
|
||||
|
||||
| Bereich | Note | Begründung |
|
||||
|---|---|---|
|
||||
| Architektur | **sehr gut** | klares Netzmodell, dokumentierte Ausnahmen, ein Ingress, Compose-first konsequent |
|
||||
| Netzwerk/DNS/Proxy | **gut, ein SPOF** | Traefik v3 labelbasiert sauber; AdGuard+Unbound ohne zweiten Resolver — bekannter Vorfall (Bulk-Deploy-DNS-Ausfall, `docs/runbooks/komodo-bulk-deploy-dns.md`) |
|
||||
| Container-Betrieb | **mittel** | 10/30 Stacks mit Healthcheck, 0 Ressourcen-Limits, mutable Tags hinter Digests versteckt |
|
||||
| Storage/Backups | **sehr gut** | Borg→Hetzner, Dumps, H:/-Nearline, Restore-Drills mit Reports belegt; offen: Backup-Löschschutz |
|
||||
| Security/Secrets | **gut** | `_FILE`/Stack-ENV konsequent, 2FA-Catch-all, WAN nur 443/tcp; `no-new-privileges` nur in 10/30 Stacks trotz P8-Pflichtregel |
|
||||
| Monitoring/Alerting | **gut** | Prometheus/Blackbox/Loki/ntfy-Kette steht; Monitoring-Stack selbst hat keine Healthchecks und überwacht sich nicht selbst |
|
||||
| Automatisierung/IaC | **sehr gut** | Komodo-Webhooks, Renovate, Posture-Check, Critical-Events-Watcher; manuelle Sync-Ausnahmen (traefik/dynamic, Authelia-Config) sind dokumentiert, aber fehleranfällig |
|
||||
| Ausfallsicherheit | **bewusst begrenzt** | Ein Host, keine USV (geparkt Q3/2026), kein WAN-Failover — als akzeptiertes Risiko dokumentiert, das ist legitim |
|
||||
| Strom/Kosten | **keine Daten** | keine Verbrauchsmessung im Repo sichtbar — siehe offene Fragen |
|
||||
|
||||
## Top 10 Verbesserungen nach Mehrwert
|
||||
|
||||
### 1. Immich vom `release`-Tag auf Versions-Tag pinnen
|
||||
- **Beobachtung:** `apps/immich/docker-compose.yml:4` nutzt `immich-server:release@sha256:...` (ebenso ML). Renovate aktualisiert Digests — beim `release`-Tag ist ein "Digest-Update" in Wahrheit ein Major-/Minor-Versionssprung, ohne dass es im PR-Titel sichtbar wird. Immich ist berüchtigt für Breaking Changes zwischen Minors.
|
||||
- **Warum relevant:** Ein gemergter "harmloser" Digest-PR kann Immich unangekündigt auf eine inkompatible Version heben (DB-Migrationen, ML-Modell-Wechsel).
|
||||
- **Änderung:** Tag auf die konkret laufende Version umstellen (z. B. `immich-server:v2.x.y@sha256:<aktueller Digest>`), gleiche Vorgehensweise wie bei Mealie/Paperless. Laufende Version ermitteln: `docker exec immich_server cat /usr/src/app/package.json | grep version` oder Immich-UI → Version.
|
||||
- **Verifikation:** Renovate erzeugt danach Versions-PRs statt stiller Digest-PRs; `docker inspect immich_server --format '{{.Config.Image}}'` zeigt den Versionstag.
|
||||
- **Rollback:** Commit revert; Digest bleibt identisch, kein Redeploy-Zwang.
|
||||
- **Nebenwirkungen:** keine zur Laufzeit (Digest unverändert). | Nutzen: **hoch** | Risiko: niedrig | Aufwand: klein | sofort
|
||||
- Gleiches Muster prüfen für: `komodo:2`, `ddns-updater:latest`, `scrutiny:latest-omnibus`, `glances:latest-full` sowie tag-lose digest-only Images (`mail-archiver`, `borg-ui`, `ntfy` — Version im Compose unsichtbar).
|
||||
|
||||
### 2. Hetzner-Storage-Box-Snapshots als Ransomware-/Fehlbedienungsschutz aktivieren
|
||||
- **Beobachtung:** Borg `append-only` wurde am 2026-06-01 bewusst verworfen (forced-command brach Key-Auth). Damit kann jeder mit dem Borg-Key (Host, borg-ui-Container mit `/local/secrets`-Mount) Archive **löschen** — ein kompromittierter Host vernichtet auch das Off-site-Backup.
|
||||
- **Warum relevant:** Das ist die einzige verbliebene Lücke in einer sonst sehr guten Backup-Kette.
|
||||
- **Änderung:** In der Hetzner-Robot-Konsole automatische Snapshots der Storage Box aktivieren (z. B. täglich, 7–14 Tage Retention). Snapshots sind host-seitig nicht löschbar und im Storage-Box-Preis enthalten.
|
||||
- **Verifikation:** Robot-Konsole zeigt Snapshot-Liste; nach 2 Tagen: zwei Snapshots vorhanden. Restore-Probe: einzelne Datei aus Snapshot über das Snapshot-Verzeichnis lesen.
|
||||
- **Rollback:** Snapshots deaktivieren — rein additiv, keine Auswirkung auf Borg.
|
||||
- **Nebenwirkungen:** Snapshots zählen ggf. anteilig aufs Quota (aktuell 65 GB / 1 TB — viel Luft). | Nutzen: **sehr hoch** | Risiko: niedrig | Aufwand: klein (<30 min) | sofort
|
||||
|
||||
### 3. DNS-Fallback gegen den AdGuard-SPOF
|
||||
- **Beobachtung:** AdGuard ist einziger LAN-Resolver. Der dokumentierte Vorfall (Bulk-Deploy: AdGuard-Recreate → Host ohne DNS → Komodo-Pulls scheitern) ist genau dieses Muster; das Runbook behandelt nur das Symptom.
|
||||
- **Warum relevant:** Jeder AdGuard-Ausfall (Update, OOM, Disk) nimmt LAN + Host-DNS gleichzeitig mit — auch die Reparaturfähigkeit (Image-Pulls!) hängt daran.
|
||||
- **Änderung (gestuft):**
|
||||
- a) Host-Ebene: zweiten Nameserver (z. B. `1.1.1.1`) in der Unraid-Netzwerkkonfig als Fallback hinter `192.168.178.58` eintragen. Damit kann der Host immer Images pullen.
|
||||
- b) LAN-Ebene: in der FRITZ!Box als zweiten lokalen DNS die FRITZ!Box selbst (oder einen Public DNS) hinterlegen — bewusster Trade-off: bei AdGuard-Down kein Ad-Blocking statt kein Internet.
|
||||
- **Verifikation:** `docker stop adguard` im Wartungsfenster → `nslookup gitea.com` auf dem Host funktioniert weiterhin; danach `docker start adguard`.
|
||||
- **Rollback:** Nameserver-Eintrag entfernen.
|
||||
- **Nebenwirkungen:** DNS-Anfragen können am Filter vorbeilaufen, solange AdGuard down ist (gewollt); Fallback-Resolver sieht dann Anfragen (Privacy-Abwägung). | Nutzen: **hoch** | Risiko: niedrig | Aufwand: klein | diese Woche
|
||||
|
||||
### 4. Healthchecks für die App-Stacks nachrüsten
|
||||
- **Beobachtung:** Nur 10 von 30 Compose-Dateien definieren Healthchecks (traefik, gitea, vaultwarden, authelia, postgresql17, redis, komodo, bentopdf, glances, hermes). **Ohne:** Nextcloud (App+DB+Redis), Immich (alle 4), Paperless, Mealie, Mail-Archiver, n8n, AdGuard, Unbound und der komplette Monitoring-Stack (11 Services).
|
||||
- **Warum relevant:** Ohne Healthcheck meldet Docker "Up", auch wenn die App hängt; der Critical-Events-Watcher sieht nur `die`/`oom`, keine Hänger. Prometheus-Blackbox prüft nur HTTP-Routen von außen.
|
||||
- **Änderung:** Pro Stack einen minimalen Healthcheck ergänzen, priorisiert: Nextcloud (`curl -f http://localhost/status.php`), Paperless, Mealie, n8n, Unbound (`drill @127.0.0.1 cloudflare.com` bzw. `unbound-control status`), AdGuard. Stackweise deployen, nicht als Bulk (siehe DNS-Runbook!).
|
||||
- **Verifikation:** `docker ps --format '{{.Names}} {{.Status}}'` zeigt `(healthy)`; cAdvisor/Glance zeigen Health-Status.
|
||||
- **Rollback:** Healthcheck-Block entfernen, Redeploy — kein Datenrisiko.
|
||||
- **Nebenwirkungen:** Falsch kalibrierte Checks (zu kurze `start_period`) können Flapping erzeugen; konservativ starten (`interval: 60s`, `retries: 5`). | Nutzen: **hoch** | Risiko: niedrig | Aufwand: mittel | diesen Monat
|
||||
|
||||
### 5. Memory-Limits für die größten Verbraucher
|
||||
- **Beobachtung:** Kein einziger Service hat `mem_limit`/`deploy.resources`. Auf einem Ein-Host-System konkurrieren ~50 Container; ein Speicherleck (Immich-ML, Nextcloud-PHP, Loki) kann den Host-OOM-Killer auslösen, der dann beliebige Tier-1-Container trifft (Postgres!).
|
||||
- **Warum relevant:** Der OOM-Killer wählt nach Score, nicht nach Wichtigkeit. Limits machen den Blast-Radius deterministisch: die fehlerhafte App stirbt, nicht die Datenbank.
|
||||
- **Änderung:** Erst messen: `docker stats --no-stream --format '{{.Name}}\t{{.MemUsage}}'` über ein paar Tage (oder cAdvisor-Dashboard `container_memory_working_set_bytes`). Dann Limits = Peak × 1,5 für die Top-5-Verbraucher (typisch: immich-ml, nextcloud, paperless, plex, prometheus) setzen.
|
||||
- **Verifikation:** `docker inspect <c> --format '{{.HostConfig.Memory}}'`; Grafana-Panel Memory vs. Limit; keine neuen `oom`-Events im Critical-Events-Log.
|
||||
- **Rollback:** Limit-Zeilen entfernen, Redeploy.
|
||||
- **Nebenwirkungen:** Zu knappe Limits OOM-killen die App selbst — deshalb messen statt raten, und Limits nur bei unkritischen Apps zuerst. | Nutzen: **hoch** | Risiko: mittel | Aufwand: mittel | diesen Monat
|
||||
|
||||
### 6. `no-new-privileges` flächendeckend gemäß P8
|
||||
- **Beobachtung:** Architektur-Regel P8 verlangt `no-new-privileges:true` standardmäßig; gesetzt ist es nur in 10 von 30 Stacks. Es fehlt u. a. bei allen Apps mit WAN-Exposition (Nextcloud, Immich, Paperless, Mealie, ntfy, n8n).
|
||||
- **Warum relevant:** Billige Defense-in-Depth gegen Privilege-Escalation nach App-Kompromittierung — genau bei den exponierten Diensten am wertvollsten. Aktuell: dokumentierte Regel ≠ gelebter Stand (Policy-Drift).
|
||||
- **Änderung:** `security_opt: ["no-new-privileges:true"]` in die fehlenden Stacks, stackweise mit Smoke-Test. Vorsicht bei Images mit s6/sudo-Setup (LSIO-Images wie speedtest/code-server haben es teils schon — prüfen) und bei Plex (Host-Netz, zuerst testen).
|
||||
- **Verifikation:** `docker inspect <c> --format '{{.HostConfig.SecurityOpt}}'`; Posture-/Policy-Check erweitern, damit Drift künftig alarmiert.
|
||||
- **Rollback:** Zeile entfernen, Redeploy.
|
||||
- **Nebenwirkungen:** Container, die intern setuid brauchen (selten: einige Init-Systeme), starten nicht — fällt im Smoke-Test sofort auf. | Nutzen: mittel | Risiko: niedrig | Aufwand: mittel | diesen Monat
|
||||
|
||||
### 7. traefik/dynamic-Sync automatisieren statt manuell
|
||||
- **Beobachtung:** `traefik/dynamic/*` (middlewares, tls, dashboards, plex) wird laut dokumentierter Ausnahme **manuell** auf den Host synchronisiert. Das ist die klassische Quelle für "Repo sagt A, Host macht B" — besonders heikel, weil hier Auth-Middlewares definiert sind.
|
||||
- **Warum relevant:** Ein vergessener Sync nach einer Middleware-Änderung kann unbemerkt eine Schutzschicht im Live-Zustand alt lassen; auffallen würde es erst beim Audit.
|
||||
- **Änderung:** Kleines Sync-Skript analog `services/authelia-diff.sh`: Repo-Spiegel `/mnt/user/services/homelab-infra/traefik/dynamic/` per `rsync --checksum --dry-run` gegen `/mnt/user/appdata/traefik/dynamic/` diffen; Diff ≠ leer → ntfy-Warnung über den bestehenden Posture-Check. (Stufe 2 optional: automatisch syncen; erst nur alarmieren.)
|
||||
- **Verifikation:** Testweise eine Whitespace-Änderung im Repo-Spiegel → Posture-Check meldet `traefik_dynamic_drift`.
|
||||
- **Rollback:** Check aus dem Posture-Skript entfernen; rein lesend, kein Produktionsrisiko.
|
||||
- **Nebenwirkungen:** keine (read-only Check). | Nutzen: mittel | Risiko: niedrig | Aufwand: klein | diese Woche
|
||||
|
||||
### 8. Watchdog für den Monitoring-Stack selbst (Dead-Man's-Switch)
|
||||
- **Beobachtung:** Die Alert-Kette ist Prometheus → Alertmanager → Bridge → ntfy. Fällt ein Glied (oder der ganze Monitoring-Stack) aus, kommen schlicht **keine** Alerts mehr — Stille ist nicht von "alles gut" unterscheidbar. Kein Healthcheck im Monitoring-Compose.
|
||||
- **Warum relevant:** Das Monitoring überwacht alles außer sich selbst.
|
||||
- **Änderung:** Dauerhaft feuernde `Watchdog`-Alert-Rule in `monitoring/prometheus/alerts.yml` + externen Heartbeat-Empfänger: einfachste Variante ist healthchecks.io (free) — Alertmanager-Route schickt den Watchdog alle 5 min an die Heartbeat-URL; bleibt er aus, alarmiert healthchecks.io per Mail/Push von außen.
|
||||
- **Verifikation:** `docker stop monitoring-prometheus` im Wartungsfenster → externe Benachrichtigung nach ~10 min; danach Start.
|
||||
- **Rollback:** Rule + Route entfernen.
|
||||
- **Nebenwirkungen:** neue (kleine) externe Abhängigkeit — in `docs/EXTERNAL_DEPENDENCIES.md` eintragen. | Nutzen: **hoch** | Risiko: niedrig | Aufwand: klein | diese Woche
|
||||
|
||||
### 9. Lokale Arbeitskopie sauber halten (GitOps-Hygiene)
|
||||
- **Beobachtung:** Die lokale Arbeitskopie hat aktuell 6 modifizierte Dateien und 2 untracked Artefakte (u. a. `docs/KalliLab_CORE_Audit_2026-06-06.pdf`, `ops/h-drive-nearline/README.md`), die nicht committed sind. Bei "Gitea = Quelle der Wahrheit" ist eine dauerhaft schmutzige Arbeitskopie ein Drift-Risiko (Änderungen gehen bei Pull-Konflikten verloren oder landen versehentlich in fremden Commits).
|
||||
- **Warum relevant:** Genau die Drift-Klasse, vor der `docs/GITOPS_DRIFT_RUNBOOK.md` warnt — nur auf Ebene 2 (lokaler Clone) statt Ebene 4.
|
||||
- **Änderung:** Modifizierte Doku-Dateien reviewen und committen oder verwerfen; PDF entweder committen (wenn es Referenz ist) oder in `.gitignore`/außerhalb des Repos ablegen; `ops/h-drive-nearline/README.md` committen.
|
||||
- **Verifikation:** `git status` zeigt clean tree (bis auf bewusste Arbeit).
|
||||
- **Rollback:** n/a (Aufräumarbeit). | Nutzen: mittel | Risiko: niedrig | Aufwand: klein (<30 min) | sofort
|
||||
|
||||
### 10. Doku-Drift-Fixes (klein, aber Vertrauensbasis)
|
||||
- **Beobachtung:** `HOMELAB_ARCHITECTURE_MASTER_V2.md` nennt "Redis-Caches auf `redis:7.4-alpine` vereinheitlicht" — real laufen alle auf `redis:8.8.0-alpine`. Ebenso "PostgreSQL 17"-Pfade/Servicenamen bei PG 18 (letzteres ist dokumentiert bewusst, ersteres nicht).
|
||||
- **Warum relevant:** Das Masterdokument ist laut eigener Regel die erste Lesepflicht für jeden (auch KI-)Eingriff; veraltete Fakten dort erzeugen falsche Entscheidungen.
|
||||
- **Änderung:** Redis-Abschnitt in Sektion 13 auf 8.8 aktualisieren; bei Gelegenheit einen Mini-Check ins Posture-/Audit-Ritual: "stimmen Versionsangaben im Master noch?"
|
||||
- **Verifikation:** `grep -n "7.4-alpine" HOMELAB_ARCHITECTURE_MASTER_V2.md` → leer.
|
||||
- **Rollback:** trivial (Doku). | Nutzen: niedrig–mittel | Risiko: keiner | Aufwand: klein | sofort
|
||||
|
||||
## Top 5 Risiken (zuerst entschärfen)
|
||||
|
||||
1. **Löschbare Off-site-Backups** — Host-Kompromittierung oder ein falscher `borg delete` vernichtet auch Hetzner. → Empfehlung 2 (Snapshots). Bis dahin ist das DR-Konzept gegen Ransomware unvollständig.
|
||||
2. **DNS-SPOF AdGuard** — bereits einmal real eingetreten (Teil-Deploy 2026-06); betrifft auch die Selbstheilungsfähigkeit (Image-Pulls). → Empfehlung 3.
|
||||
3. **Verdeckte Versionssprünge via `release`/`latest`-Digest-Bumps** — v. a. Immich (DB-Migrationen!). → Empfehlung 1.
|
||||
4. **OOM-Kaskade ohne Limits** — ein Leck in einer Tier-3-App kann Postgres killen. → Empfehlung 5. (Der Critical-Events-Watcher meldet das nur, verhindert es nicht.)
|
||||
5. **Blinde Alert-Kette** — Monitoring-Ausfall = Stille statt Alarm. → Empfehlung 8.
|
||||
|
||||
Bewusst akzeptierte Risiken (USV geparkt, ein Host, kein WAN-Failover, kein
|
||||
zweites Off-site-Ziel) sind dokumentiert und werden hier nicht erneut
|
||||
aufgemacht — die Entscheidungen sind nachvollziehbar.
|
||||
|
||||
## Quick Wins unter 30 Minuten
|
||||
|
||||
| Quick Win | Wirkung | Kommando/Weg |
|
||||
|---|---|---|
|
||||
| Hetzner-Snapshots aktivieren | Backup-Löschschutz | Robot-Konsole → Storage Box → Snapshots (Empf. 2) |
|
||||
| Host-DNS-Fallback eintragen | Selbstheilung bei AdGuard-Down | Unraid Settings → Network → DNS 2 = `1.1.1.1` (Empf. 3a) |
|
||||
| Arbeitskopie aufräumen | GitOps-Hygiene | `git status`, committen/verwerfen (Empf. 9) |
|
||||
| Redis-Doku-Drift fixen | Master-Doku wieder korrekt | Sektion 13 editieren (Empf. 10) |
|
||||
| Memory-Baseline ziehen | Grundlage für Limits | `docker stats --no-stream` auf dem Host, Output archivieren |
|
||||
| Watchdog-Rule anlegen | Vorbereitung Dead-Man's-Switch | `alerts.yml` + healthchecks.io-Account (Empf. 8) |
|
||||
|
||||
## 30-Tage-Optimierungsplan
|
||||
|
||||
**Woche 1 — Risiko-Entschärfung (alles klein):**
|
||||
Hetzner-Snapshots (Empf. 2) · Host-DNS-Fallback + Stop/Start-Test (Empf. 3a) ·
|
||||
Immich-Tag-Pinning (Empf. 1) · Arbeitskopie aufräumen (Empf. 9) ·
|
||||
Memory-Baseline starten.
|
||||
|
||||
**Woche 2 — Beobachtbarkeit:**
|
||||
Dead-Man's-Switch produktiv (Empf. 8) · traefik/dynamic-Drift-Check in den
|
||||
Posture-Check (Empf. 7) · Healthchecks für Nextcloud, Paperless, Mealie, n8n
|
||||
(Empf. 4, stackweise).
|
||||
|
||||
**Woche 3 — Hardening:**
|
||||
`no-new-privileges` für alle WAN-exponierten Apps (Empf. 6) · Healthchecks
|
||||
für AdGuard/Unbound/Monitoring-Kern · restliche Mutable-Tag-Kandidaten pinnen
|
||||
(komodo, scrutiny, glances, ddns-updater, tag-lose digest-only Images).
|
||||
|
||||
**Woche 4 — Stabilität:**
|
||||
Memory-Limits aus der Baseline für die Top-5-Verbraucher (Empf. 5) ·
|
||||
FRITZ!Box-DNS-Fallback-Entscheidung (Empf. 3b) · Doku nachziehen
|
||||
(Master Sektion 13, SERVICE_CATALOG, dieses Dokument abhaken).
|
||||
|
||||
## Größere Projekte mit hohem Nutzen (später)
|
||||
|
||||
- **End-to-end-DR-Drill** sobald zweite Hardware existiert (bereits geplant,
|
||||
bleibt der wertvollste offene Beweis).
|
||||
- **Strom-/Kostentransparenz:** smarte Steckdose mit Messfunktion (z. B.
|
||||
Shelly Plug S) vor den Unraid-Host, Werte via Home Assistant → InfluxDB 3 →
|
||||
Grafana. Erst messen, dann ggf. optimieren (Spindown-Policy, CPU-Governor).
|
||||
Messbarkeit: W-Dauerlast und kWh/Monat als Grafana-Panel.
|
||||
- **USV-Review Q3/2026** wie geparkt — nach Strommessung lässt sich die
|
||||
USV-Dimensionierung direkt ableiten.
|
||||
- **Renovate-Policy verfeinern:** Digest-PRs für mutable Tags entweder
|
||||
abschalten oder mit Warn-Label versehen, damit Befund 1 strukturell nicht
|
||||
zurückkommt.
|
||||
|
||||
## Konkrete Verifikationskommandos (Sammlung, alle read-only)
|
||||
|
||||
```bash
|
||||
# Health-Status aller Container
|
||||
docker ps --format '{{.Names}}\t{{.Status}}' | sort
|
||||
|
||||
# Memory-Baseline
|
||||
docker stats --no-stream --format '{{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}' | sort -k3 -hr | head -15
|
||||
|
||||
# Welche Container ohne no-new-privileges laufen
|
||||
docker ps -q | xargs docker inspect --format '{{.Name}} {{.HostConfig.SecurityOpt}}' | grep -v no-new-privileges
|
||||
|
||||
# Effektive Image-Referenzen (mutable Tags erkennen)
|
||||
docker ps --format '{{.Names}}\t{{.Image}}' | grep -E 'latest|release|:2$|:[0-9]+$'
|
||||
|
||||
# DNS-Fallback-Test (Wartungsfenster!)
|
||||
docker stop adguard && nslookup gitea.com && docker start adguard
|
||||
|
||||
# Borg-Snapshot-Gegenprobe (nach Aktivierung, von der Storage Box)
|
||||
ssh -p 23 u565255@u565255.your-storagebox.de ls .snapshots/ 2>/dev/null || echo "via Robot-Konsole prüfen"
|
||||
```
|
||||
|
||||
## Rollback-Hinweise (generell)
|
||||
|
||||
- Jede Compose-Änderung: Revert-Commit nach Gitea pushen → Komodo deployed
|
||||
den Vorzustand; Datenpfade bleiben unberührt (alle Empfehlungen hier sind
|
||||
config-only, keine Daten-/Volume-Migrationen).
|
||||
- Healthchecks/Limits/security_opt: Zeilen entfernen + Redeploy genügt.
|
||||
- Host-DNS/FRITZ!Box-Einträge: Eintrag löschen, sofort wirksam.
|
||||
- Hetzner-Snapshots und Dead-Man's-Switch sind rein additiv.
|
||||
- Nichts in diesem Dokument erfordert `push --force`, History-Rewrite oder
|
||||
Löschoperationen auf Datenpfaden.
|
||||
|
||||
## Offene Fragen an den Operator
|
||||
|
||||
1. **Strom:** Gibt es eine Messung des Host-Verbrauchs (W idle/last)? Ohne
|
||||
Zahl ist der Bereich Kosten/Strom nicht bewertbar. → Shelly/Messsteckdose?
|
||||
2. **RAM-Ausstattung des Hosts:** Wie viel RAM hat Kallilabcore gesamt und
|
||||
wie ist die aktuelle Auslastung (`free -h`)? Bestimmt, wie aggressiv
|
||||
Memory-Limits sinnvoll sind.
|
||||
3. **Renovate-Verhalten gewollt?** Sollen Digest-Bumps auf `release`/`latest`
|
||||
weiter automatisch als PRs kommen, oder ist die Pinning-Strategie aus
|
||||
Empfehlung 1 die gewünschte Linie für alle Stacks?
|
||||
4. **healthchecks.io o. ä. als externe Abhängigkeit akzeptabel?** Alternativ
|
||||
ginge ein ntfy-basierter Heartbeat von einem zweiten Gerät (z. B. dem
|
||||
Gaming-PC per Scheduled Task) — null neue Cloud-Abhängigkeit.
|
||||
5. **FRITZ!Box-DNS-Fallback (3b):** Filterlücke bei AdGuard-Down akzeptieren
|
||||
oder lieber nur den Host-Fallback (3a) umsetzen?
|
||||
+2
-1
@@ -82,7 +82,7 @@ Wichtige Dateien:
|
||||
H:\Windows-Neuaufsetzen-Backup\12_Exportierte_Listen\installierte_programme_lesbar.md
|
||||
H:\Windows-Neuaufsetzen-Backup\12_Exportierte_Listen\kritische_programme_lizenz_check.md
|
||||
H:\Windows-Neuaufsetzen-Backup\09_Programme_Settings_Lizenzen\keys_exporte\banking4_license_private.txt
|
||||
G:\Gitea_Clone\homelab-infra\ops\windows-reinstall\docs\windows-neuaufsetzen-masterplan.md
|
||||
G:\Gitea_Clone\homelab-infra\docs\windows-neuaufsetzen-masterplan.md
|
||||
```
|
||||
|
||||
Dann Codex/ChatGPT sagen:
|
||||
@@ -100,3 +100,4 @@ Reihenfolge:
|
||||
3. Microsoft 365 ueber Microsoft-Konto installieren.
|
||||
4. WISO Steuer installieren und Steuerdateien aus `WISO_Steuer_Dokumente` pruefen.
|
||||
5. Restliche Programme mit UniGetUI/WinGet/Installern wieder aufbauen.
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
# Runbook: Komodo Bulk-Deploy schlaegt mit DNS `connection refused` fehl
|
||||
|
||||
Stand: 2026-06-11 · Typ: Runbook / ADR-light · Status: **Sofortmassnahme aktiv** (Host-DNS-Fallback gesetzt 2026-06-11 bzw. frueher)
|
||||
|
||||
## Symptom
|
||||
|
||||
Ein Bulk-Merge (z. B. Renovate-Sammel-PR) loest gleichzeitig viele Komodo-Stack-Webhooks aus. Komodo startet parallele `DeployStack`. Nur ein Teil der Stacks deployt, der Rest bleibt auf dem alten Image. In der Deploy-Stufe **Compose Pull** stehen Fehler wie:
|
||||
|
||||
```
|
||||
Get "https://registry-1.docker.io/v2/": dial tcp: lookup registry-1.docker.io
|
||||
on 192.168.178.58:53: read udp ...->192.168.178.58:53: read: connection refused
|
||||
```
|
||||
|
||||
Manuelles Re-Deploy der betroffenen Stacks danach funktioniert (AdGuard ist dann wieder oben).
|
||||
|
||||
## Ursache
|
||||
|
||||
Der Host nutzt **AdGuard Home als einzigen Resolver** (`/etc/resolv.conf` = nur `nameserver 192.168.178.58`, keine `/etc/docker/daemon.json`). AdGuard laeuft selbst als Container auf dem Host und bindet `0.0.0.0:53`. Wird der `adguard`-Stack im selben Batch neu deployt, faellt Port 53 fuer Sekunden aus. Alle parallelen `docker compose pull` der anderen Stacks koennen `registry-1.docker.io` dann nicht aufloesen -> `connection refused` -> Deploy `success=false`.
|
||||
|
||||
Es ist **kein** Webhook-, Auth- oder Docker-Hub-Rate-Limit-Problem: Webhooks authentifizieren sauber, `webhook_enabled=true`, Fehlerbild ist `connection refused` auf den eigenen DNS-Port direkt nach AdGuard-Recreate. Fuer den Pull-Pfad zaehlt der Docker-Daemon/Go-Resolver (iteriert ueber die `resolv.conf`-Server und springt bei Socket-Fehlern zum naechsten), nicht der glibc-Client.
|
||||
|
||||
## Sofortmassnahme (Schicht 1) — umgesetzt
|
||||
|
||||
Unraid -> Settings -> Network Settings -> `eth0`:
|
||||
|
||||
- DNS server 1: `192.168.178.58` (AdGuard)
|
||||
- **DNS server 2: `192.168.178.1`** (FritzBox) — **gesetzt und aktiv** (Operator-Bestaetigung 2026-06-11; Apply-Button erfordert Docker-/VM-Stop, der gespeicherte Wert greift bereits ohne Re-Apply)
|
||||
|
||||
Damit ueberleben Registry-Pulls einen kurzen AdGuard-Ausfall via Resolver-Failover. Im Normalbetrieb wird weiter DNS1 (AdGuard) genutzt, der Filter bleibt aktiv.
|
||||
|
||||
Pruefen / Bedingungen:
|
||||
|
||||
- **Kein `options rotate`** in `/etc/resolv.conf` (sonst dauerhafter Filter-Bypass). Aktuell nicht gesetzt; nach Apply erneut pruefen.
|
||||
- Router muss oeffentliche Namen **selbst** aufloesen und nicht intern an AdGuard zurueckleiten.
|
||||
- Hinweis zur Verifikation: Ein `nslookup registry-1.docker.io 192.168.178.1` bei laufendem AdGuard ist ein gutes Signal, aber **kein letzter Beweis**. Wasserdicht: AdGuard kurz stoppen und `dig @192.168.178.1 registry-1.docker.io`, oder FritzBox-Upstream / AdGuard-Querylog pruefen.
|
||||
|
||||
Rollback: DNS server 2 leeren + Apply.
|
||||
|
||||
## Betriebsregel (Schicht 2)
|
||||
|
||||
- **AdGuard und Unbound nicht gemeinsam mit abhaengigen Stacks im Bulk deployen.** DNS-Infrastruktur immer separat / einzeln deployen, nicht waehrend 20+ parallele Pulls laufen.
|
||||
- Renovate-PRs gestaffelt mergen (eine Etappe pro Deploy) statt Sammel-Merge. Deckt dieses Problem fuer den Normalbetrieb bereits ab.
|
||||
|
||||
## Spaeter optional
|
||||
|
||||
- Komodo-Deploys serialisieren: statt vieler paralleler Stack-Webhooks eine **Procedure** (sequenzielle Stages) oder **Resource Sync** mit `after`-Ordering. Trifft die Ursache direkter, ist aber ein groesserer Umbau und **kein Renovate-Blocker**.
|
||||
- Host-DNS vom AdGuard-Container entkoppeln (AdGuard eigene IP via macvlan, Host-Resolver auf Router/Unbound), damit `:53` am Host nicht exklusiv am Container-Lifecycle haengt.
|
||||
|
||||
## Verworfen
|
||||
|
||||
- `/etc/docker/daemon.json` mit `"dns": [...]`: wirkt nur fuer Container-DNS, nicht fuer Daemon-eigene Image-Pulls.
|
||||
- AdGuard `network_mode: host`: beim Recreate ist der DNS-Prozess trotzdem weg; macht aus dem Single Point of Failure keinen HA-Resolver.
|
||||
|
||||
## Referenzen
|
||||
|
||||
- Diagnose-Zugriff: SSH `root@192.168.178.58`; Komodo-Mongo (`docker exec komodo-mongo`, DB `komodo`, Collections `Stack`/`Update`); Gitea SQLite `/data/gitea/gitea.db` (Tabelle `webhook`, `repo_id=3`).
|
||||
- Verwandt: `docs/WORKFLOW.md` (DNS-Regeln fuer Container), `docs/GITOPS_DRIFT_RUNBOOK.md`.
|
||||
</content>
|
||||
@@ -1,107 +0,0 @@
|
||||
# Smart-Home Bootstrap
|
||||
|
||||
Ziel: Den Stack `smart-home/` auf Kallilabcore initial startklar machen, ohne
|
||||
Secrets oder UI-State ins Git zu schreiben.
|
||||
|
||||
## 1. Fachrepo auf dem Host bereitstellen
|
||||
|
||||
```sh
|
||||
cd /mnt/user/services
|
||||
git clone https://git.kaleschke.info/Micha/smart-home-kalli.git smart-home-kalli
|
||||
cd smart-home-kalli
|
||||
git checkout main
|
||||
```
|
||||
|
||||
Der Home-Assistant-Container mountet daraus einzelne YAML-Dateien read-only nach
|
||||
`/config`.
|
||||
|
||||
## 2. Home-Assistant-Appdata vorbereiten
|
||||
|
||||
```sh
|
||||
mkdir -p /mnt/user/appdata/homeassistant
|
||||
cp /mnt/user/services/smart-home-kalli/secrets-template/secrets.yaml.example \
|
||||
/mnt/user/appdata/homeassistant/secrets.yaml
|
||||
cp /mnt/user/services/smart-home-kalli/secrets-template/trusted_proxies.yaml.example \
|
||||
/mnt/user/appdata/homeassistant/trusted_proxies.yaml
|
||||
```
|
||||
|
||||
Danach `trusted_proxies.yaml` auf das echte Traefik-/`frontend_net`-Subnetz
|
||||
anpassen:
|
||||
|
||||
```sh
|
||||
docker network inspect frontend_net
|
||||
```
|
||||
|
||||
## 3. Mosquitto vorbereiten
|
||||
|
||||
```sh
|
||||
mkdir -p /mnt/user/appdata/mosquitto/config \
|
||||
/mnt/user/appdata/mosquitto/data \
|
||||
/mnt/user/appdata/mosquitto/log
|
||||
|
||||
docker run --rm -it \
|
||||
-v /mnt/user/appdata/mosquitto/config:/mosquitto/external_config \
|
||||
eclipse-mosquitto:2.0.22 \
|
||||
mosquitto_passwd -c /mosquitto/external_config/passwordfile homeassistant
|
||||
|
||||
cat > /mnt/user/appdata/mosquitto/config/aclfile <<'EOF'
|
||||
user homeassistant
|
||||
topic readwrite #
|
||||
EOF
|
||||
```
|
||||
|
||||
Das initiale Passwort anschliessend in
|
||||
`/mnt/user/appdata/homeassistant/secrets.yaml` eintragen. LAN-Port `1883` bleibt
|
||||
in Phase 1 geschlossen.
|
||||
|
||||
## 4. Stack deployen
|
||||
|
||||
Komodo-Stack:
|
||||
|
||||
- Repo: `homelab-infra`
|
||||
- Pfad: `smart-home/docker-compose.yml`
|
||||
- Branch: nach Review `master`
|
||||
|
||||
Nach dem Start pruefen:
|
||||
|
||||
```sh
|
||||
docker ps --filter name=homeassistant
|
||||
docker ps --filter name=smarthome-mosquitto
|
||||
docker logs --tail=100 homeassistant
|
||||
docker logs --tail=100 smarthome-mosquitto
|
||||
```
|
||||
|
||||
## 5. Smoke-Test
|
||||
|
||||
- `https://home.kaleschke.info` zeigt die Home-Assistant-Oberflaeche.
|
||||
- Keine Trusted-Proxy-Fehler im HA-Log.
|
||||
- MQTT-Integration verbindet sich mit Host `smarthome-mosquitto`, Port `1883`.
|
||||
- HA-native Backup-Erstellung funktioniert.
|
||||
|
||||
## 6. Fachrepo-Update
|
||||
|
||||
Das Fachrepo `/mnt/user/services/smart-home-kalli` ist kein eigener
|
||||
Komodo-Stack. Aenderungen wirken erst nach diesem Host-Ablauf:
|
||||
|
||||
```sh
|
||||
cd /mnt/user/services/smart-home-kalli
|
||||
git pull --ff-only origin main
|
||||
docker restart homeassistant
|
||||
```
|
||||
|
||||
Der Restart ist Pflicht, weil `configuration.yaml`, `automations.yaml`,
|
||||
`scripts.yaml` und `scenes.yaml` als Einzeldateien in den Container gemountet
|
||||
werden. Nach einem `git pull` kann Docker sonst noch den alten Datei-Inode sehen.
|
||||
|
||||
## 7. UI-Editor-Politik
|
||||
|
||||
`automations.yaml`, `scripts.yaml` und `scenes.yaml` sind read-only aus Git
|
||||
gemountet. Der Home-Assistant-UI-Editor fuer diese Dateien ist deshalb nicht der
|
||||
primaere Schreibweg. Automationen und Scripts werden in Git gepflegt; UI-State
|
||||
und Integrations-State bleiben in `.storage` und werden per Borg gesichert.
|
||||
|
||||
## 8. Abnahmebedingung
|
||||
|
||||
Vor produktiven Energie-Automationen muss ein Restore-Test fuer
|
||||
`/mnt/user/appdata/homeassistant`, `/mnt/user/appdata/mosquitto` und den Clone
|
||||
`/mnt/user/services/smart-home-kalli` dokumentiert sein.
|
||||
+10
-24
@@ -43,20 +43,12 @@ Erledigt:
|
||||
Noch offen:
|
||||
|
||||
- Manuelle Screenshots in `H:\Windows-Neuaufsetzen-Backup\14_Screenshots` ablegen.
|
||||
- BitLocker-Status mit Adminrechten pruefen. **Nachlauf 2026-06-05:** Status
|
||||
wurde geprueft; C:/D:/E:/G:/H: sind `FullyDecrypted`, Protection `Off`.
|
||||
**Entscheidung 2026-06-06:** BitLocker bleibt bewusst deaktiviert; Recovery
|
||||
laeuft ueber Veeam-Image, kein BitLocker-Key-Management.
|
||||
- Passwortmanager, 2FA-Recovery-Codes und Browser-Sync manuell pruefen. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
||||
- Banking4-Speicherort explizit pruefen. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
||||
- Banking4 im Programm selbst oeffnen und aktuellen Datentresor/Backup-Export bestaetigen. Der Key und der Datentresor sind bereits lokal auf H: gesichert. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
||||
- WISO Steuer 2026 oeffnen und Lizenz/Buhl-Konto sowie Speicherorte der Steuerdateien bestaetigen. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
||||
- Microsoft-Konto fuer M365 pruefen: Office-Webkonto/Abonnement, Installationsrecht, OneDrive-Sync. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
||||
- Technisches Nachinstallations-Inventar 2026-06-06 erledigt:
|
||||
`baerchen-app-license-readiness-2026-06-06.md`. Banking4, WISO Steuer
|
||||
2026, Microsoft 365/OneDrive und relevante Datenpfade sind lokal sichtbar;
|
||||
Konto-/App-Oeffnen-Checks wurden am 2026-06-06 durch den Operator
|
||||
bestaetigt ("alle Dienste laufen").
|
||||
- BitLocker-Status mit Adminrechten pruefen.
|
||||
- Passwortmanager, 2FA-Recovery-Codes und Browser-Sync manuell pruefen.
|
||||
- Banking4-Speicherort explizit pruefen.
|
||||
- Banking4 im Programm selbst oeffnen und aktuellen Datentresor/Backup-Export bestaetigen. Der Key und der Datentresor sind bereits lokal auf H: gesichert.
|
||||
- WISO Steuer 2026 oeffnen und Lizenz/Buhl-Konto sowie Speicherorte der Steuerdateien bestaetigen.
|
||||
- Microsoft-Konto fuer M365 pruefen: Office-Webkonto/Abonnement, Installationsrecht, OneDrive-Sync.
|
||||
- Optional Keyfinder-Lauf durchfuehren und Ergebnisse lokal auf H: speichern.
|
||||
- `G:\Ollama` bewusst entscheiden: nicht gesichert, ca. 40,9 GB lokale Modell-/Cache-Daten.
|
||||
- D:, F: und G: vor dem spaeteren Loeschen noch einmal in Ruhe final bestaetigen.
|
||||
@@ -470,7 +462,7 @@ Direkt nach der Installation:
|
||||
- Windows-Aktivierung prüfen
|
||||
- Laufwerksbuchstaben sauber vergeben
|
||||
- Windows Defender und Firewall prüfen
|
||||
- BitLocker bewusst deaktiviert lassen (Entscheidung 2026-06-06)
|
||||
- BitLocker bewusst aktivieren oder deaktiviert lassen
|
||||
- Wiederherstellungspunkt erstellen
|
||||
|
||||
Basisprogramme:
|
||||
@@ -536,22 +528,16 @@ Zielstruktur:
|
||||
|
||||
## Finale Checkliste vor dem Löschen
|
||||
|
||||
Status 2026-06-05: Diese Checkliste ist historisch fuer die Freigabe der
|
||||
Neuinstallation. Die technische Neuinstallation, Laufwerksbereinigung,
|
||||
WinRE-Pruefung und Veeam-Baseline sind in neueren Dokumenten nachgezogen.
|
||||
Status 2026-06-06: Passwortmanager/2FA, Banking4, WISO und Microsoft/M365
|
||||
wurden durch den Operator bestaetigt ("alle Dienste laufen").
|
||||
|
||||
- [ ] Backup-Struktur auf H: erstellt
|
||||
- [ ] Programmliste exportiert
|
||||
- [ ] Laufwerksliste exportiert
|
||||
- [ ] Windows-Aktivierung dokumentiert
|
||||
- [ ] Benutzerordner gesichert
|
||||
- [ ] Browser-Lesezeichen exportiert oder Sync geprüft
|
||||
- [x] Passwortmanager geprüft
|
||||
- [x] 2FA-Recovery-Codes gesichert
|
||||
- [ ] Passwortmanager geprüft
|
||||
- [ ] 2FA-Recovery-Codes gesichert
|
||||
- [ ] SSH/API/GPG/Zertifikate gesichert
|
||||
- [x] Banking4-Speicherort geprüft und gesichert
|
||||
- [ ] Banking4-Speicherort geprüft und gesichert
|
||||
- [ ] Homelab-/NAS-Doku gesichert
|
||||
- [ ] D:, F: und G: analysiert
|
||||
- [ ] Unklare Daten nach `99_Unsortiert_von_D_F_G` kopiert
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
adguard:
|
||||
image: adguard/adguardhome:v0.107.77@sha256:e6f2b8bcda06064ab055b44933a4f0e983c35558b9cdb8d2e7ab1efcee36d890
|
||||
image: adguard/adguardhome:v0.107.52@sha256:d16cc7517ab96f843e7f8bf8826402dba98f5e6b175858920296243332391589
|
||||
container_name: adguard
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
services:
|
||||
tailscale:
|
||||
image: tailscale/tailscale:stable@sha256:dbeff02d2337344b351afac203427218c4d0a06c43fc10a865184063498472a6
|
||||
container_name: Tailscale-Docker
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- NET_RAW
|
||||
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
|
||||
environment:
|
||||
- TZ=Europe/Berlin
|
||||
- TS_HOSTNAME=kallilab-core
|
||||
- TS_STATE_DIR=/state
|
||||
- TS_AUTH_ONCE=true
|
||||
|
||||
volumes:
|
||||
- /mnt/user/appdata/tailscale:/state
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
ddns-updater:
|
||||
image: ghcr.io/qdm12/ddns-updater:latest@sha256:9313e1c31f366c89dc0819e5eff85576cb23821424c0c267fa66cfa39aabde83
|
||||
image: ghcr.io/qdm12/ddns-updater:latest@sha256:ee16ab4f6203bf9e5b0925d38a0b4ebf2d9f23771f933cfb2f5a2dbd5f9a2f88
|
||||
container_name: ddns-updater
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
|
||||
@@ -9,10 +9,10 @@ services:
|
||||
POSTGRES_USER: mailarchiver
|
||||
POSTGRES_DB: mailarchiver
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
|
||||
PGDATA: /var/lib/postgresql/18/docker
|
||||
PGDATA: /var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
- /mnt/user/appdata/postgresql18:/var/lib/postgresql
|
||||
- /mnt/user/appdata/postgresql17:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/secrets/postgres_password.txt:/run/secrets/postgres_password:ro
|
||||
|
||||
networks:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
redis:
|
||||
image: redis:8.8.0-alpine@sha256:09160599abd229764c0fb44cb6be640294e1d360a54b19985ab4843dcf2d90f1
|
||||
image: redis:7.4-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99
|
||||
container_name: Redis
|
||||
restart: unless-stopped
|
||||
command:
|
||||
|
||||
@@ -17,7 +17,7 @@ Zielzustand: ein zentraler Observability-Stack fuer KalliLab CORE.
|
||||
|
||||
Die alten Pfade `ops/loki` und `ops/grafana-influxdb` wurden am 2026-05-26 aus dem aktiven Repo entfernt. Rollback erfolgt bei Bedarf ueber Git-Historie, nicht ueber parallel gepflegte Compose-Verzeichnisse.
|
||||
|
||||
Live-Stand 2026-06-01: die zehn `monitoring-*` Container laufen produktiv, die alten Container `grafana`, `influxdb3-core`, `loki` und `alloy` sind in Docker nicht mehr vorhanden. Uptime Kuma ist durch Blackbox Exporter, Prometheus-Alerts und das Dashboard `Homelab / Availability` abgeloest.
|
||||
Live-Stand 2026-05-25: die zehn `monitoring-*` Container laufen produktiv, die alten Container `grafana`, `influxdb3-core`, `loki` und `alloy` sind in Docker nicht mehr vorhanden. Uptime Kuma ist durch Blackbox Exporter, Prometheus-Alerts und das Dashboard `Homelab / Availability` abgeloest.
|
||||
|
||||
## Secrets
|
||||
|
||||
@@ -72,7 +72,7 @@ INFLUXDB_BIND_IP=192.168.178.58
|
||||
- Dozzle bleibt abgeloest: `Homelab / Containers + Logs` ersetzt Live-Logs und Error-Rate.
|
||||
- Glances erst stoppen, wenn `Homelab / Host Overview` und `Homelab / Containers + Logs` fuer CPU, RAM, Disk, Network, Container-CPU und Container-RAM passen.
|
||||
- Uptime Kuma ist entfernt; `Homelab / Availability`, Blackbox Exporter und Prometheus-Alerts sind der Zielzustand fuer HTTP-Verfuegbarkeit.
|
||||
- Dashboard-Zielbestand: `Homelab / Availability`, `Homelab / Containers + Logs`, `Homelab / Host Overview`, `Homelab / Family Status`, `Traefik Official Standalone Dashboard`.
|
||||
- Dashboard-Zielbestand: `Homelab / Availability`, `Homelab / Containers + Logs`, `Homelab / Host Overview`, `Traefik Official Standalone Dashboard`.
|
||||
|
||||
## Alerting
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
prometheus:
|
||||
image: prom/prometheus:v3.12.0@sha256:69f5241418838263316593f7274a304b095c40bcf22e57272865da91bd60a8ac
|
||||
image: prom/prometheus:v3.7.3@sha256:49214755b6153f90a597adcbff0252cc61069f8ab69ce8411285cd4a560e8038
|
||||
container_name: monitoring-prometheus
|
||||
restart: unless-stopped
|
||||
command:
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
- cadvisor
|
||||
|
||||
alertmanager:
|
||||
image: prom/alertmanager:v0.32.2@sha256:b85533a2eb45865835315810315f6951331b2dbc8c93a6cf9a51e156a006a706
|
||||
image: prom/alertmanager:v0.28.1@sha256:27c475db5fb156cab31d5c18a4251ac7ed567746a2483ff264516437a39b15ba
|
||||
container_name: monitoring-alertmanager
|
||||
restart: unless-stopped
|
||||
command:
|
||||
@@ -42,7 +42,7 @@ services:
|
||||
- no-new-privileges:true
|
||||
|
||||
alertmanager-ntfy-bridge:
|
||||
image: python:3.14-alpine@sha256:5a824eb82cc75361f98611f3cfc5091ea33f10a6ccea4d4ebdabbc523b9a1614
|
||||
image: python:3.13-alpine@sha256:420cd0bf0f3998275875e02ecd5808168cf0843cbb4d3c536432f729247b2acc
|
||||
container_name: monitoring-alertmanager-ntfy-bridge
|
||||
restart: unless-stopped
|
||||
dns:
|
||||
@@ -63,21 +63,18 @@ services:
|
||||
- no-new-privileges:true
|
||||
|
||||
blackbox-exporter:
|
||||
image: prom/blackbox-exporter:v0.28.0@sha256:e753ff9f3fc458d02cca5eddab5a77e1c175eee484a8925ac7d524f04366c2fc
|
||||
image: prom/blackbox-exporter:v0.27.0@sha256:a50c4c0eda297baa1678cd4dc4712a67fdea713b832d43ce7fcc5f9bea05094d
|
||||
container_name: monitoring-blackbox-exporter
|
||||
restart: unless-stopped
|
||||
# Use AdGuard so *.kaleschke.info resolves to the internal Traefik IP.
|
||||
# External resolvers (1.1.1.1/8.8.8.8) return the public WAN IP, which
|
||||
# causes hairpin-NAT timeouts when probing from inside the Docker network.
|
||||
dns:
|
||||
- 172.23.0.3
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
command:
|
||||
- --config.file=/etc/blackbox_exporter/blackbox.yml
|
||||
volumes:
|
||||
- ./blackbox/blackbox.yml:/etc/blackbox_exporter/blackbox.yml:ro
|
||||
networks:
|
||||
- monitoring_net
|
||||
- dns_net
|
||||
expose:
|
||||
- "9115"
|
||||
security_opt:
|
||||
@@ -100,7 +97,7 @@ services:
|
||||
- no-new-privileges:true
|
||||
|
||||
promtail:
|
||||
image: grafana/promtail:3.6.11@sha256:a761cb834cfaeee29745440d4884d6748f0a08d8f68928db1d707018c1dcfbe9
|
||||
image: grafana/promtail:3.6.10@sha256:2a0f5e3e160ee5d549c585f6cc4f4e1c566ff783324a424bd75bc16503fc660e
|
||||
container_name: monitoring-promtail
|
||||
restart: unless-stopped
|
||||
command:
|
||||
@@ -118,9 +115,8 @@ services:
|
||||
- loki
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:13.0.2@sha256:5dad0df181cb644a14e13617b913b261a54f7d4fd4510721dba420929f35bea2
|
||||
image: grafana/grafana:12.4.3@sha256:2e986801428cd689c2358605289c90ab37d2b39e24808874971f54c99bcdc412
|
||||
container_name: monitoring-grafana
|
||||
user: "0"
|
||||
restart: unless-stopped
|
||||
dns:
|
||||
- 1.1.1.1
|
||||
@@ -131,21 +127,6 @@ services:
|
||||
GF_SECURITY_ADMIN_PASSWORD__FILE: /run/secrets/monitoring_grafana_admin_password
|
||||
GF_USERS_ALLOW_SIGN_UP: "false"
|
||||
GF_AUTH_ANONYMOUS_ENABLED: "false"
|
||||
GF_PLUGINS_PREINSTALL_DISABLED: "true"
|
||||
# --- Authelia OIDC SSO (2026-06-06) ---
|
||||
GF_AUTH_GENERIC_OAUTH_ENABLED: "true"
|
||||
GF_AUTH_GENERIC_OAUTH_NAME: Authelia
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_ID: grafana
|
||||
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET__FILE: /run/secrets/grafana_oidc_client_secret
|
||||
GF_AUTH_GENERIC_OAUTH_SCOPES: "openid profile email groups"
|
||||
GF_AUTH_GENERIC_OAUTH_AUTH_URL: https://auth.kaleschke.info/api/oidc/authorization
|
||||
GF_AUTH_GENERIC_OAUTH_TOKEN_URL: https://auth.kaleschke.info/api/oidc/token
|
||||
GF_AUTH_GENERIC_OAUTH_API_URL: https://auth.kaleschke.info/api/oidc/userinfo
|
||||
GF_AUTH_GENERIC_OAUTH_USE_PKCE: "true"
|
||||
GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP: "true"
|
||||
# Proof: alle OIDC-Logins als Admin; spaeter ueber groups verfeinern
|
||||
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_PATH: "'Admin'"
|
||||
GF_AUTH_GENERIC_OAUTH_ROLE_ATTRIBUTE_STRICT: "false"
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
- -c
|
||||
@@ -162,7 +143,6 @@ services:
|
||||
secrets:
|
||||
- monitoring_grafana_admin_password
|
||||
- monitoring_grafana_influxdb_token
|
||||
- grafana_oidc_client_secret
|
||||
expose:
|
||||
- "3000"
|
||||
security_opt:
|
||||
@@ -178,12 +158,11 @@ services:
|
||||
- traefik.http.routers.monitoring-grafana.entrypoints=websecure
|
||||
- traefik.http.routers.monitoring-grafana.tls=true
|
||||
- traefik.http.routers.monitoring-grafana.tls.certresolver=le
|
||||
# ForwardAuth bewusst entfernt 2026-06-06: Grafana macht jetzt eigenes OIDC-SSO gegen Authelia
|
||||
- traefik.http.routers.monitoring-grafana.middlewares=secure-headers@file
|
||||
- traefik.http.routers.monitoring-grafana.middlewares=authelia@file,secure-headers@file
|
||||
- traefik.http.services.monitoring-grafana.loadbalancer.server.port=3000
|
||||
|
||||
grafana-dashboard-importer:
|
||||
image: python:3.14-alpine
|
||||
image: python:3.13-alpine
|
||||
container_name: monitoring-grafana-dashboard-importer
|
||||
restart: "no"
|
||||
profiles:
|
||||
@@ -294,7 +273,7 @@ services:
|
||||
echo "Dashboard import complete."
|
||||
|
||||
node-exporter:
|
||||
image: prom/node-exporter:v1.11.1@sha256:e9cff4fc67b1818f8c97adb115b9f12c9a54b533de86765d4a0effc01b357205
|
||||
image: prom/node-exporter:v1.9.1@sha256:d00a542e409ee618a4edc67da14dd48c5da66726bbd5537ab2af9c1dfc442c8a
|
||||
container_name: monitoring-node-exporter
|
||||
restart: unless-stopped
|
||||
command:
|
||||
@@ -316,7 +295,7 @@ services:
|
||||
- no-new-privileges:true
|
||||
|
||||
cadvisor:
|
||||
image: ghcr.io/google/cadvisor:v0.57.0@sha256:e75bdb03b74b0b6995f208f166fead2e6e555dde73e44200113bb26f41b1981d
|
||||
image: ghcr.io/google/cadvisor:v0.53.0@sha256:c3770bd6fc6c6a9cb2b47143e6b3cc3fdd9d20a8453dffbb7e09a145e7e0c4e4
|
||||
container_name: monitoring-cadvisor
|
||||
restart: unless-stopped
|
||||
command:
|
||||
@@ -337,7 +316,7 @@ services:
|
||||
- no-new-privileges:true
|
||||
|
||||
influxdb3-core:
|
||||
image: influxdb:3.9.3-core@sha256:c27c9b2ca2625b5b6966f0b09baa448102310e63a471fd60dff22646a2522e29
|
||||
image: influxdb:3.9.1-core@sha256:1d58c8b9ac90153ae3a020ede2810c8284933dda50ac71e7573389ab6f012128
|
||||
container_name: monitoring-influxdb3-core
|
||||
user: "0"
|
||||
restart: unless-stopped
|
||||
@@ -370,8 +349,6 @@ networks:
|
||||
driver: bridge
|
||||
frontend_net:
|
||||
external: true
|
||||
dns_net:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
prometheus_data:
|
||||
@@ -385,7 +362,5 @@ secrets:
|
||||
file: /mnt/user/appdata/secrets/monitoring_grafana_admin_password.txt
|
||||
monitoring_grafana_influxdb_token:
|
||||
file: /mnt/user/appdata/secrets/monitoring_grafana_influxdb_token.txt
|
||||
grafana_oidc_client_secret:
|
||||
file: /mnt/user/appdata/secrets/grafana_oidc_client_secret
|
||||
influxdb3_admin_token:
|
||||
file: /mnt/user/appdata/secrets/influxdb3_admin_token.json
|
||||
|
||||
@@ -1,295 +0,0 @@
|
||||
{
|
||||
"uid": "homelab-family-status",
|
||||
"title": "Homelab / Family Status",
|
||||
"tags": ["homelab", "family", "status"],
|
||||
"timezone": "browser",
|
||||
"schemaVersion": 39,
|
||||
"version": 1,
|
||||
"refresh": "30s",
|
||||
"time": {
|
||||
"from": "now-24h",
|
||||
"to": "now"
|
||||
},
|
||||
"panels": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "stat",
|
||||
"title": "Family Apps Up",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 5, "w": 6, "x": 0, "y": 0},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "sum(probe_success{job=\"blackbox-http\", instance=~\"https://(vault|immich|cloud|paperless|mealie|ntfy|glance)\\\\.kaleschke\\\\.info\"})"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "short",
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "red", "value": null},
|
||||
{"color": "yellow", "value": 5},
|
||||
{"color": "green", "value": 7}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "stat",
|
||||
"title": "Family Apps Down",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 5, "w": 6, "x": 6, "y": 0},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "count(probe_success{job=\"blackbox-http\", instance=~\"https://(vault|immich|cloud|paperless|mealie|ntfy|glance)\\\\.kaleschke\\\\.info\"}) - sum(probe_success{job=\"blackbox-http\", instance=~\"https://(vault|immich|cloud|paperless|mealie|ntfy|glance)\\\\.kaleschke\\\\.info\"})"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "short",
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "green", "value": null},
|
||||
{"color": "red", "value": 1}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "stat",
|
||||
"title": "Backup Age",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 5, "w": 6, "x": 12, "y": 0},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "(time() - homelab_borg_last_completed_timestamp_seconds) / 3600"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "h",
|
||||
"decimals": 1,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "green", "value": null},
|
||||
{"color": "yellow", "value": 24},
|
||||
{"color": "red", "value": 30}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "stat",
|
||||
"title": "TLS Days Left",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 5, "w": 6, "x": 18, "y": 0},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "min((probe_ssl_earliest_cert_expiry{job=\"blackbox-http\"} - time()) / 86400)"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "d",
|
||||
"decimals": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "red", "value": null},
|
||||
{"color": "yellow", "value": 7},
|
||||
{"color": "green", "value": 21}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}}
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "stat",
|
||||
"title": "Critical Containers Down",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 5, "w": 6, "x": 0, "y": 5},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "count(homelab_critical_container_running) - sum(homelab_critical_container_running)"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "short",
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "green", "value": null},
|
||||
{"color": "red", "value": 1}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "stat",
|
||||
"title": "Image Drift",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 5, "w": 6, "x": 6, "y": 5},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "count(homelab_gitops_runtime_image_match) - sum(homelab_gitops_runtime_image_match)"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "short",
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "green", "value": null},
|
||||
{"color": "yellow", "value": 1},
|
||||
{"color": "red", "value": 3}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}}
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "stat",
|
||||
"title": "Last Backup OK",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 5, "w": 6, "x": 12, "y": 5},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "homelab_borg_last_success"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "bool",
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "red", "value": null},
|
||||
{"color": "green", "value": 1}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}}
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "stat",
|
||||
"title": "Metrics Age",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 5, "w": 6, "x": 18, "y": 5},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "(time() - homelab_textfile_exporter_last_run_timestamp_seconds) / 60"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"unit": "m",
|
||||
"decimals": 0,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "green", "value": null},
|
||||
{"color": "yellow", "value": 60},
|
||||
{"color": "red", "value": 120}
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {"reduceOptions": {"calcs": ["lastNotNull"], "fields": "", "values": false}}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "timeseries",
|
||||
"title": "Family App Availability",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 10},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "probe_success{job=\"blackbox-http\", instance=~\"https://(vault|immich|cloud|paperless|mealie|ntfy|glance)\\\\.kaleschke\\\\.info\"}",
|
||||
"legendFormat": "{{instance}}"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {"defaults": {"unit": "bool", "min": 0, "max": 1}, "overrides": []},
|
||||
"options": {"legend": {"displayMode": "list", "placement": "bottom"}}
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "timeseries",
|
||||
"title": "Family App Response Time",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 10},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "probe_duration_seconds{job=\"blackbox-http\", instance=~\"https://(vault|immich|cloud|paperless|mealie|ntfy|glance)\\\\.kaleschke\\\\.info\"}",
|
||||
"legendFormat": "{{instance}}"
|
||||
}
|
||||
],
|
||||
"fieldConfig": {"defaults": {"unit": "s"}, "overrides": []},
|
||||
"options": {"legend": {"displayMode": "list", "placement": "bottom"}}
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "table",
|
||||
"title": "Public Endpoint Status",
|
||||
"datasource": "Prometheus",
|
||||
"gridPos": {"h": 9, "w": 24, "x": 0, "y": 18},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"expr": "probe_http_status_code{job=\"blackbox-http\"}",
|
||||
"format": "table",
|
||||
"instant": true
|
||||
}
|
||||
],
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {
|
||||
"excludeByName": {"Time": true, "__name__": true, "job": true},
|
||||
"renameByName": {"Value": "status_code", "instance": "target"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -57,15 +57,6 @@ groups:
|
||||
summary: "Disk usage high on {{ $labels.mountpoint }}"
|
||||
description: "{{ $labels.mountpoint }} is above 85% used."
|
||||
|
||||
- alert: HomelabDiskCritical
|
||||
expr: 100 * (1 - node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"} / node_filesystem_size_bytes{fstype!~"tmpfs|overlay"}) > 95
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Disk critically full on {{ $labels.mountpoint }}"
|
||||
description: "{{ $labels.mountpoint }} is above 95% used. Writes may start to fail (DB, appdata, cache)."
|
||||
|
||||
- alert: HomelabHighMemoryUsage
|
||||
expr: 100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 90
|
||||
for: 10m
|
||||
@@ -139,23 +130,3 @@ groups:
|
||||
annotations:
|
||||
summary: "Critical container is down: {{ $labels.name }}"
|
||||
description: "The host textfile exporter reports that critical container {{ $labels.name }} is not running."
|
||||
|
||||
- alert: HomelabGitOpsRuntimeImageDrift
|
||||
expr: homelab_gitops_runtime_image_match == 0
|
||||
for: 10m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "Runtime image drift: {{ $labels.name }}"
|
||||
description: "Container {{ $labels.name }} is not running the image declared by its Compose config in project {{ $labels.project }}."
|
||||
|
||||
- name: homelab-meta
|
||||
rules:
|
||||
- alert: HomelabPrometheusTargetDown
|
||||
expr: up == 0
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Prometheus target down: {{ $labels.job }} / {{ $labels.instance }}"
|
||||
description: "Scrape target {{ $labels.instance }} (job {{ $labels.job }}) is unreachable. Metrics from this target are silent — alerts built on them will not fire."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Borg Backup Scope for KalliLabcore
|
||||
|
||||
Stand: 2026-05-31
|
||||
Stand: 2026-05-16
|
||||
|
||||
This file defines the target state for replacing Backrest with Borg in this homelab.
|
||||
|
||||
@@ -45,13 +45,9 @@ The Unraid flash configuration archive is intentional as well and must be treate
|
||||
| GitOps host automation | repo clone + Komodo workspaces + host-check state | `/local/services/homelab-infra`, `/local/services/stacks`, `/local/services/posture-check` |
|
||||
| Unraid OS flash | generated config archive | `/local/borg-dumps/unraid-flash-config.tar.gz` plus checksum and manifest |
|
||||
| Nextcloud | DB dump + file data | `/local/borg-dumps`, `/local/appdata/nextcloud/html`, `/local/nextcloud/data` |
|
||||
| Grafana | SQLite dump from `monitoring_grafana_data` + provisioned config in Git | `/local/borg-dumps`, `monitoring/grafana/provisioning`, `monitoring/grafana/dashboards` |
|
||||
| Grafana | SQLite dump + file data | `/local/borg-dumps`, `/local/appdata/grafana` |
|
||||
| Filebrowser | file-backed state dump + file data | `/local/borg-dumps`, `/local/appdata/filebrowser` |
|
||||
| InfluxDB 3 Core | file data | `/local/appdata/influxdb3/data`, `/local/appdata/influxdb3/plugins` |
|
||||
| Home Assistant | HA-native backup + file state | `/local/appdata/homeassistant`, `/local/services/smart-home-kalli` |
|
||||
| Smart-Home MQTT / Mosquitto | file data | `/local/appdata/mosquitto/config`, `/local/appdata/mosquitto/data` |
|
||||
| Zigbee2MQTT (planned) | file data + coordinator state | `/local/appdata/zigbee2mqtt`, `/local/services/smart-home-kalli` |
|
||||
| ESPHome (planned) | Fachrepo + optional build/runtime cache | `/local/services/smart-home-kalli/esphome`, optional `/local/appdata/esphome` |
|
||||
| Hermes Agent | file data + SSH key | `/local/appdata/hermes-agent/data`, `/local/secrets/hermes_runner_id_ed25519` |
|
||||
| BentoPDF | rebuildable | no critical persistence in compose |
|
||||
|
||||
@@ -73,7 +69,7 @@ The live Unraid User Scripts execute repo scripts from `/mnt/user/services/homel
|
||||
|
||||
## Database Dumps Required
|
||||
|
||||
### Shared PostgreSQL (`postgresql17`, runtime PostgreSQL 18)
|
||||
### Shared PostgreSQL (`postgresql17`)
|
||||
|
||||
- `mailarchiver`
|
||||
- `paperless`
|
||||
@@ -91,20 +87,17 @@ The live Unraid User Scripts execute repo scripts from `/mnt/user/services/homel
|
||||
- SQLite: `gitea`, `vaultwarden`, `speedtest-tracker`, `borg-ui`, `grafana`
|
||||
- File-backed state: `filebrowser.bolt.dump`
|
||||
- Unraid flash config: `unraid-flash-config.tar.gz` plus `unraid-flash-config.tar.gz.sha256`
|
||||
- Home Assistant native backups: created by HA under `/mnt/user/appdata/homeassistant/backups` and captured as file state
|
||||
|
||||
## Explicitly Not Backed Up as Raw Live DB Files
|
||||
|
||||
- `/mnt/user/appdata/postgresql18`
|
||||
- `/mnt/user/appdata/mealie/postgres18`
|
||||
- `/mnt/user/appdata/immich_postgres_vectorchord`
|
||||
- `/mnt/user/appdata/nextcloud/postgres18`
|
||||
- `/mnt/user/appdata/postgresql17`
|
||||
- `/mnt/user/appdata/mealie/postgres`
|
||||
- `/mnt/user/appdata/immich_postgres`
|
||||
- `/mnt/user/appdata/nextcloud/postgres`
|
||||
- `/mnt/user/appdata/komodo/mongo`
|
||||
- `/mnt/user/appdata/redis`
|
||||
- `/mnt/user/appdata/scrutiny/influxdb`
|
||||
|
||||
Archived PG18/VectorChord rollback volumes under `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602` are retained only as temporary rollback material, not as primary backup truth.
|
||||
|
||||
## Low-Priority / Rebuildable
|
||||
|
||||
These are not part of the first-class Borg scope:
|
||||
|
||||
@@ -20,9 +20,5 @@
|
||||
/local/appdata/komodo/periphery
|
||||
/local/appdata/komodo/core
|
||||
/local/services/homelab-infra
|
||||
/local/services/smart-home-kalli
|
||||
/local/services/stacks
|
||||
/local/services/posture-check
|
||||
/local/appdata/homeassistant
|
||||
/local/appdata/mosquitto/config
|
||||
/local/appdata/mosquitto/data
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
borg-ui:
|
||||
image: ainullcode/borg-ui@sha256:0922157e8f77a1b2bd23cd09366a458ea6de07fd9306aa1485f9cfe623eca17f
|
||||
image: ainullcode/borg-ui@sha256:867c73983e5bef5491cdee1c34acf85fe8a9fe4f6ad5a9381e7ca2c382359ce6
|
||||
container_name: borg-ui
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
|
||||
@@ -278,7 +278,7 @@ main() {
|
||||
need_cmd sha256sum
|
||||
ensure_dirs
|
||||
|
||||
# Shared PostgreSQL 18 (historischer Containername: postgresql17)
|
||||
# Shared PostgreSQL 17
|
||||
if need_container "postgresql17"; then
|
||||
# Use the cluster admin/superuser for all shared-cluster dumps. The
|
||||
# application roles exist, but they can have different passwords from the
|
||||
@@ -324,7 +324,7 @@ main() {
|
||||
|
||||
# Additional host-side SQLite dumps for admin tooling with appdata files.
|
||||
dump_sqlite_file "/mnt/user/appdata/borg-ui/data/borg.db" "$LATEST_DIR/borg-ui.sqlite" "borg-ui"
|
||||
dump_sqlite_file "/var/lib/docker/volumes/monitoring_grafana_data/_data/grafana.db" "$LATEST_DIR/grafana.sqlite" "grafana"
|
||||
dump_sqlite_file "/mnt/user/appdata/grafana/grafana.db" "$LATEST_DIR/grafana.sqlite" "grafana"
|
||||
|
||||
# MongoDB
|
||||
dump_mongo_container "komodo-mongo" "$LATEST_DIR/komodo-mongo.archive.gz"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user