Compare commits
180 Commits
593ea0ba82
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ab6dcefd2 | |||
| c24b792808 | |||
| 25a4ada891 | |||
| 6e6005aefd | |||
| ad438a07b3 | |||
| ce6f5c72dd | |||
| 630ee8dd90 | |||
| b1ca9ef19c | |||
| 1c949d3fcc | |||
| cfa6c01768 | |||
| 3474d53ce5 | |||
| ca81b959cc | |||
| 23764dff38 | |||
| 3c4a48d7e5 | |||
| c0a39f5dfc | |||
| a1d7b6e433 | |||
| 45f43da659 | |||
| 290cb8949e | |||
| d933d3cee8 | |||
| baedf9f932 | |||
| b387757e87 | |||
| 3eedbcbe16 | |||
| 9033724b15 | |||
| aae176f1b7 | |||
| c7590e6603 | |||
| 3e486b95f6 | |||
| 08b4be7a5d | |||
| a4f4696b0d | |||
| 1fcdb68221 | |||
| 489a429316 | |||
| 513f41b852 | |||
| c80b51f585 | |||
| 42ed59a4d7 | |||
| 58c3324557 | |||
| d48d473942 | |||
| e80e5dd49f | |||
| 3c339474a7 | |||
| c79afdfab0 | |||
| 8172793c68 | |||
| 8e46440944 | |||
| dfe1dc1c99 | |||
| 4007da3302 | |||
| 9836ea3c4f | |||
| 803f84b3af | |||
| d05ca63545 | |||
| 9847baf327 | |||
| 8ec5bc55d9 | |||
| 9c844074e0 | |||
| c126b71852 | |||
| e89b88a513 | |||
| 8bb250220b | |||
| 2f64aee109 | |||
| ed55b88ec1 | |||
| ce747f687f | |||
| cf11b4d75b | |||
| 796901ec6b | |||
| de7b714b4d | |||
| 8045e22873 | |||
| 52f8c2adcb | |||
| 0ddae675a8 | |||
| 7ce8e948cd | |||
| 2a87220862 | |||
| f2d4cad566 | |||
| e7370e4820 | |||
| dc26eb313c | |||
| dc7cbfa6cd | |||
| cf9ca59eb1 | |||
| d2a9c3b8cb | |||
| 0177350e64 | |||
| 2f3a029098 | |||
| a4c79d9d81 | |||
| 18a90fbb4b | |||
| 30f076c85a | |||
| 6e65f81503 | |||
| 6123584a02 | |||
| c33e29016b | |||
| 2628a0c795 | |||
| c7eed6bdad | |||
| 6c61ad3860 | |||
| 2d1b541847 | |||
| c3491eb382 | |||
| 023ee63687 | |||
| 3a263a4846 | |||
| 68d3ace598 | |||
| 0ef98a23e1 | |||
| 6353da47c5 | |||
| 207f49f001 | |||
| a687d9b73e | |||
| e3459c76d0 | |||
| 254eb81496 | |||
| 9a6d7123ce | |||
| 151d253aff | |||
| dda6021116 | |||
| 2f3d184a3b | |||
| bc3ecad45a | |||
| 88a42f3f78 | |||
| af2c6ee533 | |||
| f382c25696 | |||
| d710a506e8 | |||
| 2ea65e906d | |||
| 2d438cf02b | |||
| 7ba10c893b | |||
| fb948ac951 | |||
| 9ca6e47472 | |||
| 38fa8c5dd5 | |||
| ba87719de3 | |||
| 53c34dca0e | |||
| 7d87698715 | |||
| c47639ecf4 | |||
| b158f9d871 | |||
| d947c7f066 | |||
| 9edd6c24e6 | |||
| 7a513e9fc8 | |||
| 4b96d13510 | |||
| 642eb88b40 | |||
| dd494046ce | |||
| 16d3b8f2fa | |||
| a9b232195d | |||
| 5ee4a158d6 | |||
| 86435d4091 | |||
| 5e52316fab | |||
| 8a4df239fa | |||
| 893b34a585 | |||
| d1f9491b24 | |||
| 14de2f4801 | |||
| 90d1595285 | |||
| c1985e177b | |||
| a244f2d677 | |||
| ef032f2dde | |||
| 6fec64d0a1 | |||
| 5d1ae68705 | |||
| 2913e1005f | |||
| 6f0e6f0d5a | |||
| f473fbaa8b | |||
| c922d1f241 | |||
| ba3ef8fcfc | |||
| 52fc007123 | |||
| 8d71dfb9ad | |||
| 440000c085 | |||
| cacf77bfb0 | |||
| cd4dd178ed | |||
| 541c7be853 | |||
| b1ae9f3c26 | |||
| e2624796f0 | |||
| 9f63e6e3bc | |||
| 8eb367f0b5 | |||
| 745761f518 | |||
| ac637d30fb | |||
| b0a6244e21 | |||
| 4fb17a09e6 | |||
| be5c68751f | |||
| 3bfd065326 | |||
| eeebeec804 | |||
| 55fdb13532 | |||
| 8709fe8239 | |||
| 89114b1b12 | |||
| 3da19421d0 | |||
| 16e661be87 | |||
| 12c05376d0 | |||
| dfd0ccbb9a | |||
| ae5d4aedfc | |||
| 479eb291c4 | |||
| c3222e800b | |||
| 4e34582008 | |||
| ab8bfea7c8 | |||
| 92562dfc9c | |||
| c9c8f9e7ce | |||
| 1d98945a67 | |||
| 9ffcb4e92e | |||
| 99a0bfd60e | |||
| e835dfd6ed | |||
| 6e928b6944 | |||
| 60015c1e2c | |||
| e1afd08bf3 | |||
| 268df30a13 | |||
| 80a5ad24a2 | |||
| 28406ae22b | |||
| 7b6c03b433 | |||
| 59b93924fb | |||
| aecf3b2807 |
@@ -0,0 +1,6 @@
|
||||
*.sh text eol=lf
|
||||
*.ps1 text eol=crlf
|
||||
*.md text
|
||||
*.json text
|
||||
*.yml text
|
||||
*.yaml text
|
||||
@@ -22,9 +22,14 @@
|
||||
**/*.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/
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# 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-05-04
|
||||
Stand: 2026-06-11
|
||||
|
||||
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,9 +10,10 @@ Claude muss vor jeder fachlichen oder technischen Aenderung mindestens diese Dat
|
||||
|
||||
1. `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
2. `docs/WORKFLOW.md`
|
||||
3. `docs/REPO_MAP.md`
|
||||
4. `docs/SERVICE_CATALOG.md`
|
||||
5. die betroffene `docker-compose.yml`
|
||||
3. `docs/README.md`
|
||||
4. `docs/REPO_MAP.md`
|
||||
5. `docs/SERVICE_CATALOG.md`
|
||||
6. die betroffene `docker-compose.yml`
|
||||
|
||||
Zusaetzlich je nach Thema:
|
||||
|
||||
@@ -21,7 +22,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`
|
||||
- Home Assistant / Ecowitt / InfluxDB: `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md`
|
||||
- Architektur-/Betriebsentscheidungen mit Begruendung: `docs/DECISIONS.md`
|
||||
|
||||
## Projektbeschreibung
|
||||
|
||||
@@ -89,7 +90,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`: `network_mode: host`
|
||||
- `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.
|
||||
- `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
|
||||
@@ -122,6 +123,7 @@ 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-05-23 | **Aktueller Schwerpunkt:** GitOps / Doku-Synchronisierung / Reproduzierbare Deployments
|
||||
**Stand:** 2026-06-11 | **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](#13-betriebserfahrungen-und-entscheidungs-log)
|
||||
13. [Betriebserfahrungen und Entscheidungs-Log (ausgelagert)](#13-betriebserfahrungen-und-entscheidungs-log-ausgelagert)
|
||||
|
||||
---
|
||||
|
||||
@@ -93,6 +93,7 @@ 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)
|
||||
@@ -123,7 +124,8 @@ 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)
|
||||
├── monitoring_influx_lan (Bridge fuer LAN-Port-Publishing, keine Traefik-Route)
|
||||
└── smarthome_net (HA, Mosquitto, spaeter Zigbee2MQTT/ESPHome)
|
||||
|
||||
Host-Sonderfälle
|
||||
├── tailscale
|
||||
@@ -145,6 +147,8 @@ 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**:
|
||||
@@ -162,6 +166,8 @@ 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
|
||||
|
||||
@@ -238,7 +244,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 | Git-Stack (`host-services/tailscale/`) | nutzt `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` als dokumentierte VPN-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 |
|
||||
|
||||
### 7.2 Sicherheit / Identity
|
||||
|
||||
@@ -258,6 +264,7 @@ 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
|
||||
|
||||
@@ -271,7 +278,10 @@ 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 |
|
||||
| `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 | — |
|
||||
| `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 |
|
||||
|
||||
### 7.5 Admin / Operations
|
||||
|
||||
@@ -304,7 +314,7 @@ Legende Status:
|
||||
|
||||
| Container | Status | Ziel |
|
||||
|---|---|---|
|
||||
| — | — | Plex ist nicht mehr offen: der Dienst ist als Repo-Compose-Stack unter `host-services/plex/` dokumentiert; `host`-Netz bleibt als Discovery-Ausnahme. |
|
||||
| — | — | 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. |
|
||||
|
||||
### 7.8 Entfernte Container
|
||||
|
||||
@@ -366,23 +376,7 @@ labels:
|
||||
|
||||
## 9. Historische Migration (abgeschlossen)
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
## 10. Bekannte Ausnahmen und Begründungen
|
||||
|
||||
| Container | Ausnahme | Begründung |
|
||||
@@ -400,8 +394,12 @@ Für den laufenden Betrieb gilt stattdessen:
|
||||
| `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 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-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-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. |
|
||||
|
||||
---
|
||||
|
||||
@@ -457,159 +455,15 @@ Damit ist sofort klar:
|
||||
|
||||
---
|
||||
|
||||
## 13. Betriebserfahrungen und Entscheidungs-Log
|
||||
## 13. Betriebserfahrungen und Entscheidungs-Log (ausgelagert)
|
||||
|
||||
### 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`.
|
||||
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).
|
||||
|
||||
---
|
||||
|
||||
## Schlussformel
|
||||
|
||||
Dieses Dokument ist keine lose Notiz, sondern das **operative Masterdokument** für die Docker- und Zugriffsarchitektur des Homelabs.
|
||||
|
||||
@@ -8,19 +8,20 @@ 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:
|
||||
|
||||
3. `docs/DISASTER_RECOVERY.md`
|
||||
4. `docs/RESTORE_MATRIX.md`
|
||||
5. `docs/SERVICES_RECOVERY.md`
|
||||
4. `docs/DISASTER_RECOVERY.md`
|
||||
5. `docs/RESTORE_MATRIX.md`
|
||||
6. `docs/SERVICES_RECOVERY.md`
|
||||
|
||||
Bei Hardware-, Netzwerk-, Provider- oder Kapazitaetsfragen zusaetzlich:
|
||||
|
||||
6. `docs/HARDWARE_INVENTORY.md`
|
||||
7. `docs/NETWORK_INVENTORY.md`
|
||||
8. `docs/EXTERNAL_DEPENDENCIES.md`
|
||||
9. `docs/CAPACITY_AND_LIFECYCLE.md`
|
||||
7. `docs/HARDWARE_INVENTORY.md`
|
||||
8. `docs/NETWORK_INVENTORY.md`
|
||||
9. `docs/EXTERNAL_DEPENDENCIES.md`
|
||||
10. `docs/CAPACITY_AND_LIFECYCLE.md`
|
||||
|
||||
## Architektur
|
||||
|
||||
@@ -65,6 +66,7 @@ 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.
|
||||
@@ -75,4 +77,5 @@ 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,7 +1,7 @@
|
||||
services:
|
||||
immich-server:
|
||||
container_name: immich_server
|
||||
image: ghcr.io/immich-app/immich-server:release@sha256:c15bff75068effb03f4355997d03dc7e0fc58720c2b54ad6f7f10d1bc57efaa5
|
||||
image: ghcr.io/immich-app/immich-server:v2.7.5@sha256:c15bff75068effb03f4355997d03dc7e0fc58720c2b54ad6f7f10d1bc57efaa5
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- redis
|
||||
@@ -32,8 +32,19 @@ services:
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich_machine_learning
|
||||
image: ghcr.io/immich-app/immich-machine-learning:release@sha256:a2501141440f10516d329fdfba2c68082e19eb9ba6016c061ac80d23beadf7f3
|
||||
image: ghcr.io/immich-app/immich-machine-learning:v2.7.5@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:
|
||||
@@ -43,7 +54,7 @@ services:
|
||||
|
||||
redis:
|
||||
container_name: immich_redis
|
||||
image: redis:7.4-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99
|
||||
image: redis:8.8.0-alpine@sha256:09160599abd229764c0fb44cb6be640294e1d360a54b19985ab4843dcf2d90f1
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- immich_default
|
||||
@@ -52,14 +63,15 @@ services:
|
||||
|
||||
database:
|
||||
container_name: immich_postgres
|
||||
image: tensorchord/pgvecto-rs:pg14-v0.2.0@sha256:739cdd626151ff1f796dc95a6591b55a714f341c737e27f045019ceabf8e8c52
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23
|
||||
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:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/immich_postgres_vectorchord:/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:ea7fd8c2e3e0ef0941e8dd9e726e35a8de33296f5c7b9ed811df5168ae6a9714
|
||||
image: s1t5/mailarchiver@sha256:4ea7ecc47ad1dd2c523b85c3967574b61e39def1b6fd26edf874e21733c4018c
|
||||
container_name: mail-archiver
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
|
||||
@@ -4,6 +4,12 @@ services:
|
||||
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"
|
||||
@@ -18,6 +24,16 @@ 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
|
||||
|
||||
@@ -38,7 +54,7 @@ services:
|
||||
- traefik.http.services.mealie.loadbalancer.server.port=9000
|
||||
|
||||
mealie-postgres:
|
||||
image: postgres:17.10@sha256:0027bef26712baaee437a4ea48fdf3d2d2e2bc5f0d81615374408ca320f3c7e3
|
||||
image: postgres:18.4@sha256:8ff36f3c66371cba71d20ceedccfc3de9669a68737607888c4ef0af93abe8e39
|
||||
container_name: mealie-postgres
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -47,10 +63,10 @@ services:
|
||||
POSTGRES_USER: mealie
|
||||
POSTGRES_DB: mealie
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
|
||||
PGDATA: /var/lib/postgresql/data
|
||||
PGDATA: /var/lib/postgresql/18/docker
|
||||
|
||||
volumes:
|
||||
- /mnt/user/appdata/mealie/postgres:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/mealie/postgres18:/var/lib/postgresql
|
||||
- /mnt/user/appdata/secrets/mealie_postgres_password.txt:/run/secrets/postgres_password:ro
|
||||
|
||||
networks:
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
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
|
||||
@@ -0,0 +1,284 @@
|
||||
{
|
||||
"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.4-apache@sha256:caa40b8beaf0057ac213d8dfc515c36ce64f7a8f0825b6a287e6f7cf2f4a095d
|
||||
image: nextcloud:33.0.5-apache@sha256:56bdc45109067500fd0832fa64832b7c77a167d9394cbf5f0f4b59740b94194d
|
||||
container_name: nextcloud
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
@@ -46,7 +46,7 @@ services:
|
||||
- "traefik.http.services.nextcloud.loadbalancer.server.port=80"
|
||||
|
||||
nextcloud-postgres:
|
||||
image: postgres:17.10@sha256:0027bef26712baaee437a4ea48fdf3d2d2e2bc5f0d81615374408ca320f3c7e3
|
||||
image: postgres:18.4@sha256:8ff36f3c66371cba71d20ceedccfc3de9669a68737607888c4ef0af93abe8e39
|
||||
container_name: nextcloud-postgres
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
@@ -54,9 +54,9 @@ services:
|
||||
POSTGRES_DB: nextcloud
|
||||
POSTGRES_USER: nextcloud
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
|
||||
PGDATA: /var/lib/postgresql/data
|
||||
PGDATA: /var/lib/postgresql/18/docker
|
||||
volumes:
|
||||
- /mnt/user/appdata/nextcloud/postgres:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/nextcloud/postgres18:/var/lib/postgresql
|
||||
- /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:7.4-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99
|
||||
image: redis:8.8.0-alpine@sha256:09160599abd229764c0fb44cb6be640294e1d360a54b19985ab4843dcf2d90f1
|
||||
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:b32b4221a64ec2e7c000f0782b2feef24022e1a09a24e531640f4cbba6cfa1e6
|
||||
image: binwiederhier/ntfy@sha256:f8a9b104313b87cc24ae4f775f39e6328205b57dff6ede3eaf098a91e5d79f59
|
||||
container_name: ntfy
|
||||
restart: unless-stopped
|
||||
dns:
|
||||
|
||||
@@ -15,15 +15,18 @@ services:
|
||||
PAPERLESS_API_TOKEN: "${PAPERLESS_API_TOKEN}"
|
||||
MANUAL_TAG: "paperless-gpt"
|
||||
AUTO_TAG: "paperless-gpt-auto"
|
||||
LLM_PROVIDER: "ollama"
|
||||
LLM_MODEL: "qwen3:8b"
|
||||
OLLAMA_HOST: "http://192.168.178.103:11434"
|
||||
OLLAMA_CONTEXT_LENGTH: "4096"
|
||||
TOKEN_LIMIT: "1500"
|
||||
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_LANGUAGE: "German"
|
||||
OCR_PROVIDER: "llm"
|
||||
VISION_LLM_PROVIDER: "ollama"
|
||||
VISION_LLM_MODEL: "minicpm-v:latest"
|
||||
VISION_LLM_PROVIDER: "openai"
|
||||
VISION_LLM_MODEL: "gpt-5.4-mini"
|
||||
VISION_LLM_TEMPERATURE: "1.0"
|
||||
VISION_LLM_REQUESTS_PER_MINUTE: "20"
|
||||
OCR_PROCESS_MODE: "image"
|
||||
CREATE_NEW_TAGS: "true"
|
||||
AUTO_GENERATE_TITLE: "true"
|
||||
|
||||
@@ -3,6 +3,9 @@ services:
|
||||
image: ghcr.io/paperless-ngx/paperless-ngx:2.20.15@sha256:6c86cad803970ea782683a8e80e7403444c5bf3cf70de63b4d3c8e87500db92f
|
||||
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:
|
||||
@@ -17,6 +20,11 @@ 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
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
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:96809ff052e8bd79bba30e067d8b27ed9a2f069b6b2a3484fe1d0eb45aba07c5
|
||||
image: shaanmajid/unbound:1.25.1@sha256:f140db02a005904802bf5840093e95e675321aa060a00426fdffc2a3ac2eeb6b
|
||||
container_name: unbound
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
### 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]
|
||||
@@ -0,0 +1,52 @@
|
||||
### 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
|
||||
@@ -0,0 +1,63 @@
|
||||
### 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.
|
||||
@@ -0,0 +1,58 @@
|
||||
### 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.
|
||||
@@ -0,0 +1,66 @@
|
||||
### 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]
|
||||
@@ -0,0 +1,45 @@
|
||||
### 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)
|
||||
+38
-198
@@ -1,213 +1,53 @@
|
||||
# AI Context
|
||||
|
||||
Stand: 2026-05-04
|
||||
Typ: Einstieg/Index · Stand: 2026-06-11 · Status: aktiv
|
||||
|
||||
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.
|
||||
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`.
|
||||
|
||||
## Kurzfassung
|
||||
## Systembild
|
||||
|
||||
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.
|
||||
- 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
|
||||
|
||||
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/`.
|
||||
## Vor jeder Aenderung lesen
|
||||
|
||||
## Zielbild des Homelabs
|
||||
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`
|
||||
|
||||
- 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:
|
||||
## Harte Regeln
|
||||
|
||||
- Keine Secrets zitieren oder ins Repo schreiben.
|
||||
- Keine produktiven Host-Hotfixes ohne Repo-Abgleich.
|
||||
- Datenbanken nie ins `frontend_net`.
|
||||
- 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`.
|
||||
- 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`).
|
||||
|
||||
## Security-Modell
|
||||
## Bekannte Ausnahmen
|
||||
|
||||
- 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.
|
||||
Autoritativ: `HOMELAB_ARCHITECTURE_MASTER_V2.md` §10. Kurzliste:
|
||||
|
||||
Bekannte Ausnahmen:
|
||||
- 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
|
||||
|
||||
- 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
|
||||
## Arbeitsstand
|
||||
|
||||
## 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.
|
||||
- Offene Punkte: `docs/MASTER_TODO.md` (einzige Statusliste)
|
||||
- Entscheidungen und Begruendungen: `docs/DECISIONS.md`
|
||||
- Belege/Reports: `/mnt/user/backups/restore-reports/` auf dem Host
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,34 +0,0 @@
|
||||
# Alerting Map
|
||||
|
||||
Stand: 2026-05-23
|
||||
|
||||
Ziel: Alle problemrelevanten Homelab-Meldungen landen auf einem Handy-Topic.
|
||||
|
||||
> Die Prometheus-Alarmregeln im Detail (Trigger, Schwellen, Severity,
|
||||
> Handlungshinweis, Luecken-Analyse) stehen in `docs/ALERT_RULES.md`.
|
||||
|
||||
## 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.
|
||||
+42
-117
@@ -1,129 +1,54 @@
|
||||
# Alert Rules
|
||||
|
||||
Stand: 2026-05-30
|
||||
Stand: 2026-06-05
|
||||
|
||||
Zentrale Nachschlagetabelle aller Prometheus-Alarmregeln plus Bewertung, ob die
|
||||
Abdeckung sinnvoll und vollstaendig ist.
|
||||
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/`.
|
||||
|
||||
- **Authoritative Quelle der Regeln:** `monitoring/prometheus/alerts.yml`
|
||||
- **Topic-/Sender-Konvention:** `docs/ALERTING_MAP.md`
|
||||
- Alle Prometheus-Alarme laufen ueber Alertmanager →
|
||||
`monitoring/alertmanager-ntfy-bridge/bridge.py` → ntfy-Topic `homelab-alerts`.
|
||||
## Alarmwege
|
||||
|
||||
> Diese Datei ist **Doku**, nicht die Konfiguration. Wer eine Regel aendert,
|
||||
> aendert `monitoring/prometheus/alerts.yml`, pusht nach Gitea und laesst Komodo
|
||||
> deployen bzw. Prometheus neu laden. Danach diese Tabelle nachziehen.
|
||||
|
||||
## Zwei Alarm-Pfade nebeneinander
|
||||
|
||||
Nicht jeder Homelab-Alarm kommt aus Prometheus. Wer "fehlt da was?" beantworten
|
||||
will, muss beide Pfade zusammen lesen:
|
||||
|
||||
| Pfad | Quelle | Beispiele |
|
||||
| Weg | Quelle | Ziel |
|
||||
|---|---|---|
|
||||
| **Prometheus / Alertmanager** | `monitoring/prometheus/alerts.yml` | Erreichbarkeit, Zertifikate, Disk/RAM, Borg-Metriken, Critical-Container |
|
||||
| **Posture-Check / ntfy-direkt** | `services/posture-check/*` | NVMe-SMART, Cert/Token-Check, Compose-Runtime-Drift, Docker `die`/`oom`/`kill`, Authelia-Drift, Borg-Pre-Hook, Restore-Jobs |
|
||||
| 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` |
|
||||
|
||||
Beide enden auf `homelab-alerts`. Der Posture-Pfad ist in `docs/ALERTING_MAP.md`
|
||||
tabelliert; er wird hier nur referenziert, nicht dupliziert.
|
||||
## Prometheus-Regeln
|
||||
|
||||
## Prometheus-Regeltabelle
|
||||
|
||||
Severity-Routing der Bridge: `critical` und `warning` gehen beide auf
|
||||
`homelab-alerts` (kein eigenes Topic je Severity).
|
||||
|
||||
### Gruppe `homelab-availability`
|
||||
|
||||
| Alarm | Trigger (PromQL, gekuerzt) | Schwelle / `for` | Severity | Was tun |
|
||||
|---|---|---|---|---|
|
||||
| `HomelabExternalConnectivityDown` | `sum(probe_success{blackbox-http}==0) >= 5` | ≥5 Endpunkte / 8m | warning | WAN/DNS/Provider pruefen, nicht pro Domain jagen — Sammelausfall |
|
||||
| `HomelabEndpointDown` | `probe_success==0` (einzeln, nicht im Sammelausfall) | 1 Endpunkt / 8m | critical | Betroffenen Dienst/Traefik-Route pruefen |
|
||||
| `HomelabEndpointSlow` | `probe_duration_seconds > 5` | >5s / 5m | warning | Dienst-/Backend-Last pruefen, oft transient |
|
||||
| `HomelabCertificateExpiresSoon` | Restlaufzeit 7–21 Tage | <21d & >7d / 30m | warning | ACME/Traefik-Renewal beobachten |
|
||||
| `HomelabCertificateExpiresCritical` | Restlaufzeit ≤7 Tage (oder abgelaufen) | ≤7d / 15m | critical | Renewal sofort erzwingen/pruefen |
|
||||
|
||||
### Gruppe `homelab-host`
|
||||
|
||||
| Alarm | Trigger (PromQL, gekuerzt) | Schwelle / `for` | Severity | Was tun |
|
||||
|---|---|---|---|---|
|
||||
| `HomelabDiskAlmostFull` | `100*(1-avail/size) > 85` (ohne tmpfs/overlay) | >85% / 10m | warning | Mountpoint aufraeumen / erweitern |
|
||||
| `HomelabDiskCritical` | `100*(1-avail/size) > 95` (ohne tmpfs/overlay) | >95% / 5m | critical | Sofort Platz schaffen — Writes drohen zu scheitern (DB, appdata, Cache) |
|
||||
| `HomelabHighMemoryUsage` | `100*(1-MemAvailable/MemTotal) > 90` | >90% / 10m | warning | Speicherfresser identifizieren, ggf. Container-Limit (F-19) |
|
||||
| `HomelabTraefik5xx` | `increase(traefik_service_requests_total{5..}[5m]) >= 5` je Service | ≥5 / 2m | warning | Backend des betroffenen Service pruefen |
|
||||
|
||||
### Gruppe `homelab-backup-and-containers`
|
||||
|
||||
| Alarm | Trigger (PromQL, gekuerzt) | Schwelle / `for` | Severity | Was tun |
|
||||
|---|---|---|---|---|
|
||||
| `HomelabTextfileExporterStale` | `time()-last_run > 2h` | >2h / 15m | warning | `export-prometheus-textfile.sh`-Cron auf Host pruefen |
|
||||
| `HomelabBorgMetricsMissing` | `absent(borg_last_completed_ts)` | fehlt / 15m | critical | Textfile-Export oder borg-ui pruefen |
|
||||
| `HomelabBorgBackupStale` | `time()-borg_last_completed_ts > 30h` | >30h / 15m | warning | Letztes Borg-Backup nachholen/pruefen |
|
||||
| `HomelabBorgLastJobFailed` | `borg_last_success != 1` | ≠1 / 15m | critical | Borg-UI-Job-Log pruefen, Backup wiederholen |
|
||||
| `HomelabBorgLastJobCompletedWithWarnings` | `borg_last_job_warning == 1` | =1 / 15m | warning | Warnung im Borg-UI-Job lesen |
|
||||
| `HomelabCriticalContainerDown` | `homelab_critical_container_running == 0` | =0 / 5m | critical | Container neu starten / Komodo-Stack pruefen (`name`-Label) |
|
||||
| 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` (`CRITICAL_CONTAINERS`).
|
||||
`services/posture-check/export-prometheus-textfile.sh`.
|
||||
|
||||
### Gruppe `homelab-meta`
|
||||
## Bekannte Luecken
|
||||
|
||||
| Alarm | Trigger (PromQL, gekuerzt) | Schwelle / `for` | Severity | Was tun |
|
||||
|---|---|---|---|---|
|
||||
| `HomelabPrometheusTargetDown` | `up == 0` | =0 / 5m | critical | Scrape-Ziel (node-exporter/cadvisor/blackbox/traefik) pruefen — Metriken sind sonst still |
|
||||
|
||||
## Bewertung: Sind die Alarme sinnvoll?
|
||||
|
||||
Insgesamt solide. Die Erreichbarkeits-Gruppe ist gut entworfen — der
|
||||
Sammelausfall-Trick (`>=5` Endpunkte als ein Warning, Einzelausfall als
|
||||
Critical) verhindert eine ntfy-Flut bei kurzen DSL-Reconnects. Borg ist mit vier
|
||||
Regeln (fehlende Metrik, veraltet, fehlgeschlagen, mit Warnungen) gut
|
||||
abgedeckt.
|
||||
|
||||
Anmerkungen / Feinschliff (kein Handlungsdruck):
|
||||
|
||||
- **`HomelabDiskAlmostFull` ohne Array-Filter.** Der `fstype!~"tmpfs|overlay"`-
|
||||
Filter schliesst keine bewusst vollen Unraid-Array-Disks aus. Eine
|
||||
Datengrab-Disk, die dauerhaft bei 90 % liegt, erzeugt einen Dauer-Warning.
|
||||
Bei Bedarf per `mountpoint`-Filter auf die wirklich kritischen Pfade
|
||||
(`/`, appdata-/services-Cache) eingrenzen.
|
||||
- **`HomelabEndpointSlow` >5s** ist grosszuegig und damit eher ruhig — okay als
|
||||
bewusste Wahl, faengt aber keine schleichende 3–4s-Degradierung.
|
||||
- **`HomelabHighMemoryUsage` 90 %** ist auf einem Host mit ZFS/Unraid-Cache
|
||||
schnell erreicht (Cache zaehlt nicht als „available" je nach Messung); die
|
||||
Verwendung von `MemAvailable` ist hier korrekt und mildert das.
|
||||
|
||||
## Bewertung: Fehlt etwas? (Luecken, priorisiert)
|
||||
|
||||
### Hoch — erledigt 2026-05-30
|
||||
|
||||
1. ~~Kein `up == 0` auf Scrape-Targets~~ → **`HomelabPrometheusTargetDown`**
|
||||
umgesetzt (Gruppe `homelab-meta`). Faellt node-exporter/cadvisor/blackbox/
|
||||
traefik aus, feuert jetzt nach 5 Minuten ein Critical.
|
||||
2. ~~Kein Disk-Critical-Tier~~ → **`HomelabDiskCritical`** bei >95 % umgesetzt
|
||||
(Gruppe `homelab-host`), zusaetzlich zum bestehenden Warning bei >85 %.
|
||||
|
||||
### Mittel — sinnvoll, aber kein Notstand
|
||||
|
||||
3. **Dead-Man's-Switch.** Faellt Prometheus oder die ntfy-Bridge selbst aus,
|
||||
feuert gar kein Alarm — strukturell blind. Eine immer feuernde
|
||||
Watchdog-Regel plus externer „Heartbeat fehlt"-Waechter (z. B. Uptime-Kuma
|
||||
Push-Monitor oder Healthchecks.io) schliesst die Luecke. Bewusst leichtes
|
||||
Gewicht, weil Posture-Check/Borg-Pre-Hook teilweise unabhaengig laufen.
|
||||
4. **Inode-Erschoepfung.** Paperless/Immich erzeugen viele kleine Dateien;
|
||||
`node_filesystem_files_free` kann vor dem Byte-Limit knapp werden. Niedrige
|
||||
Wahrscheinlichkeit, billiger Alarm.
|
||||
|
||||
### Bewusst nicht in Prometheus (anderer Pfad deckt ab)
|
||||
|
||||
- **NVMe-SMART-Verschleiss** → `check_nvme_smart` im Posture-Check (ntfy direkt).
|
||||
- **Compose-Runtime-Drift / Authelia-Drift** → Posture-Check (ntfy direkt).
|
||||
- **Docker `oom`/`die`/`kill`** → `docker-critical-events.sh` (ntfy direkt) —
|
||||
dies ist auch der Detektionspfad fuer den ersten echten OOM-Vorfall, der F-19
|
||||
(Container-Memory-Limits) ausloesen wuerde.
|
||||
- **Cert/Token-Health jenseits TLS-Ablauf** → `cert-token-check.sh`.
|
||||
|
||||
## Stand
|
||||
|
||||
Die zwei Hoch-Luecken sind seit 2026-05-30 in `alerts.yml` umgesetzt. Naechster
|
||||
optionaler Schritt waere der Dead-Man's-Switch ueber einen externen Heartbeat-
|
||||
Waechter; ohne familienkritischen Anlass aber nicht eilig.
|
||||
- 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`.
|
||||
|
||||
@@ -1,369 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,22 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,88 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,895 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,137 +0,0 @@
|
||||
# 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 + Skript + Erstlauf) | 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 unter `ops/restore-tests/komodo-bootstrap-*` seit 2026-05-29 vorhanden, Erstlauf 2026-05-30 erfolgreich (siehe Sprint 8 Eintrag). |
|
||||
| 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 (Skript) / 2026-05-30 (Erstlauf) | 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. **Erstlauf 2026-05-30 erfolgreich**: Result `SUCCESS`, alle 5 Checks gruen — compose config valid, Test-Mongo healthy (6s), Mongo authenticated ping ok, Komodo Core HTTP `200`, Test-Periphery container state `running`. Report unter `/mnt/user/backups/restore-reports/komodo-bootstrap-2026-05-30.md`. Produktive Komodo-Container, Mongo-Datadir und Secrets nicht beruehrt. Damit ist `ops/komodo/docker-compose.yml` als Recovery-Anker belegt tauglich (nicht mehr nur angenommen). |
|
||||
| erledigt 2026-05-29 | Renovate-Bot gegen Gitea (F-12) | Live: Service-Account `renovate` (uid 2, kein Admin) angelegt, Collaborator Write auf `Micha/homelab-infra`, PAT in `/mnt/user/appdata/secrets/renovate_token.txt` (chmod 600). Cron `renovate-six-hourly` (`20 */6 * * *`) live in `/etc/cron.d/root`. Erstlauf 2026-05-29 erfolgreich: 5 PRs (mongo digest+minor, postgres digest+minor, minor-and-patch-updates gruppiert), 1 Dependency-Dashboard-Issue, 8 Branches. Komodo-Major durch packageRule deaktiviert wie erwartet. Architektur-Detail: Repo-Config in `renovate.json`, Bot-Config in `ops/renovate/bot-config.js` (Renovate liest die im Repo nur als Repo-Config, Bot-Settings dort triggern "forbidden/disabled"). |
|
||||
| erledigt 2026-05-30 | Authelia Repo<->Host Drift-Check (F-10) | `services/authelia-diff.sh` vergleicht die `access_control:`-Sektion zwischen Repo-Baseline und Host-Datei (Default; per env `AUTHELIA_DIFF_SECTIONS` erweiterbar). OIDC-Clients/Identity-Provider und Secret-Werte bleiben bewusst aussen vor. Exit-Codes: 0 = ok, 1 = Drift, 2 = Datei fehlt, 3 = Sektion fehlt, 4 = Werkzeug fehlt. Posture-Check ruft das Skript als Check `authelia_config_drift` auf (`SKIP_AUTHELIA_DRIFT=1` skippt, `AUTHELIA_DIFF_SCRIPT` ueberschreibt den Pfad); Drift wird als Warning gemeldet, nicht Critical. Smoke-Test lokal: identische Files -> rc=0, ACL-Drift im Domain-Eintrag -> rc=1 mit unified diff. WORKFLOW.md hat jetzt eine eigene Pflicht-Sektion "Ausnahme: Authelia configuration.yml" analog zur Traefik-Dynamic-Sektion. Pflicht-Setup auf dem Host: Repo-Spiegel unter `/mnt/user/services/homelab-infra/`. |
|
||||
|
||||
## 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
|
||||
```
|
||||
@@ -1,80 +0,0 @@
|
||||
# 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`.
|
||||
@@ -0,0 +1,186 @@
|
||||
# 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-Bewertung 2026-05-26; externe Cold-Storage-Groessen offen.
|
||||
Status: Initiale Capacity-Baseline 2026-05-26; H:/-Nearline-Pull seit 2026-05-28 produktiv; zweites Off-site/Cold-Storage bewusst nicht umgesetzt.
|
||||
|
||||
## 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 | TBD | TBD | TBD | TBD | TBD |
|
||||
| Externe Cold-Platte | TBD | TBD | TBD | TBD | TBD |
|
||||
| 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 |
|
||||
|
||||
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 | TBD | Familiennutzung kann stark wachsen | Quota/Backup pruefen |
|
||||
| Nextcloud | aktuell klein, kann durch Familiennutzung stark wachsen | Datenwachstum und Quotas koennen spaeter relevant werden | Quota/Backup bei Familien-Onboarding 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,63 +51,48 @@ du -sh /mnt/user/documents /mnt/user/photos /mnt/user/media /mnt/user/backups 2>
|
||||
|
||||
## H:/ als zusaetzliches lokales Backup-Ziel
|
||||
|
||||
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
|
||||
`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.
|
||||
|
||||
| Nutzung | Umsetzung | Hinweis |
|
||||
|---|---|---|
|
||||
| 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 von `/mnt/user/backups/borg/dumps/latest` auf H:/ | Windows Scheduled Task per `robocopy` | keine CIFS-Hard-Mounts auf Unraid |
|
||||
| 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` | identisch | wie Secret behandeln, Windows-seitig nicht in geteilten Ordnern ablegen |
|
||||
| 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 |
|
||||
|
||||
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 |
|
||||
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` |
|
||||
|
||||
### 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, Gitea-Bundles und Flash-Backup |
|
||||
| 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 |
|
||||
|
||||
### Naechste Schritte
|
||||
|
||||
- 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.
|
||||
- Task-Lauf quartalsweise gegen Reports unter `H:\kallilab-nearline-backups\_reports` pruefen.
|
||||
- Review-Intervall: quartalsweise. Bei jeder grossen Strukturaenderung Freeze-Pull manuell ausloesen.
|
||||
|
||||
## Restore-Zeitziele
|
||||
|
||||
| Tier | Beispiel | Zielzeit | Status |
|
||||
|---|---|---:|---|
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
||||
## 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; 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 |
|
||||
| 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` |
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
# 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,202 +0,0 @@
|
||||
# Codex-Prompt: Jellyfin entfernen, Plex bleibt
|
||||
|
||||
> **Status (Stand 2026-05-30):** Auftrag ausgefuehrt. Jellyfin wurde 2026-05-25 aus Repo, Komodo, Traefik-Routing, Authelia-ACL und Appdata-Live-Pfad entfernt (Service-Removal-Checkliste in `docs/WORKFLOW.md`, MIGRATION_LOG-Eintrag dort). Datei bleibt im Repo als **Codex-Removal-Pattern** fuer kuenftige Stack-Removals (z.B. Hermes nach Review-Deadline 2026-07-25 oder bei BentoPDF/paperless-gpt-Folgeentscheidung). Inhaltlich nicht mehr aendern — als Vorlage referenzieren und pro Anwendung neu instanzieren.
|
||||
|
||||
Stand: 2026-05-23
|
||||
Ausloeser: Operator-Entscheidung "Plex bleibt, Jellyfin weg".
|
||||
Bezug: `docs/STRATEGISCHE_BEWERTUNG_2026-05-23.md` Block 9 Quick Wins.
|
||||
|
||||
Du hast Vollzugriff auf `G:\Gitea_Clone\homelab-infra`, Gitea-Push, Komodo, und SSH auf Unraid `Kallilabcore`.
|
||||
|
||||
## Lies zuerst
|
||||
|
||||
1. `CLAUDE.md`
|
||||
2. `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 7.4 und 7.8
|
||||
3. `docs/WORKFLOW.md`
|
||||
4. `docs/ROLLBACK.md`
|
||||
5. `apps/jellyfin/docker-compose.yml`
|
||||
6. `security/authelia/configuration.yml` (Access-Control-Block)
|
||||
7. `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md`, `docs/MIGRATION_LOG.md`
|
||||
|
||||
## Ziel
|
||||
|
||||
Jellyfin ist vollstaendig aus dem Repo, Komodo, Traefik-Routing und Authelia-ACL entfernt. Plex laeuft unveraendert weiter. Medien-/Foto-Mounts unter `/mnt/user/media` und `/mnt/user/photos` bleiben unberuehrt. Domain `jellyfin.kaleschke.info` antwortet nicht mehr ueber Traefik.
|
||||
|
||||
## Wichtige Vorabinformation
|
||||
|
||||
- `/mnt/user/appdata/jellyfin/{config,cache}` ist **nicht** im Borg-Scope (`ops/borg-ui/all-important-sources.txt`). Watch-History, User-Settings und Metadaten-Cache sind danach weg. Das ist akzeptabel, weil Plex die Nutzungsdaten ohnehin separat fuehrt.
|
||||
- Plex teilt sich `/mnt/user/media:ro` und `/mnt/user/photos:ro` mit Jellyfin — Datenpfad bleibt unangetastet.
|
||||
- Authelia-Eintrag `jellyfin.kaleschke.info` steht unter `policy: bypass` in `security/authelia/configuration.yml` Zeile 42. Die `configuration.yml` ist Repo-Baseline und muss laut `docs/AI_CONTEXT.md` manuell auf den Host gemerged werden.
|
||||
- Jellyfin hat **keinen** Eintrag in `monitoring/blackbox/blackbox.yml`, `ops/glance/config/glance.yml`, `apps/homepage/docker-compose.yml`. Die Homepage-Service-Cards liegen hostseitig unter `/mnt/user/appdata/homepage/config/services.yaml` — dort moeglicherweise ein Eintrag, vor Ort pruefen.
|
||||
|
||||
## Reihenfolge
|
||||
|
||||
### P0 — Plex-Tauglichkeit verifizieren (vor jeglichem Loeschen)
|
||||
|
||||
Smoke-Test auf dem Host:
|
||||
|
||||
```bash
|
||||
curl -fsS -o /dev/null -w "%{http_code}\n" http://192.168.178.58:32400/identity
|
||||
docker exec plex test -d /data/Filme || echo "Filme nicht erreichbar"
|
||||
docker exec plex test -d /photos || echo "Photos nicht erreichbar"
|
||||
```
|
||||
|
||||
Akzeptanzkriterium: Plex antwortet mit `200`, beide Medien-Pfade sind im Plex-Container sichtbar, Plex zeigt in seiner Web-UI alle erwarteten Bibliotheken. **Wenn nicht erfuellt: abbrechen und Operator fragen.**
|
||||
|
||||
### P1 — Jellyfin Stack in Komodo stoppen (nicht loeschen)
|
||||
|
||||
In Komodo Web-UI Stack `jellyfin` `Stop` ausfuehren (nicht `Destroy`). Damit ist der Container weg, Stack-Definition und Workspace bleiben — Rollback per `Start` moeglich.
|
||||
|
||||
Akzeptanzkriterium:
|
||||
|
||||
```bash
|
||||
docker ps -a --filter name=jellyfin --format "{{.Names}}\t{{.Status}}"
|
||||
```
|
||||
|
||||
zeigt entweder keine Zeile oder `Exited`.
|
||||
|
||||
### P2 — Authelia ACL um Jellyfin-Bypass bereinigen
|
||||
|
||||
Datei: `security/authelia/configuration.yml`
|
||||
|
||||
```diff
|
||||
- domain:
|
||||
- immich.kaleschke.info
|
||||
- paperless.kaleschke.info
|
||||
- mealie.kaleschke.info
|
||||
- vault.kaleschke.info
|
||||
- ntfy.kaleschke.info
|
||||
- git.kaleschke.info
|
||||
- - jellyfin.kaleschke.info
|
||||
policy: bypass
|
||||
```
|
||||
|
||||
Kein anderer Authelia-Eintrag referenziert Jellyfin. Wildcard `*.kaleschke.info` mit `policy: one_factor` greift fuer geloeschte Domains nicht, weil Traefik die Route nicht mehr kennt.
|
||||
|
||||
**Manueller Host-Sync danach Pflicht** (`docs/AI_CONTEXT.md`, Workflow): die geaenderte `configuration.yml` muss auf `/mnt/user/appdata/authelia/config/configuration.yml` gemerged werden (OIDC-/Secret-Block hostseitig erhalten). Danach `docker exec authelia authelia validate-config -c /config/configuration.yml` und Stack-Restart.
|
||||
|
||||
### P3 — Compose-Stack aus Repo entfernen
|
||||
|
||||
```bash
|
||||
git rm -r apps/jellyfin/
|
||||
```
|
||||
|
||||
Akzeptanzkriterium: `apps/jellyfin/` existiert nicht mehr; `git status --short` zeigt `D apps/jellyfin/docker-compose.yml`.
|
||||
|
||||
### P4 — Doku synchronisieren
|
||||
|
||||
**`HOMELAB_ARCHITECTURE_MASTER_V2.md`:**
|
||||
|
||||
- Abschnitt 3.2 Diagramm: `jellyfin` aus oeffentliche-Apps-Zeile entfernen.
|
||||
- Abschnitt 4.1 "Oeffentlich ueber Traefik": Zeile `- jellyfin — jellyfin.kaleschke.info` entfernen.
|
||||
- Abschnitt 7.4 Tabelle "Produktive Apps": Zeile `jellyfin` entfernen.
|
||||
- Abschnitt 7.8 "Entfernte Container": neue Zeile
|
||||
|
||||
```text
|
||||
| `jellyfin` | 2026-05-23 | doppelter Medienserver neben Plex; Plex bleibt einziger Medienserver |
|
||||
```
|
||||
|
||||
**`docs/SERVICE_CATALOG.md`:**
|
||||
|
||||
- Block "Public / User Apps": Jellyfin-Zeile entfernen.
|
||||
|
||||
**`docs/REPO_MAP.md`:**
|
||||
|
||||
- Abschnitt "Apps"-Tabelle: Jellyfin-Zeile entfernen.
|
||||
- Abschnitt "Traefik Hosts": `jellyfin.kaleschke.info`-Zeile entfernen.
|
||||
- Abschnitt "Volumes und Datenpfade": Jellyfin-Zeile entfernen.
|
||||
|
||||
**`docs/MIGRATION_LOG.md`:** neuen Eintrag anhaengen
|
||||
|
||||
```text
|
||||
### Jellyfin entfernt (2026-05-23)
|
||||
- Operator-Entscheidung: Plex bleibt einziger Medienserver.
|
||||
- Compose-Stack `apps/jellyfin/` aus Repo entfernt.
|
||||
- Authelia-ACL bereinigt (`jellyfin.kaleschke.info` aus `bypass`-Liste raus), Host-Config gemerged.
|
||||
- Komodo-Stack `jellyfin` gestoppt; Stack-Eintrag und Webhook bei Abschluss von Schritt P7 entfernt.
|
||||
- Appdata unter `/mnt/user/appdata/jellyfin/` nach `/mnt/user/appdata/_archive/jellyfin-removed-2026-05-23/` verschoben (siehe Schritt P5).
|
||||
- DNS-Eintrag `jellyfin.kaleschke.info` in Cloudflare belassen, kann beim naechsten DNS-Cleanup mit entfernt werden.
|
||||
```
|
||||
|
||||
### P5 — Appdata archivieren statt loeschen
|
||||
|
||||
Auf dem Host:
|
||||
|
||||
```bash
|
||||
mkdir -p /mnt/user/appdata/_archive
|
||||
mv /mnt/user/appdata/jellyfin /mnt/user/appdata/_archive/jellyfin-removed-2026-05-23
|
||||
```
|
||||
|
||||
Akzeptanzkriterium: `/mnt/user/appdata/jellyfin` existiert nicht mehr, `/mnt/user/appdata/_archive/jellyfin-removed-2026-05-23` enthaelt `config/` und `cache/`. **Nicht endgueltig loeschen** vor mindestens 14 Tagen Plex-Stabilitaet.
|
||||
|
||||
### P6 — Policy-Check + Commit
|
||||
|
||||
```powershell
|
||||
pwsh ops/policy-checks/check_repo.ps1
|
||||
```
|
||||
|
||||
Akzeptanzkriterium: 0 Critical, keine neuen Warnings (vorher: 4 dokumentierte Warnings, soll danach gleich bleiben).
|
||||
|
||||
Commit:
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "Remove Jellyfin stack; Plex remains sole media server"
|
||||
git push origin master
|
||||
```
|
||||
|
||||
### P7 — Komodo-Stack-Eintrag und Webhook entfernen
|
||||
|
||||
Nach erfolgreichem Push und gruener Komodo-Reaktion auf restliche Stacks:
|
||||
|
||||
- In Komodo: Stack `jellyfin` `Destroy` (Workspace `/mnt/user/services/stacks/jellyfin/` entfernen).
|
||||
- In Gitea: Webhook-Eintrag fuer Komodo-Stack-ID `jellyfin` entfernen.
|
||||
|
||||
Akzeptanzkriterium: `ls /mnt/user/services/stacks/ | grep jellyfin` ist leer; Gitea-Webhook-Liste fuer `Micha/homelab-infra` enthaelt keinen Jellyfin-Eintrag mehr.
|
||||
|
||||
### P8 — Smoke-Test final
|
||||
|
||||
```bash
|
||||
curl -fsS -o /dev/null -w "%{http_code}\n" https://jellyfin.kaleschke.info/
|
||||
docker ps --filter name=jellyfin --format "{{.Names}}"
|
||||
ss -ltnp | grep 8096 || echo "Port 8096 frei"
|
||||
```
|
||||
|
||||
Erwartung:
|
||||
|
||||
- `https://jellyfin.kaleschke.info/` antwortet `404` (Traefik kennt die Route nicht mehr) oder Cert-Fehler je nach Cache.
|
||||
- Kein laufender `jellyfin`-Container.
|
||||
- Port `8096` nicht belegt (Jellyfin nutzte nur Container-Port, sollte sowieso frei sein).
|
||||
- Authelia-Login fuer Admin-Domains (`uptime`, `files`, `scrutiny`) funktioniert weiterhin — Bypass-Liste-Aenderung darf 2FA-Domains nicht angreifen.
|
||||
|
||||
## Rollback (bis Schritt P5 einschliesslich)
|
||||
|
||||
- Git: `git revert <commit-sha>` und push. Komodo deployt Jellyfin neu, sobald Stack in Komodo wieder existiert.
|
||||
- Appdata: `mv /mnt/user/appdata/_archive/jellyfin-removed-2026-05-23 /mnt/user/appdata/jellyfin`.
|
||||
- Authelia-ACL: Bypass-Eintrag wieder rein, Host-Sync, Authelia-Restart.
|
||||
|
||||
Ab Schritt P7 (Komodo Destroy + Webhook weg) ist Rollback nur per Neuanlegen des Komodo-Stacks moeglich.
|
||||
|
||||
## Regeln (aus CLAUDE.md, nicht verhandelbar)
|
||||
|
||||
- Secrets nie im Klartext ausgeben.
|
||||
- Keine Aenderungen direkt in Komodo, nur ueber Git → Push → Komodo. **Ausnahme:** Schritt P1 (`Stop`) und P7 (`Destroy`) sind explizit Komodo-Aktionen nach erfolgreichem Repo-Stand.
|
||||
- Kein `push --force`, kein blindes Loeschen unter `/mnt/user/{appdata,documents,photos,services,backups}` — Appdata wird in `_archive/` verschoben, nicht entfernt.
|
||||
- Working-Tree-Status nur aus `git status --short` ableiten, nie aus `git diff` ueber Linux-Mount.
|
||||
- Traefik dynamic config wird nicht von Komodo deployed — fuer diesen Auftrag nicht relevant, weil Jellyfin nur per Docker-Labels gerouteted war.
|
||||
- Nicht anfassen: Plex-Stack, Medien-/Foto-Mounts, alle anderen Apps.
|
||||
- Wenn zwei Reparaturversuche scheitern: stoppen, `docs/GITOPS_DRIFT_RUNBOOK.md` Pflichtmatrix, Operator fragen.
|
||||
|
||||
## Arbeitsmodus pro Schritt
|
||||
|
||||
Lesen → minimal aendern → `ops/policy-checks/check_repo.ps1` lokal (nur P6) → Commit → Push → Komodo-Reaktion + Smoke-Test → Eintrag in `docs/MIGRATION_LOG.md`.
|
||||
|
||||
## Fertig
|
||||
|
||||
Wenn alle 8 Schritte abgehakt sind: kurze Erfolgsmeldung an Operator mit:
|
||||
|
||||
- Commit-SHA des Removal-Commits
|
||||
- Bestaetigung Plex weiterhin gruen
|
||||
- Bestaetigung Authelia validate-config gruen
|
||||
- Bestaetigung Komodo-Stack und Webhook entfernt
|
||||
- Pfad zum Appdata-Archiv und Erinnerung, dass `_archive/jellyfin-removed-2026-05-23/` nach 14 Tagen Plex-Stabilitaet entfernt werden darf
|
||||
@@ -1,123 +0,0 @@
|
||||
# Codex-Prompt: Komodo 5xx-Spam Root-Cause
|
||||
|
||||
Stand: 2026-05-31
|
||||
Auftraggeber: Operator
|
||||
Vorarbeit: Claude (auto-mode), siehe Ermittlungsstand unten.
|
||||
|
||||
## Auftrag
|
||||
|
||||
`HomelabTraefik5xx` feuert dauerhaft fuer `service="komodo@docker"`. Quelle
|
||||
finden, fixen, dokumentieren. Bitte einmal **bis zum Ende** durchziehen, nicht
|
||||
nur eine Hypothese pruefen.
|
||||
|
||||
## Vor Arbeitsbeginn lesen
|
||||
|
||||
- `CLAUDE.md`
|
||||
- `docs/WORKFLOW.md`
|
||||
- `monitoring/prometheus/alerts.yml`
|
||||
- `docs/ALERT_RULES.md`
|
||||
- `ops/komodo/docker-compose.yml`
|
||||
- `traefik/docker-compose.yml`
|
||||
- `monitoring/prometheus/prometheus.yml` (Blackbox-Targets)
|
||||
- `monitoring/blackbox/blackbox.yml`
|
||||
- `ops/glance/config/glance.yml` (5 Komodo-URL-Stellen, **NICHT** die Quelle — siehe Ermittlung)
|
||||
|
||||
## Ermittlungsstand (bereits geklaert)
|
||||
|
||||
### Was gemessen wurde
|
||||
|
||||
- Traefik-Access-Log: Source-IP ist **eure WAN-IP `217.249.121.39`** (Hairpin
|
||||
aus dem Heimnetz). User-Agent leer (`"-"`).
|
||||
- Muster: `GET /` 200 **alle 15s** + `GET /user` **500** alle 30s, plus
|
||||
gelegentlich `POST /auth/login/GetLoginOptions` 200 und
|
||||
`POST /read/GetCoreInfo` 500.
|
||||
- Prometheus `sum by (code) (increase(traefik_service_requests_total{service="komodo@docker"}[5m]))`:
|
||||
`200`=22, `500`=14 (Werte vom 2026-05-31 08:11 UTC).
|
||||
- `docker logs komodo-core` ist still — keine internen Errors, nur normale
|
||||
Execute-Requests. Komodo wirft den 500 also vermutlich auf Auth-Pfad
|
||||
(`/user` ohne gueltige Session sollte `401` sein, nicht `500`). Das ist ein
|
||||
Komodo-Bug-on-Top, **aber nicht die Frage**.
|
||||
|
||||
### Ausgeschlossene Kandidaten (durch Test)
|
||||
|
||||
- **Browser-Tabs** — User hat alle Komodo-Tabs zugemacht, Polling laeuft
|
||||
weiter.
|
||||
- **PWA auf Handy** — User hat keine.
|
||||
- **Uptime-Kuma** — Container existiert nicht mehr.
|
||||
- **Homepage** — entfernt.
|
||||
- **Glance** — Test 2026-05-31 ~08:35 UTC: 130s gestoppt, 5xx-Rate
|
||||
unveraendert (2/60s Baseline → 4/130s waehrend Stop). Trotz 5 Komodo-URL-
|
||||
Eintraegen in `ops/glance/config/glance.yml` (search-shortcut Zeile 40,
|
||||
bookmark Zeilen 131/768, monitor-Widget Zeile 237 mit `check-url:
|
||||
http://komodo-core:9120`, docker-containers-Widget Zeile 725). Glance ist
|
||||
raus.
|
||||
|
||||
### Noch nicht getestete Kandidaten
|
||||
|
||||
- **Posture-Check / cert-token-check.sh** (`services/posture-check/`) — koennte
|
||||
periodisch Komodo-HTTPS pingen. 15s-/30s-Kadenz waere ungewoehnlich fuer
|
||||
einen Cron-Job, aber pruefen.
|
||||
- **Blackbox-Exporter** — pollt laut `monitoring/prometheus/prometheus.yml`
|
||||
`https://komodo.kaleschke.info` alle 15s. Das erklaert den `GET / 200`-
|
||||
Anteil sauber. Erklaert aber NICHT den `GET /user 500` 30s-Takt.
|
||||
- **Komodo Periphery** — auf `komodo_net` und `frontend_net`. Sollte mit
|
||||
Core via internes Netz reden, koennte aber per Misconfig die Public-URL
|
||||
treffen. Logs noch nicht eingesehen.
|
||||
- **Komodo Core selbst** mit `KOMODO_HOST=https://komodo.kaleschke.info` —
|
||||
evtl. Self-Check via Public-URL.
|
||||
- **Ein Gerat im LAN**, das wir noch nicht auf dem Schirm haben (zweiter
|
||||
Rechner mit altem Tab, Smart-TV, etc.).
|
||||
|
||||
### Was nicht geht
|
||||
|
||||
- `tcpdump` fehlt auf dem Host.
|
||||
- `conntrack` zeigt die Hairpin-Pakete nicht (NAT-Pre-Routing).
|
||||
|
||||
## Naechste Schritte (Vorschlag)
|
||||
|
||||
1. **Blackbox-Exporter ausschliessen**: Targets in `prometheus.yml` zeigen,
|
||||
dass Blackbox NUR `https://komodo.kaleschke.info` pollt (also `/`, kein
|
||||
`/user`). Bestaetigen.
|
||||
2. **Posture-Check pruefen**: `services/posture-check/cert-token-check.sh`
|
||||
lesen, Kadenz und Endpunkte protokollieren. Falls dort `/user` oder ein
|
||||
30s-Loop drin ist → Treffer.
|
||||
3. **Periphery isolieren**: Periphery 2 min stoppen, Traefik-Log gegen-
|
||||
checken. `docker stop komodo-periphery; sleep 130; <log-check>; docker
|
||||
start komodo-periphery`. Vorsicht: Periphery-Down heisst Komodo-Deploy
|
||||
funktioniert nicht — also nur kurz, kein Deploy in dem Fenster.
|
||||
4. **Komodo-Core isolieren**: Wenn 1-3 nichts ergeben, Komodo-Core selbst 2 min
|
||||
stoppen. Wenn Polling weiterlaeuft, ist der Client ausserhalb der Komodo-
|
||||
Stack (LAN-Geraet). Wenn es aufhoert, polled Komodo Core sich selbst.
|
||||
5. **LAN-Aufnahme via Komodo-Container**: Falls Container-Stack ausgeschlossen,
|
||||
im komodo-core-Container per `ss -tnp state syn-recv` waehrend einer
|
||||
typischen Polling-Sekunde mitschauen. Source-IP/Port der eingehenden
|
||||
Connection liefert den Hairpin-Origin am genauesten.
|
||||
|
||||
## Fix-Erwartung
|
||||
|
||||
Sobald Quelle bekannt:
|
||||
|
||||
- **Wenn Container im Stack**: Config so anpassen, dass die Anfrage intern
|
||||
laeuft (kein Public-Hostname), inkl. Doku.
|
||||
- **Wenn LAN-Geraet**: User informieren, was es ist; wenn moeglich Geraet
|
||||
reparieren (Tab schliessen, App deinstallieren). Kein Repo-Change noetig.
|
||||
- **Wenn nicht abstellbar**: separate Frage, ob `HomelabTraefik5xx` fuer
|
||||
`service="komodo@docker"` mit einem Exclude versehen werden soll — aber nur
|
||||
als letzter Ausweg. Default ist: Quelle fixen.
|
||||
|
||||
## Doku am Ende
|
||||
|
||||
- Eintrag in `docs/MIGRATION_LOG.md`: Datum, Symptom, Root-Cause, Fix,
|
||||
Smoke-Test.
|
||||
- Falls eine Glance-/Periphery-/sonstige Config-Aenderung noetig wird:
|
||||
Standard-Loop (Commit → Push → Komodo-Deploy → Smoke), Co-Authored-By-Tag
|
||||
mitgeben.
|
||||
|
||||
## Regeln (nicht verhandelbar)
|
||||
|
||||
- Git → Push → Komodo. Keine direkten Komodo-Edits.
|
||||
- Stop/Start-Tests sind okay, aber nur kurz (≤ 3 min) und mit
|
||||
Wiederanlauf-Schritt im selben Block.
|
||||
- Secrets nicht ausgeben.
|
||||
- Bei zwei gescheiterten Versuchen: stop, Pflichtmatrix aus
|
||||
`docs/GITOPS_DRIFT_RUNBOOK.md`, Operator fragen.
|
||||
@@ -1,83 +0,0 @@
|
||||
# Codex-Prompt: KalliLab Konsolidierung (Bewertungs-Followup)
|
||||
|
||||
> **Status (Stand 2026-05-30):** Erstprompt fuer den Audit-Zyklus 2026-05-25, Stand weitgehend abgearbeitet. Verbleibende Punkte sind in `docs/AUDIT_2026-05-25_TODO.md` weiter gefuehrt (offen, geparkt, bewusst nicht umgesetzt). Datei bleibt im Repo als **Codex-Prompt-Vorlage** fuer kuenftige Konsolidierungs-Sweeps; inhaltlich nicht mehr aendern.
|
||||
|
||||
Stand: 2026-05-23
|
||||
Auftraggeber: Operator
|
||||
Quelle: `docs/STRATEGISCHE_BEWERTUNG_2026-05-23.md`
|
||||
|
||||
## Schritt 0 — Reviewe die Bewertung kritisch
|
||||
|
||||
Lies `docs/STRATEGISCHE_BEWERTUNG_2026-05-23.md` komplett. Bevor du irgendetwas anfasst, sag dem Operator ehrlich:
|
||||
|
||||
- Wo ist Claudes Befund richtig?
|
||||
- Wo liegt Claude daneben oder hat etwas Wichtiges uebersehen?
|
||||
- Welche Hausaufgaben unten wuerdest du anders priorisieren oder weglassen?
|
||||
|
||||
Erst nach Operator-Freigabe weitermachen.
|
||||
|
||||
## Lies vor jedem Block
|
||||
|
||||
`CLAUDE.md`, `docs/WORKFLOW.md`, betroffene Compose-Datei. Bei DR/Backup zusaetzlich `docs/DISASTER_RECOVERY.md` und `docs/RESTORE_MATRIX.md`.
|
||||
|
||||
## Hausaufgaben
|
||||
|
||||
### P0 — Quick Wins (≤ 1 Woche, hoher Nutzen)
|
||||
|
||||
1. **Externer Repo-Mirror** einrichten (GitHub privat oder zweites Gitea); Push-Mirror in Gitea aktivieren. Schliesst das groesste DR-Loch.
|
||||
2. **Borg-Passphrase analog sichern** (Schliessfach oder Familienmitglied).
|
||||
3. **Jellyfin entfernen, Plex bleibt.** Detail-Schritte in `docs/CODEX_JELLYFIN_REMOVAL_2026-05-23.md`. Kurzfassung: Plex-Smoke-Test → Komodo-Stop → Authelia-Bypass raus + Host-Sync → `git rm apps/jellyfin/` → Doku (MASTER 3.2/4.1/7.4/7.8, SERVICE_CATALOG, REPO_MAP, MIGRATION_LOG) → Appdata nach `_archive/` → Policy-Check → Push → Komodo-Destroy + Webhook weg.
|
||||
4. **Glance oder Homepage** als einziges Dashboard waehlen, das andere stoppen und aus Repo entfernen.
|
||||
5. **AdGuard Admin-Port 8082** hinter Authelia oder nur via Tailscale (Block F aus MASTER 10).
|
||||
6. **Authelia 2FA-Pflicht** fuer alle aktiven User verifizieren bzw. aktivieren.
|
||||
7. **Disk1 NTFS → XFS Phase 2** abschliessen, anschliessend `ALLOW_DISK1_NTFS=0` in posture-check.
|
||||
|
||||
### P1 — Stabilitaet und Ordnung (2–4 Wochen)
|
||||
|
||||
8. **Monitoring-Migration abschliessen**: `monitoring/` produktiv, `ops/grafana-influxdb` + `ops/loki` `down` + aus Repo entfernen.
|
||||
9. **Uptime-Kuma abloesen** durch Blackbox + Grafana-Alerts (nach 7 Tagen Parallelbetrieb mit Paritaet, wie in SERVICE_CATALOG vorgesehen).
|
||||
10. **Hermes-Agent Entscheidung**: produktiv mit klarem Alltagsnutzen oder vollstaendig entfernen. Kein weiteres Quartal "halb da".
|
||||
11. **paperless-gpt und BentoPDF**: gleiche Frage. Produktiv im Workflow oder weg.
|
||||
12. **Unraid USB-Flash-Backup** einrichten (eingebauter Mechanismus).
|
||||
13. **Family-View-Dashboard** in Grafana: alles-gruen-Uebersicht fuer den Morgen-Check.
|
||||
|
||||
### P2 — Automatisierung und Transparenz (4–12 Wochen)
|
||||
|
||||
14. **Authelia OIDC-Provider** aktivieren; Nextcloud + Immich + Grafana als OIDC-Clients.
|
||||
15. **Renovate Bot gegen Gitea** fuer kontrollierte Image-Update-PRs (loest die manuelle Digest-Pflege ab).
|
||||
16. **Restore-Test fuer Immich** als eigener Sprint einplanen (groesster Datentopf ohne Mini-Restore).
|
||||
17. **Immich Smartphone-Auto-Backup** fuer alle Familien-Geraete aktivieren — der eigentliche Familien-Nutzen.
|
||||
18. **CrowdSec vor Traefik** als Bouncer fuer oeffentlich erreichbare Apps.
|
||||
|
||||
### P3 — Advanced (3–6 Monate)
|
||||
|
||||
19. Staging-Branch + zweites Komodo-Ziel in Tailscale-VM.
|
||||
20. Restore-Test-Automatisierung als CI (Gitea Actions oder Drone).
|
||||
21. Off-Site-Backup zu zweitem Ziel (zweites BorgBase-Repo oder Hetzner Storage Box).
|
||||
22. Cold-Standby-Konzept dokumentieren.
|
||||
23. Komodo-Self-Stack aus Komodo-Management herausnehmen, als handgepflegter `docker compose`-Service in `services/`.
|
||||
|
||||
### P4 — Nice-to-have / Spielwiese
|
||||
|
||||
24. Firefly III oder Actual Budget fuer `/mnt/user/finance`.
|
||||
25. Wandtablet im Flur mit Family-Dashboard.
|
||||
26. Home Assistant tiefer in ntfy-Workflows verzahnen (Frostwarnung, PV-Ueberschuss, Briefkasten).
|
||||
27. Ecowitt-Wetter-Dashboard, sobald HA→InfluxDB-Pipeline aus `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md` laeuft.
|
||||
|
||||
## Regeln (aus CLAUDE.md, nicht verhandelbar)
|
||||
|
||||
- Git → Push → Komodo. Keine direkten Komodo-Edits, kein `push --force`.
|
||||
- Secrets nie ins Repo, nie loggen.
|
||||
- Appdata-Pfade nicht blind loeschen — vor Removal nach `/mnt/user/appdata/_archive/<ding>-removed-<datum>/` verschieben, 14 Tage warten.
|
||||
- Traefik dynamic config manueller Host-Sync.
|
||||
- Working-Tree-Status nur aus `git status --short`, nie aus `git diff` ueber Linux-Mount.
|
||||
- Nicht anfassen: Komodo native Auth (dokumentierte Ausnahme), Grafana/InfluxDB `user: "0"`, Image-Pinning ddns/glances/scrutiny.
|
||||
- Bei zwei gescheiterten Versuchen: stop, `docs/GITOPS_DRIFT_RUNBOOK.md` Pflichtmatrix, Operator fragen.
|
||||
|
||||
## Arbeitsmodus pro Block
|
||||
|
||||
Lesen → minimal aendern → `ops/policy-checks/check_repo.ps1` → Commit → Push → Komodo + Smoke-Test → eine Zeile in `docs/MIGRATION_LOG.md`.
|
||||
|
||||
## Fertig pro Block
|
||||
|
||||
Kurz an Operator: Commit-SHA, Smoke-Test-Beleg, ggf. neuer Watchpoint.
|
||||
@@ -0,0 +1,169 @@
|
||||
# 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).
|
||||
+154
-13
@@ -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
|
||||
- `docs/RESTORE_HANDBOOK.md` - praktische Restore-Betriebsanleitung
|
||||
- `ops/restore-tests/README.md` - Restore-Test-Betrieb und Werkzeuge
|
||||
- `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,7 +62,8 @@ 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 |
|
||||
| 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" |
|
||||
| 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 |
|
||||
@@ -87,9 +88,15 @@ Deshalb gilt:
|
||||
|
||||
Verfuegbare Wege:
|
||||
|
||||
- externer Push-Mirror: `https://github.com/michaelkaleschke-spec/homelab-infra`
|
||||
- lokaler Bare-Clone auf dem PC
|
||||
- normaler lokaler Arbeits-Clone auf dem PC
|
||||
- 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.
|
||||
|
||||
Wenn **weder GitHub-Mirror noch lokaler Repo-Clone** verfuegbar sind, ist `services/gitea/data` selbst ein kritischer Restore-Pfad.
|
||||
|
||||
@@ -148,6 +155,12 @@ 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:
|
||||
@@ -241,17 +254,52 @@ 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/`
|
||||
3. `host-services/tailscale/`
|
||||
|
||||
> **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.
|
||||
|
||||
Ziel:
|
||||
|
||||
@@ -261,7 +309,7 @@ Ziel:
|
||||
|
||||
### Stufe 2 - Gemeinsame Backends und Identity
|
||||
|
||||
4. `infra/postgresql17/`
|
||||
4. `infra/postgresql17/` (PostgreSQL 18 runtime, historischer Stack-Name bleibt fuer Service-DNS stabil)
|
||||
5. `security/authelia/`
|
||||
6. `infra/redis/`
|
||||
7. `core/gitea/`
|
||||
@@ -290,6 +338,13 @@ 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/`
|
||||
@@ -342,6 +397,7 @@ 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
|
||||
|
||||
@@ -382,7 +438,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 validate-config` erfolgreich sein; der SMTP-Startup-Check darf den Start nicht blockieren.
|
||||
Beim Smoke-Test muss `authelia config validate` erfolgreich sein; der SMTP-Startup-Check darf den Start nicht blockieren.
|
||||
|
||||
### `nextcloud`
|
||||
|
||||
@@ -396,6 +452,12 @@ 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.
|
||||
@@ -406,6 +468,50 @@ 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.
|
||||
@@ -423,15 +529,50 @@ 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. Offene Vorbereitungs-To-dos
|
||||
## 11. Laufende Vorbereitung
|
||||
|
||||
- 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
|
||||
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
|
||||
- `komodo-mongo`-Dump nach Major-Upgrades gezielt kontrollieren
|
||||
- Restore-Drills nach Kadenz aus `ops/restore-tests/schedule.md` rotieren
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,225 @@
|
||||
# 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: Initiale Betreiber-Baseline 2026-05-26; konkrete Account-Recovery-Codes und Besitznachweise muessen ausserhalb des Repos bestaetigt werden.
|
||||
Status: Betreiber-Baseline 2026-06-01; Account-Recovery, Schluessel und Besitznachweise bleiben ausserhalb des Repos.
|
||||
|
||||
## Zweck
|
||||
|
||||
@@ -11,17 +11,19 @@ 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 regelmaessig sichern (FRITZ!OS-Backup), Reset-Pin und Account-Pfad bereithalten |
|
||||
| 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 |
|
||||
| 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 | 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 |
|
||||
| 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 |
|
||||
| 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 | mittel | Mail-Notifier faellt aus, Login selbst nicht zwingend | GMX-Konto; SMTP-Secret liegt hostseitig | ntfy/zweiter SMTP als Fallback pruefen |
|
||||
| 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 |
|
||||
| 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/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 |
|
||||
| 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 |
|
||||
| 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
|
||||
|
||||
@@ -33,9 +35,28 @@ 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 | In Host-Secret, Fallback pruefen |
|
||||
| SMTP Passwort | Authelia Mail, Vaultwarden-Einladungen, Ops-Report-Mail | In Host-Secrets, 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 | SSH-/Web-Zugang und Zahlungsweg extern 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.
|
||||
|
||||
## Ausfall-Szenarien
|
||||
|
||||
@@ -43,7 +64,8 @@ Authoritativ ist `docs/SECRETS_MAP.md`. Diese Liste markiert nur externe Abhaeng
|
||||
|
||||
- Lokales Borg-Repo und aktuelle Dumps pruefen.
|
||||
- Keine destruktiven Host-Aenderungen starten, solange Off-site unklar ist.
|
||||
- Zweites Off-site-Ziel oder Cold-Platte als Folgeaufgabe umsetzen.
|
||||
- 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.
|
||||
|
||||
### Cloudflare Account/DNS gestoert
|
||||
|
||||
@@ -63,7 +85,7 @@ Authoritativ ist `docs/SECRETS_MAP.md`. Diese Liste markiert nur externe Abhaeng
|
||||
- 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 8.21 Update wird bewusst nur in einem geplanten Service-Fenster eingespielt, weil Reboot WAN/Tailscale-Aufbau unterbricht.
|
||||
- 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.
|
||||
|
||||
### Domain verloren oder Registrar-Zugriff verloren
|
||||
|
||||
@@ -74,6 +96,6 @@ Authoritativ ist `docs/SECRETS_MAP.md`. Diese Liste markiert nur externe Abhaeng
|
||||
|
||||
| Datum | Ergebnis | Naechste Aktion |
|
||||
|---|---|---|
|
||||
| 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 |
|
||||
| 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 |
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
# 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>
|
||||
+121
-14
@@ -1,6 +1,6 @@
|
||||
# Familien-Willkommen - KalliLab CORE
|
||||
|
||||
Status: **Final-Stand vor Wochenend-Einladung** (2026-05-27). Zielgruppe: Familie. Kein Technik-Wortschatz noetig.
|
||||
Status: **Praxis-Onboarding** (2026-06-01). 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,12 +25,44 @@ 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 | Plex-App auf dem Geraet, mit Konto anmelden |
|
||||
| **Plex** | Filme und Musik auf Fernseher, Handy und Tablet | Web `https://plex.kaleschke.info` oder 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:
|
||||
@@ -57,13 +89,40 @@ 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. Fertig. Neue Fotos landen automatisch zuhause auf dem Server.
|
||||
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.
|
||||
|
||||
> 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."
|
||||
@@ -134,18 +193,66 @@ Michi laesst es dich wissen, wenn ein Wartungsfenster geplant ist.
|
||||
|
||||
---
|
||||
|
||||
## Offene Inhalte (Operator-Notiz)
|
||||
## Erster Onboarding-Termin - Ablauf fuer Michi
|
||||
|
||||
Diese Punkte gehoeren in das Wochenend-Onboarding-Gespraech und sind nicht Teil dieser Familien-Seite:
|
||||
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.
|
||||
|
||||
| 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 |
|
||||
> 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").
|
||||
|
||||
## Bewusst nicht versprochen
|
||||
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,104 +0,0 @@
|
||||
# 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 |
|
||||
@@ -0,0 +1,117 @@
|
||||
# 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,8 +3,20 @@
|
||||
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.
|
||||
@@ -19,7 +31,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/MIGRATION_LOG.md` |
|
||||
| Flash-Backup | In Borg-Scope aufgenommen, siehe `docs/RESTORE_MATRIX.md` |
|
||||
|
||||
## CPU
|
||||
|
||||
@@ -96,7 +108,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 | TBD | TBD | TBD | TBD | TBD | Externe Rotation | offen |
|
||||
| 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 |
|
||||
|
||||
Pruefkommando:
|
||||
|
||||
@@ -138,18 +150,27 @@ Bewertung:
|
||||
|
||||
- Aktueller Befund 2026-05-26: keine funktionierende USV-Absicherung nachgewiesen.
|
||||
- `apcupsd` ist zwar auf dem System vorhanden, aber nicht aktiv.
|
||||
- Operator-Entscheidung 2026-05-26: aktuell keine USV-Anschaffung.
|
||||
- **Operator-Entscheidung 2026-06-05: USV-Anschaffung bewusst auf Q3/2026 geparkt.** Keine Beschaffung in diesem Quartal.
|
||||
- Power-Loss bleibt damit ein bewusst akzeptiertes Risiko fuer Docker-/DB-State und laufende Writes.
|
||||
- Review-Ausloeser: Hardware-Erweiterung, wiederholte Stromausfaelle, Datenkorruption oder Veraenderung der Betreiber-Prioritaet.
|
||||
- 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.
|
||||
|
||||
## 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 | TBD | externes Messgeraet erforderlich | TBD |
|
||||
| Normalbetrieb | TBD | externes Messgeraet erforderlich | TBD |
|
||||
| Backup-Lauf | TBD | externes Messgeraet erforderlich | TBD |
|
||||
| Last | TBD | externes Messgeraet erforderlich | TBD |
|
||||
| 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.
|
||||
|
||||
## Ersatzteil- und Lifecycle-Plan
|
||||
|
||||
@@ -160,7 +181,7 @@ Bewertung:
|
||||
| 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 | Risiko am 2026-05-26 bewusst akzeptiert; bei Review erneut bewerten |
|
||||
| USV | keine funktionierende USV-Abschaltung | Anschaffung 2026-06-05 bewusst auf Q3/2026 geparkt; Trigger: Hardware-Upgrade, realer Stromausfall mit Datenfolge, oder Q3-Review |
|
||||
|
||||
## Audit-Kommandos
|
||||
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,78 +0,0 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,87 @@
|
||||
# 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.
|
||||
@@ -1,660 +0,0 @@
|
||||
# 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-31 - Komodo Deploy-Drift strukturell abgesichert
|
||||
|
||||
Nach dem Renovate-Block wurde die Ursache fuer den kurzzeitigen `nextcloud-postgres`-Drift nachgezogen: Komodo hatte den `nextcloud`-Stack beim Postgres-17.10-Deploy gestartet, aber `docker compose up -d` scheiterte zunaechst an einem Docker-Recreate-Namenskonflikt (`nextcloud-postgres` Ersatzcontainer). Der Workspace war dadurch bereits auf dem neuen Commit, waehrend der laufende DB-Container noch das alte Image nutzte. Der spaetere gezielte `docker compose up -d` aus dem aktualisierten Workspace hat den Zwischenzustand sauber aufgeloest; es blieben keine exited/dead Containerreste.
|
||||
|
||||
- Komodo-Update-Historie bestaetigt: ein fehlgeschlagener `DeployStack` fuer `nextcloud` mit Compose-Up-Konflikt, danach ein erfolgreicher `DeployStack`.
|
||||
- Aktueller Runtime-Stand nach Pruefung: `nextcloud`, `nextcloud-postgres`, `nextcloud-redis`, `postgresql17`, `mealie-postgres`, `gitea`, `bentopdf`, `ddns-updater` und Komodo-Self-Stack laufen ohne `unhealthy`-Status; die erwarteten Images stimmen mit den Compose-Dateien ueberein.
|
||||
- `services/posture-check/export-prometheus-textfile.sh` exportiert jetzt `homelab_gitops_runtime_image_match{name,project,service}` fuer laufende Compose-Container. Die Metrik vergleicht das Image aus `docker compose config --format json` gegen `docker inspect .Config.Image` des laufenden Containers und faengt damit genau den Zustand "Workspace/Compose neu, Runtime alt" ab.
|
||||
- Neue Prometheus-Regel `HomelabGitOpsRuntimeImageDrift`: feuert als Warning, wenn ein laufender Compose-Container laenger als 10 Minuten nicht dem Compose-Image entspricht.
|
||||
- Smoke: Exporter-Test in `/tmp/kallilab-textfile-test/homelab.prom` lieferte fuer alle erkannten Compose-Container `homelab_gitops_runtime_image_match = 1`; `promtool check rules` meldete `SUCCESS: 17 rules found`.
|
||||
- Beim Live-Reload zeigte Prometheus nach dem Git-Pull einen `stale file handle` auf die bind-gemountete `alerts.yml`. Fix: nur `monitoring-prometheus` aus dem aktuellen Monitoring-Workspace per `docker compose up -d --force-recreate --no-deps prometheus` neu erstellt. Danach: `promtool check rules` erfolgreich, Lifecycle-Reload erfolgreich, Regel `HomelabGitOpsRuntimeImageDrift` geladen und `inactive`.
|
||||
|
||||
### 2026-05-31 - Renovate PRs #1 bis #5 gemerged und deployed
|
||||
|
||||
Die ersten fuenf Renovate-PRs wurden einzeln in `master` uebernommen, mit Policy-Check und Live-Smoke nach den Datenhalter-Aenderungen. Major-Branches wurden bewusst nicht gemerged.
|
||||
|
||||
- #1 `renovate/mongo-7.0.32`: Mongo-Digest fuer Komodo uebernommen, Merge-Commit `b8b0af9`.
|
||||
- #2 `renovate/postgres-17.9`: Postgres-17.9-Digest fuer `postgresql17`, `mealie-postgres` und `nextcloud-postgres` uebernommen, Merge-Commit `db1fa7c`.
|
||||
- #3 `renovate/minor-patch-updates`: gruppierte Minor-/Patch-Updates uebernommen, Merge-Commit `dde4419`. Danach wurden die Komodo-Workspaces `gitea`, `bentopdf` und `ddns-updater` wegen Drift gezielt gesichert, auf `origin/master` synchronisiert und neu deployed. Backups liegen unter `/mnt/user/appdata/komodo/_workspace_backups/*-workspace-before-renovate-pr3-resync-*.tar.gz`.
|
||||
- #4 `renovate/mongo-7.x`: Komodo-Mongo von `7.0.32` auf `7.0.34` gehoben, Merge-Commit `076676d`. Da der Komodo-Self-Stack nicht ueber einen normalen Git-Webhook redeployed, wurde vorher ein Compose-Backup (`/mnt/user/appdata/komodo/_workspace_backups/komodo-compose-before-renovate-20260531-125102.yaml`) und ein frischer Mongo-Dump (`/mnt/user/backups/borg/dumps/latest/komodo-mongo-pre-renovate-20260531-125102.archive.gz`) erstellt, danach der Self-Stack kontrolliert aktualisiert.
|
||||
- #5 `renovate/postgres-17.x`: Postgres von `17.9` auf `17.10` fuer `postgresql17`, `mealie-postgres` und `nextcloud-postgres` gehoben, Merge-Commit `96fcacc`. `postgresql17` und `mealie-postgres` wurden durch Komodo recreated; `nextcloud-postgres` musste aus dem bereits aktualisierten Workspace `/mnt/user/services/stacks/nextcloud/apps/nextcloud` einmal gezielt mit `docker compose up -d` nachgezogen werden.
|
||||
- `ops/policy-checks/check_repo.ps1` blieb nach den Merge-Commits ohne Criticals; einzige Warning ist weiterhin die dokumentierte InfluxDB-root-Ausnahme.
|
||||
- Smoke-Beleg nach Settle: `postgresql17` healthy auf `postgres:17.10@sha256:0027bef...`, `mealie-postgres` und `nextcloud-postgres` laufen auf demselben `17.10`-Digest, `mealie.kaleschke.info` HTTP `200`, `cloud.kaleschke.info` HTTP `302`, `git.kaleschke.info` HTTP `200`, `komodo.kaleschke.info` HTTP `200`, keine `unhealthy` Container.
|
||||
- Gitea listete #1 bis #5 nach den lokalen Merge-Commits noch als offen. Jeder PR bekam per API einen Kommentar mit dem manuellen Merge-Commit und wurde geschlossen, damit Renovate keinen offenen Altstand behaelt.
|
||||
- Watchpoint: Renovate-Branches `mongo-8.x`, `postgres-18.x`, `redis-8.x` und `major-major-updates` bleiben bewusst ungemerged und brauchen separate Operator-Entscheidung.
|
||||
|
||||
### 2026-05-31 - Gitea Komodo-Workspace-Drift bereinigt
|
||||
|
||||
Der Komodo-Workspace fuer den `gitea`-Stack unter `/mnt/user/services/stacks/gitea` war auf `1d0cba9` stehengeblieben, 70 Commits hinter `origin/master`, mit 23 untracked Pfaden. Dadurch war die von Docker genutzte Compose-Datei nicht identisch mit dem aktuellen Repo-Stand (`core/gitea/docker-compose.yml`), obwohl der Gitea-Komodo-Webhook aktiv war.
|
||||
|
||||
- Vor der Bereinigung wurde der komplette Workspace gesichert: `/mnt/user/appdata/komodo/_workspace_backups/gitea-workspace-before-resync-20260531-122515.tar.gz`.
|
||||
- Die untracked Pfade wurden einzeln gegen `origin/master` geprueft. 18 Eintraege waren byte-identisch, vier Doku-Dateien waren aeltere Zwischenstaende, und `ops/h-drive-nearline/pull-critical-backups.ps1` war ebenfalls identisch. Es gab keinen nur-im-Workspace-gueltigen neueren Arbeitsstand.
|
||||
- Danach wurden nur die bekannten untracked Konfliktpfade aus dem Workspace entfernt und `git pull --ff-only origin master` ausgefuehrt. Ergebnis: `stacks/gitea` steht sauber auf `e6a0e9f`, `## master...origin/master`, ohne Dirty-State.
|
||||
- `docker compose up -d` aus `/mnt/user/services/stacks/gitea/core/gitea` lief ohne Recreate-Zwang; der laufende Container nutzt weiterhin den Stack-Workspace als Compose-Quelle und ist `healthy`.
|
||||
- Smoke-Test: `docker exec gitea wget -qO- http://localhost:3000/api/healthz` liefert `status: pass`, `https://git.kaleschke.info` liefert HTTP `200`, und die lokale Gitea-API fuer `Micha/homelab-infra` antwortet mit `default_branch: master`.
|
||||
- Watchpoint: Gitea ist ein Henne-Ei-Stack, weil der Dienst sein eigenes Git-Origin bereitstellt. Webhook und `auto_pull` sind aktiv, aber Workspace-Drift muss bei kuenftigen Gitea-Aenderungen besonders bewusst geprueft werden; kein pauschales `git clean -fd` ohne vorherige Sicherung und Vergleich.
|
||||
|
||||
### 2026-05-31 - Komodo 5xx-Spam eingegrenzt: LAN-Client statt Stack-Fehler
|
||||
|
||||
`HomelabTraefik5xx` feuerte fuer `service="komodo@docker"`, weil wiederkehrende Komodo-UI-API-Requests ohne gueltige Session (`GET /user`, zeitweise `POST /read/GetCoreInfo`) von Traefik als 500 gezaehlt wurden. Komodo Core selbst loggte keine internen Fehler; die 500-Antwort ist ein Komodo-Auth-Pfad-Bug-on-top, aber nicht die primaere Betriebsstoerung.
|
||||
|
||||
- Bestaetigt: Blackbox-Exporter erklaert nur `GET /` alle 15s. Waehrend `monitoring-blackbox-exporter` gestoppt war, verschwanden die `/`-200-Probes, `/user`-500 lief aber weiter.
|
||||
- Ausgeschlossen: `cert-token-check.sh` prueft keine Komodo-Domain; Komodo Periphery war nach 130s Stop nicht die Quelle; Glance war bereits vorab durch Stop-Test ausgeschlossen.
|
||||
- Core-Isolation: Bei gestopptem `komodo-core` liefen die Client-Requests weiter, aber Traefik loggte sie als 404 ohne `komodo@docker`-Service. Nach Core-Start wurden dieselben Requests wieder zu `komodo@docker`-500. Damit ist die Quelle ein LAN-/Client-Geraet, nicht Komodo Core als Self-Poll.
|
||||
- Lokale Client-Suche: Auf dem Windows-Operator-PC `192.168.178.103` bestanden HTTPS-Verbindungen zur WAN-IP `217.249.121.39`. Brave war zunaechst plausibel, weil die Brave-Session alte Komodo-Tabs enthielt; ein Brave-Schluss beendete den 5xx-Takt jedoch nicht. Danach blieb als lokaler Kandidat nur `Codex.exe` mit Verbindung zur WAN-IP. Der in-app Browser zeigte keine offene Seite, daher ist der operative Fix: Codex-App/Thread nach Abschluss schliessen bzw. neu starten; falls der Takt danach wider Erwarten weiterlaeuft, naechster Schritt ist LAN-Geraetesuche am Router/Switch statt Repo-Aenderung.
|
||||
- Kein Repo-/Komodo-Fix umgesetzt: Monitoring-Regel und Komodo-Compose bleiben unveraendert. Ein Alert-Exclude fuer `komodo@docker` waere nur ein letzter Ausweg und wurde nicht gesetzt.
|
||||
- Smoke-Beleg waehrend der Eingrenzung: `traefik`, `komodo-core`, `komodo-periphery`, `komodo-mongo` und `monitoring-blackbox-exporter` liefen nach den Stop/Start-Tests wieder; `komodo-mongo` und `traefik` waren healthy.
|
||||
|
||||
### 2026-05-30 - Komodo-Bootstrap-Trockenlauf Erstlauf (F-09 Rest abgeschlossen)
|
||||
|
||||
Skript ist seit 2026-05-29 vorbereitet, heute erster echter Lauf auf dem Host.
|
||||
|
||||
- Aufruf: `bash /mnt/user/services/homelab-infra/ops/restore-tests/komodo-bootstrap-test.sh --keep-data`
|
||||
- Vorlauf: `--what-if` zur Plan-Verifikation, danach echter Lauf, beides ohne Eingriff in den produktiven Komodo-Stack.
|
||||
- Ergebnis: `SUCCESS`, alle 5 Smoke-Checks gruen.
|
||||
- `docker compose config valid: ok`
|
||||
- `Test-Mongo healthy: ok` (Mongo healthy in ~6 s)
|
||||
- `Mongo authenticated ping (Test-Creds): ok`
|
||||
- `Komodo Core HTTP status: 200` (Login-Seite ausgeliefert)
|
||||
- `Test-Periphery container state: running`
|
||||
- Report: `/mnt/user/backups/restore-reports/komodo-bootstrap-2026-05-30.md`
|
||||
- Isolation hielt wie geplant: produktive Container `komodo-mongo`, `komodo-core`, `komodo-periphery` unter Project `komodo` blieben unangetastet, ebenso `/mnt/user/appdata/komodo/{mongo,core,periphery}` und die produktiven `KOMODO_*`-Secrets. Test lief unter Project `restoretest-komodo` mit Wegwerf-Datadir `/mnt/user/backups/restore-lab/komodo/`, Wegwerf-Secrets im Test-Compose und Test-Port nur auf `127.0.0.1:19120`.
|
||||
- Operator-Klick bewusst nicht von Claude uebernommen: `ssh root@kallilabcore` ist eine Aktionsklasse, die in CLAUDE.md ausdruecklich Operator-Anweisung verlangt. Der Auto-Mode-Classifier hat einen nicht-destruktiven SSH-Probe entsprechend blockiert. Der Operator hat den Befehl im Unraid-Webterminal selbst gestartet.
|
||||
- Bedeutung: `ops/komodo/docker-compose.yml` ist als Recovery-Anker fuer die Bootstrap-Stufen A-F in `docs/SERVICES_RECOVERY.md` jetzt **belegt** tauglich, nicht mehr nur angenommen tauglich. Image-Digests (mongo:7.0.32, komodo-core:2, komodo-periphery:2) und Mongo-Auth-Schema sind verifiziert.
|
||||
- Lab-Daten unter `/mnt/user/backups/restore-lab/komodo/` bleiben mit `--keep-data` erhalten, Test-Container wurden im EXIT-Trap sauber abgeraeumt. Operator entscheidet, ob das Lab-Verzeichnis (~300 MB) entfernt wird.
|
||||
|
||||
Folgeschritt fuer `docs/RESTORE_DRILL_ROUTINE.md`: Komodo-Bootstrap-Trockenlauf passt zum quartalsweisen DR-Sanity-Check (Q4) oder als wiederholbarer Standalone-Drill. Aktuell kein Host-Schedule, Aufruf bleibt manuell.
|
||||
|
||||
### 2026-05-30 - F-10: Authelia Repo<->Host Drift-Check
|
||||
|
||||
Der dokumentierte "by-design"-Drift zwischen `security/authelia/configuration.yml` (Repo-Baseline) und `/mnt/user/appdata/authelia/config/configuration.yml` (Host) wird jetzt automatisch ueberwacht. Vorher: Manueller Merge auf den Host war Pflicht, aber keine Pruefung. Eine vergessene ACL-Synchronisation waere erst bei einem Login-Fehler aufgefallen.
|
||||
|
||||
- Neues Skript `services/authelia-diff.sh`: extrahiert die `access_control:`-Sektion aus beiden YAMLs per awk-Block-Extractor (Top-Level-Key bis zum naechsten Top-Level-Key), normalisiert Kommentar- und Leerzeilen, vergleicht via `diff -u`. Default-Sektion ist `access_control`, weil das laut F-10 der primaere Drift-Vektor ist; per env `AUTHELIA_DIFF_SECTIONS` koennen weitere Top-Level-Sektionen (`session`, `regulation`, `totp`, ...) ergaenzt werden. OIDC-Clients, Identity-Provider und Secret-Werte bleiben bewusst aussen vor.
|
||||
- Exit-Code-Schema: 0 = ok, 1 = Drift (Diff auf stdout), 2 = Datei fehlt, 3 = Sektion fehlt, 4 = Werkzeug fehlt. Macht das Skript auch standalone nutzbar (`ssh kallilab "bash /mnt/user/services/homelab-infra/services/authelia-diff.sh"`).
|
||||
- `services/posture-check/posture-check.sh` ruft das Skript am Ende des Checks-Blocks auf (`check_authelia_config_drift`). Drift wird als **Warning** gemeldet, nicht Critical, weil die produktive Authelia trotz Drift weiter laeuft und die ACL fuer schon angemeldete Sessions weiter wirkt. Skip-Mechanismus: `SKIP_AUTHELIA_DRIFT=1`. Pfad-Override: `AUTHELIA_DIFF_SCRIPT`.
|
||||
- Pflicht-Setup auf dem Host: Repo-Spiegel unter `/mnt/user/services/homelab-infra/` als read-only-Clone von Gitea `Micha/homelab-infra` mit regelmaessigem `git pull --ff-only`. Default-Pfade des Skripts setzen das voraus. Ohne Repo-Spiegel meldet der Check Warning, weil die Baseline-Datei fehlt - keine stille Inaktivierung.
|
||||
- Lokaler Smoke-Test 2026-05-30 erfolgreich: identische Files -> rc=0; ACL-Drift im Domain-Eintrag `scrutiny.kaleschke.info -> scrutiny-renamed.kaleschke.info` -> rc=1 mit unified diff, ACL-Block korrekt extrahiert, Kommentar- und Leerzeilen rausgefiltert. False-Positive auf `session.default_redirection_url`-Aenderung korrekt vermieden (gehoert nicht zu `access_control`).
|
||||
- `docs/WORKFLOW.md` hat jetzt eine eigene Sektion "Ausnahme: Authelia configuration.yml" analog zur Traefik-Dynamic-Sektion. Pflicht-Workflow: 1. Repo-Aenderung + Commit + Push, 2. manueller Merge in die Host-Datei mit Erhalt der OIDC-Sektionen, 3. `docker restart authelia` + Login-Smoke-Test, 4. `services/authelia-diff.sh` muss `exit 0` liefern.
|
||||
- `docs/REPO_MAP.md` und `docs/SERVICE_CATALOG.md` zeigen das Skript und den neuen Posture-Check-Eintrag.
|
||||
|
||||
Operator-Folgeschritt (klein, nicht heute): Repo-Spiegel `/mnt/user/services/homelab-infra/` auf dem Host einrichten und in den vorhandenen `gitea-bundle-mirror-6h`-Plan oder einen eigenen 6h-Cron einbinden, damit das Skript einen aktuellen Vergleichsstand findet.
|
||||
|
||||
### 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 (live)**
|
||||
|
||||
- Repo-Config in `renovate.json` (Repo-Root): nur extends, packageRules, ignorePaths, manager file patterns, labels, rangeStrategy. Bot-Config separat in `ops/renovate/bot-config.js`: platform, endpoint, autodiscover=false, repositories=["Micha/homelab-infra"], gitAuthor, Concurrent-Limits. Trennung war noetig: Renovate liest die `renovate.json` im Repo als REPO-Config; Bot-Felder darin wurden als "this repo is disabled" fehlinterpretiert (Repository result: forbidden, status: disabled).
|
||||
- `ops/renovate/run-renovate.sh` als One-Shot-Container-Wrapper. Wichtige Haertungen waehrend des Setups:
|
||||
- `--add-host git.kaleschke.info:192.168.178.58`: Renovate-Container kann den Hostname sonst nicht aufloesen (`EAI_AGAIN`). Analog zur `extra_hosts`-Loesung in der Komodo-Compose.
|
||||
- `--env-file` statt `-e RENOVATE_TOKEN=...`: Token war sonst in `ps` und `docker inspect` sichtbar.
|
||||
- `chmod 0777` auf `/mnt/user/services/renovate/state`: Renovate-Image laeuft als uid 12021 (ubuntu), kann root-owned Mount sonst nicht beschreiben.
|
||||
- Live-Setup am Host:
|
||||
- Service-Account `renovate` (uid 2, **kein Admin**) ueber `gitea admin user create` angelegt.
|
||||
- Collaborator-Status mit Write-Permission auf `homelab-infra` (initialer DB-Insert hat den Gitea-Permissions-Cache nicht aktualisiert; Renovate sah `permissions.push=false` und brach mit "Repository does not permit pull or push" ab; saubere Loesung war Operator-UI-Klick "Entfernen + neu hinzufuegen", was den Cache konsistent aktualisiert; Befund-Bestaetigung via Doku-Studium `lib/modules/platform/gitea/index.ts`: die Push-Check ist hardcoded, kein Bypass moeglich).
|
||||
- Personal-Access-Token mit Scopes `read:user,write:repository,write:issue`, in `/mnt/user/appdata/secrets/renovate_token.txt` (chmod 600). Token wurde einmal rotiert, weil der Wert beim ersten Erzeugen im SSH-Output sichtbar war.
|
||||
- User-Script `renovate-six-hourly` mit Cron `20 */6 * * *` live in `/etc/cron.d/root`.
|
||||
- Erstlauf 2026-05-29 erfolgreich: 5 PRs (mongo digest, mongo 7.0.32->7.0.34, postgres digest, postgres 17.9->17.10, minor-and-patch-updates gruppiert), 1 Issue "Renovate Dependency Dashboard", 8 Branches (drei Major-Branches warten auf naechsten Lauf wegen prConcurrentLimit=5). Komodo-Major-Updates wurden korrekt durch packageRule unterdrueckt.
|
||||
- `docs/RENOVATE.md` zeigt die ursprueglichen 5 Operator-Schritte fuer Neuaufsetzen bzw. Disaster Recovery.
|
||||
|
||||
### 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.
|
||||
+295
-30
@@ -1,7 +1,7 @@
|
||||
# Network Inventory - KalliLab CORE
|
||||
|
||||
Status: Host-Audit erfasst; Router-Baseline und Portfreigaben-UI geprueft; VLAN/IPv6-Details offen.
|
||||
Letzte Pruefung: 2026-05-27
|
||||
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)
|
||||
|
||||
## 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.21 (Update gemeldet, nicht eingespielt) |
|
||||
| Firmware | FRITZ!OS 8.25 (`154.08.25` per TR-064 am 2026-06-01) |
|
||||
| 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 | TBD (FRITZ!Box-UI separat pruefen) |
|
||||
| IPv6 aktiv | Windows-Client hat Provider-IPv6; Host hat keine globale Provider-IPv6, nur Tailscale-ULA |
|
||||
| DynDNS / DDNS | Cloudflare via `ddns-updater` (kein FRITZ!Box-DynDNS in Nutzung) |
|
||||
| Heimnetz-Geraete (FRITZ!Box-UI) | 36 aktive Geraete |
|
||||
| Heimnetz-Geraete (FRITZ!Box-UI) | 35 aktive Geraete |
|
||||
| LAN-Ports belegt | LAN 1-4 verbunden |
|
||||
| Telefonie / DECT | aktiv |
|
||||
| USB an FRITZ!Box | nicht verbunden |
|
||||
@@ -30,7 +30,8 @@ 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 8.21 hat ein angezeigtes Update; Einspielung ist Betreiber-Aufgabe und nicht Teil des Repos.
|
||||
- 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.
|
||||
|
||||
## DNS
|
||||
|
||||
@@ -43,28 +44,168 @@ Dieses Dokument beschreibt Router, DNS, Tailscale, Portfreigaben und Netztrennun
|
||||
|
||||
## Tailscale
|
||||
|
||||
| Feld | Wert |
|
||||
Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`,
|
||||
`tailscale status --json`, `tailscale ip -4/-6`).
|
||||
|
||||
| Feld | Wert / Status |
|
||||
|---|---|
|
||||
| Node-Name | Kallilabcore |
|
||||
| Tailscale IPv4 | 100.80.98.33 |
|
||||
| Tailscale IPv6 | TBD |
|
||||
| Exit Node | TBD |
|
||||
| Subnet Router | TBD |
|
||||
| ACL-Policy extern dokumentiert | TBD |
|
||||
| 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. |
|
||||
|
||||
Pruefkommando:
|
||||
### 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):
|
||||
|
||||
```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 2026-05-28:
|
||||
Aktiver Soll-Stand nach Operator-Bereinigung und UI-Gegencheck 2026-06-01:
|
||||
|
||||
| Aktive Freigabe | Ziel | Zweck | Bemerkung |
|
||||
|---|---|---|---|
|
||||
@@ -76,25 +217,26 @@ 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-05-28 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-06-01 erneut geprueft und 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 in `docs/MIGRATION_LOG.md` und hier als bewusste Ausnahme dokumentiert oder pro Geraet wieder deaktiviert.
|
||||
Sollten neue Geraete UPnP-Selbstfreigaben anfordern, wird das hier als bewusste Ausnahme dokumentiert oder pro Geraet wieder deaktiviert.
|
||||
|
||||
Aktueller UI-Befund vom 2026-05-27 (`Internet -> Freigaben -> Kallilabcore`):
|
||||
Historischer UI-Befund vor Bereinigung vom 2026-05-27 (`Internet -> Freigaben -> Kallilabcore`):
|
||||
|
||||
| Beobachtung | Bewertung |
|
||||
|---|---|
|
||||
| `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 |
|
||||
| `HTTP-Server`, TCP, extern `80/tcp` auf `192.168.178.58` | war Abweichung; **2026-05-28 entfernt** |
|
||||
| `HTTPS-Server`, TCP, extern `443/tcp` auf `192.168.178.58` | entspricht Repo-Soll |
|
||||
| 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 |
|
||||
| Keine `222/tcp`-Freigabe sichtbar | entspricht seit 2026-05-28 dem Soll: Gitea-SSH bleibt Tailscale-only |
|
||||
| Kallilabcore: keine selbststaendige Portfreigabe, kein IPv4-/IPv6-Exposed-Host sichtbar | entspricht Sicherheitsziel |
|
||||
| `PC-192-168-178-71`: selbststaendige Portfreigabe erlaubt, `0 aktiv` | keine aktive Freigabe, aber UPnP/PCP-Erlaubnis sollte bei Gelegenheit deaktiviert werden |
|
||||
| `PC-192-168-178-71`: selbststaendige Portfreigabe erlaubt, `0 aktiv` | **2026-06-01 deaktiviert**; danach nur noch `Kallilabcore` in der Portfreigabenliste sichtbar |
|
||||
|
||||
### Host (lokal beobachtbar)
|
||||
|
||||
@@ -102,10 +244,11 @@ Aktueller UI-Befund vom 2026-05-27 (`Internet -> Freigaben -> Kallilabcore`):
|
||||
|---:|---|---|---|
|
||||
| 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 | WAN-Freigabe in FRITZ!Box erwartet, dokumentierte Ausnahme |
|
||||
| 222/tcp | Gitea SSH | Git SSH | nur LAN/Tailscale; keine WAN-Freigabe |
|
||||
| 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 | LAN Writer fuer Home Assistant | LAN-only, Bind-IP pruefen |
|
||||
| 8181/tcp | InfluxDB 3 Core | Home Assistant / Ecowitt Writer | 2026-05-31 effektiv nur `127.0.0.1:8181`, nicht LAN-exponiert |
|
||||
|
||||
Pruefkommando:
|
||||
|
||||
@@ -118,9 +261,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 36 aktive Geraete |
|
||||
| LAN | 192.168.178.0/24 | Hauptnetz, Host `192.168.178.58`, FRITZ!Box meldet 35 aktive Geraete |
|
||||
| WLAN 2,4 / 5 GHz | aktiv, SSID `Fritzi` | Standard-WLAN, im LAN-Adressbereich, kein eigener Adressraum |
|
||||
| Gast-WLAN | **inaktiv** (FRITZ!Box-UI) | Solange inaktiv: kein Gast-Pfad zu LAN-Diensten; AdGuard-Admin-Trennung primaer ueber Tailscale-Bind statt Netzsegmentierung |
|
||||
| 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 |
|
||||
| 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 |
|
||||
@@ -145,14 +288,136 @@ 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-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 |
|
||||
| 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". |
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,140 +0,0 @@
|
||||
# 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 |
|
||||
@@ -0,0 +1,73 @@
|
||||
# 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/`.
|
||||
@@ -1,89 +0,0 @@
|
||||
# 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.
|
||||
+32
-8
@@ -1,7 +1,7 @@
|
||||
# Renovate Bot - Self-hosted gegen Gitea
|
||||
|
||||
Status: **vorbereitet 2026-05-29**; PAT-Setup und Cron-Aktivierung sind Operator-Schritte.
|
||||
Audit-Bezug: `docs/AUDIT_2026-05-25.md` Finding **F-12**.
|
||||
Status: **live seit 2026-05-29**; PAT, State-Verzeichnis und Cron sind auf dem Host aktiv.
|
||||
Audit-Bezug: Mai-2026-Audit 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 (User-Script `renovate-six-hourly`)
|
||||
- **Schedule:** alle 6 Stunden per Unraid User-Script `renovate-six-hourly` (`20 */6 * * *`)
|
||||
- **Plattform:** Gitea via `https://git.kaleschke.info/api/v1`
|
||||
- **Authentifizierung:** Gitea-PAT als Host-Secret-Datei
|
||||
- **Konfiguration:** `renovate.json` im Repo-Root
|
||||
|
||||
## Operator-Setup (einmalig, ~10 Minuten)
|
||||
## Operator-Setup (historisch, einmalig)
|
||||
|
||||
### Schritt 1 - Service-Account in Gitea
|
||||
|
||||
@@ -87,19 +87,43 @@ 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, pgvecto-rs) | `groupName: null`, eigener Label | Einzelne PRs ohne Group, hoehere Sichtbarkeit |
|
||||
| Tier-1-Datenhalter (Postgres, Mongo, Redis, Immich-Postgres) | `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` | Renovate scant alte/abgeloeste Stacks nicht |
|
||||
| Ignore-Pfade | `_archive`, `ops/grafana-influxdb`, `ops/loki`, `ops/komodo` | Renovate scant alte/abgeloeste Stacks nicht; `ops/komodo` ist bewusst raus (siehe unten) |
|
||||
|
||||
## Erwartete erste PRs
|
||||
## 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)
|
||||
|
||||
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, pgvecto-rs - 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, Immich-Postgres - 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.
|
||||
|
||||
|
||||
+46
-243
@@ -1,260 +1,63 @@
|
||||
# Repository Map
|
||||
|
||||
Stand: 2026-05-23
|
||||
Stand: 2026-05-31
|
||||
|
||||
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.
|
||||
Kurzkarte des Repositories. Diese Datei ist bewusst kein zweites Handbuch; fuer
|
||||
Details gilt immer die betroffene Compose-Datei oder das jeweilige Runbook.
|
||||
|
||||
Secret-Werte werden hier nicht dokumentiert. Aufgefuehrt werden nur Variablennamen, Secret-Namen und Pfade.
|
||||
|
||||
## Ordnerstruktur
|
||||
## Top-Level
|
||||
|
||||
| Pfad | Zweck |
|
||||
|---|---|
|
||||
| `apps/` | Produktive Anwendungen und vorbereitete App-Stacks |
|
||||
| `apps/` | produktive Anwendungen und vorbereitete App-Stacks |
|
||||
| `core/` | Basisdienste, aktuell Gitea |
|
||||
| `docs/` | Betriebsdokumentation, Restore, Rollback, GitOps-Regeln |
|
||||
| `env/` | globale nicht geheime Beispiel-Env-Dateien |
|
||||
| `host-services/` | Host-nahe Dienste mit direkten Ports oder Host-Netz |
|
||||
| `docs/` | aktive Betriebsdoku, Restore, Inventare, Arbeitsregeln |
|
||||
| `env/` | nicht geheime Beispiel-Env-Dateien |
|
||||
| `host-services/` | host-nahe Dienste mit direkten Ports oder Host-Netz |
|
||||
| `infra/` | technische Infrastruktur wie PostgreSQL, Redis, DDNS |
|
||||
| `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 |
|
||||
| `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 |
|
||||
|
||||
## Wichtige Dokumente
|
||||
## Einstiegspunkte
|
||||
|
||||
| Datei | Bedeutung |
|
||||
| Datei | Wann lesen |
|
||||
|---|---|
|
||||
| `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/STRATEGISCHE_BEWERTUNG_2026-05-23.md` | Historische Baseline-Bewertung; hat den Audit-Zyklus 2026-05-25 angestossen |
|
||||
| `docs/CODEX_KONSOLIDIERUNG_2026-05-23.md` | Codex-Erstprompt zum Audit-Zyklus, abgearbeitet; Vorlage fuer kuenftige Sweeps |
|
||||
| `docs/CODEX_JELLYFIN_REMOVAL_2026-05-23.md` | Codex-Removal-Pattern, Jellyfin-Removal 2026-05-25 ausgefuehrt; Vorlage fuer kuenftige Stack-Removals |
|
||||
| `ops/policy-checks/mem-limits-baseline.md` | F-19 Vorbereitungs-Plan fuer Container-Mem-Limits; bewusst nicht vor 7 Tagen Peak-Beobachtung |
|
||||
| `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 |
|
||||
| `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 |
|
||||
|
||||
## Relevante Nicht-Compose-Dateien
|
||||
## Wichtige Skripte
|
||||
|
||||
| Datei | Zweck / Hinweis |
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `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, Authelia-Repo<->Host-Drift und ntfy-Alarmierung |
|
||||
| `services/posture-check/export-prometheus-textfile.sh` | Host-seitiger Textfile-Exporter fuer Borg-, Critical-Container- und GitOps-Runtime-Image-Drift-Metriken |
|
||||
| `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` |
|
||||
| `services/authelia-diff.sh` | Vergleicht `access_control:`-Sektion zwischen Repo-Baseline und Host-Datei; wird vom Posture-Check als Check `authelia_config_drift` aufgerufen |
|
||||
| `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 |
|
||||
| `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 |
|
||||
|
||||
## Stack-Inventar
|
||||
## Doku-Regeln
|
||||
|
||||
### 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/export-prometheus-textfile.sh` | Unraid Host, Cron/Textfile-Collector | schreibt Borg-, Critical-Container- und GitOps-Runtime-Image-Drift-Metriken fuer Prometheus |
|
||||
| `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`.
|
||||
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.
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
# 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 (teilweise erledigt, Rest vor Quartalsende 2026-06-30):
|
||||
- Komodo-Bootstrap-Pfad: **erledigt 2026-05-30** durch echten Trockenlauf via `ops/restore-tests/komodo-bootstrap-test.sh --keep-data`, Report `/mnt/user/backups/restore-reports/komodo-bootstrap-2026-05-30.md`, `ops/komodo/docker-compose.yml` als Recovery-Anker belegt.
|
||||
- Gitea-Bundles ueber `ops/borg-ui/scripts/gitea-bundle-mirror.sh` auf Frische und Bundle-Klonbarkeit pruefen: offen.
|
||||
- Secrets-Inventur gegen `docs/SECRETS_MAP.md` abgleichen: offen.
|
||||
|
||||
### 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.
|
||||
@@ -1,206 +0,0 @@
|
||||
# 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`
|
||||
+78
-19
@@ -28,15 +28,23 @@ 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 |
|
||||
| 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 |
|
||||
| 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` |
|
||||
| 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`, `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 |
|
||||
| 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` |
|
||||
|
||||
---
|
||||
|
||||
@@ -44,14 +52,17 @@ 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 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 |
|
||||
| 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` |
|
||||
| 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` | Traefik, Paperless | UI startet, Konfiguration vorhanden |
|
||||
| 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 |
|
||||
|
||||
---
|
||||
|
||||
@@ -69,6 +80,8 @@ 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 |
|
||||
|
||||
@@ -97,6 +110,14 @@ 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
|
||||
@@ -117,13 +138,51 @@ Die Dump-Erzeugung ist host-seitig ueber `ops/borg-ui/scripts/pre-backup-dumps.s
|
||||
|
||||
---
|
||||
|
||||
## Erste sinnvolle Referenz-Restores
|
||||
## Restore-Test-Reifegrad
|
||||
|
||||
Wenn weitere Restore-Uebungen dokumentiert werden sollen, sind diese Dienste besonders geeignet:
|
||||
Stand 2026-06-06. Pro Dienst auf einen Blick: Wurde der Restore schon einmal real getestet?
|
||||
|
||||
1. `mail-archiver`
|
||||
2. `paperless-ngx`
|
||||
3. `gitea`
|
||||
4. `vaultwarden`
|
||||
| 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 |
|
||||
|
||||
Sie liefern hohen Erkenntnisgewinn ohne den kompletten Homelab-Neuaufbau zu brauchen.
|
||||
---
|
||||
|
||||
## 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`.
|
||||
|
||||
+14
-63
@@ -1,6 +1,10 @@
|
||||
# Rollback Guide - Homelab
|
||||
# Rollback Guide - Homelab
|
||||
|
||||
Typ: Runbook · Stand: 2026-06-11 · Status: aktiv
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -72,59 +76,14 @@ 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
|
||||
|
||||
## BentoPDF / Stirling-PDF Rollback
|
||||
## Monitoring-Stack Rollback
|
||||
|
||||
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:
|
||||
`monitoring/` ist der einzige Observability-Stack. Bei Problemen:
|
||||
|
||||
1. `monitoring` in Komodo stoppen oder auf den letzten funktionierenden Commit zurueckgehen
|
||||
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
|
||||
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
|
||||
|
||||
---
|
||||
|
||||
@@ -132,19 +91,11 @@ Nach einem Deploy:
|
||||
|
||||
Bevorzugte Quellen:
|
||||
|
||||
- Borg-Restore
|
||||
- erzeugte PostgreSQL-/MariaDB-Dumps
|
||||
- bekannte Appdata-Snapshots
|
||||
- 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/`
|
||||
|
||||
Beispiele:
|
||||
|
||||
```bash
|
||||
cp -r /mnt/user/appdata/<service> /mnt/user/backup/
|
||||
```
|
||||
|
||||
```bash
|
||||
pg_dumpall > /mnt/user/backup/pg_dump_$(date +%Y%m%d).sql
|
||||
```
|
||||
Dienst-spezifische Restore-Quellen, Dumps und Smoke-Tests stehen in `docs/RESTORE_MATRIX.md`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+24
-6
@@ -17,13 +17,15 @@ 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 17 | DB Password | `/mnt/user/appdata/secrets/postgres_password.txt` -> `POSTGRES_PASSWORD_FILE` | aktiv |
|
||||
| PostgreSQL 18 | 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 |
|
||||
@@ -38,7 +40,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}` | 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 |
|
||||
| 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 |
|
||||
@@ -51,8 +53,16 @@ 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 |
|
||||
| Home Assistant -> InfluxDB | HA InfluxDB Token | `/homeassistant/secrets.yaml` -> `influxdb3_homeassistant_token` | geplant |
|
||||
| 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) |
|
||||
| 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) |
|
||||
|
||||
---
|
||||
|
||||
@@ -89,6 +99,7 @@ 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
|
||||
```
|
||||
|
||||
@@ -101,6 +112,12 @@ 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -109,8 +126,7 @@ 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. **Vaultwarden** (Operator-Eintrag pro Stack, sofern dort gepflegt).
|
||||
3. **Externe Operator-Notiz** (analoge Sicherung, vergleichbar mit der Borg-Passphrase).
|
||||
2. **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.
|
||||
|
||||
@@ -119,12 +135,14 @@ 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` | Provider-UIs (Immich, AdGuard, Speedtest-Tracker) neu erzeugen | rebuildbar; Widgets bleiben leer bis Tokens neu erzeugt sind, kein kritischer Datentopf |
|
||||
| `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. |
|
||||
|
||||
### Komodo-Sonderfall
|
||||
|
||||
|
||||
@@ -140,7 +140,10 @@ Erst nach erfolgreichem Komodo-Bootstrap werden produktive Stacks ueber den doku
|
||||
|
||||
### Trockenlauf (als Repo-Skript, bestaetigt)
|
||||
|
||||
Trockenlauf gegen Wegwerf-Pfade ist seit 2026-05-29 als Repo-Skript abgelegt: `ops/restore-tests/komodo-bootstrap-{compose.test.yml,test.sh,plan.md,runbook.md}`. Aufruf:
|
||||
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:
|
||||
|
||||
```bash
|
||||
bash /mnt/user/services/homelab-infra/ops/restore-tests/komodo-bootstrap-test.sh --what-if # nur Plan
|
||||
@@ -199,13 +202,4 @@ 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.
|
||||
|
||||
## 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 |
|
||||
| erledigt 2026-05-29 | Komodo-Trockenlauf-Skript in `ops/restore-tests/` analog zu Immich vorbereiten |
|
||||
| erledigt 2026-05-30 | Restore-Kommandos nach erstem Trockenlauf mit echten Pfaden ergaenzen |
|
||||
| erledigt | Services-Recovery in `docs/DISASTER_RECOVERY.md` verlinken |
|
||||
Offene Folgepunkte werden in `docs/MASTER_TODO.md` gefuehrt.
|
||||
|
||||
+27
-18
@@ -1,6 +1,6 @@
|
||||
# Service Catalog
|
||||
|
||||
Stand: 2026-05-23
|
||||
Stand: 2026-06-02
|
||||
|
||||
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,43 +13,44 @@ 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 | `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 |
|
||||
| `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 |
|
||||
| `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 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 |
|
||||
| `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 |
|
||||
|
||||
## Shared Infrastructure
|
||||
|
||||
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `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 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. |
|
||||
| `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. |
|
||||
| `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`, `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_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_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/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 |
|
||||
| `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 |
|
||||
| `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/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. |
|
||||
| `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. |
|
||||
| `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
|
||||
|
||||
@@ -65,7 +66,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`, `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`, `Homelab / Family Status`, `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 |
|
||||
@@ -74,16 +75,24 @@ 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` | 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 |
|
||||
| `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 |
|
||||
| `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` | 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` |
|
||||
| `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` |
|
||||
|
||||
## Backup- und Restore-Hinweise
|
||||
|
||||
|
||||
+4
-34
@@ -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 `docs/H_DRIVE_NEARLINE_PULL.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 `ops/h-drive-nearline/README.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,38 +380,8 @@ 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. Changelog
|
||||
## 18. Status
|
||||
|
||||
| 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 |
|
||||
Status: **Active v1.4 seit 2026-05-27**.
|
||||
|
||||
## 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.
|
||||
Detailhistorie und alte Review-Tabellen liegen in der Git-Historie. Aktuelle Folgepunkte stehen nicht mehr hier, sondern in `docs/MASTER_TODO.md`.
|
||||
|
||||
@@ -1,522 +0,0 @@
|
||||
# Strategische Bewertung KalliLab CORE
|
||||
|
||||
> **Status (Stand 2026-05-30): Historischer Snapshot vom 2026-05-23, inhaltlich grossteils ueberholt.**
|
||||
>
|
||||
> Dieses Dokument bleibt im Repo als Audit-Anker und als "wo standen wir am 2026-05-23". Die konkreten Befunde, Top-5-Listen und Mehrwert-Fahrplaene sind durch den Audit-Zyklus 2026-05-25 zu einem grossen Teil **abgearbeitet, bewusst nicht umgesetzt oder explizit geparkt**.
|
||||
>
|
||||
> - **Nicht als TODO-Liste lesen.** Aktuelle Arbeitsliste: `docs/AUDIT_2026-05-25_TODO.md`.
|
||||
> - **Originaltext nicht aendern.** Statt Inline-Annotationen steht der pro-Punkt-Status in einer Tabelle am Ende des Dokuments (Abschnitt "Status-Anhang 2026-05-30").
|
||||
> - **Schulnote 2- gilt nicht mehr.** Mit den Konsolidierungen seit 2026-05-25 sind die meisten Notenabzieher behoben; eine neue Note wuerde hier eher bei 1- bis 2 landen, ist aber kein Selbstzweck.
|
||||
|
||||
Stand: 2026-05-23
|
||||
Bewertet von: externer Blick auf den Repo-Sollzustand
|
||||
|
||||
> Diese Bewertung ist bewusst kein Sicherheits- oder Konfigurations-Audit, sondern eine ganzheitliche Einordnung: was das Setup heute leistet, wo es stark ist, wo es zu komplex ist, und wo der nächste echte Mehrwert liegt.
|
||||
|
||||
---
|
||||
|
||||
## Vorbemerkung und Methode
|
||||
|
||||
Bewertet wurde der Repo-Stand auf `master`, nicht der Live-Zustand auf dem Host. Grundlage waren `HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/WORKFLOW.md`, `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md`, `docs/DISASTER_RECOVERY.md`, `docs/RESTORE_MATRIX.md`, `docs/SECRETS_MAP.md`, `docs/AI_CONTEXT.md`, `docs/GITOPS_DRIFT_RUNBOOK.md`, `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md`, `docs/ALERTING_MAP.md`, `ops/borg-ui/BACKUP_SCOPE.md`, `ops/policy-checks/last-report.md`, `ops/restore-tests/schedule.md`, repräsentative Compose-Dateien (Paperless, Monitoring) sowie die Memory-Notiz zum Post-Restore-Sprint.
|
||||
|
||||
Ehrliche Einschätzung in einem Satz: Das ist kein Bastel-Homelab mehr. Das ist eine kleine private Plattform mit dokumentationsbasierter Disziplin, die ein paar Lasten mitschleppt, die man jetzt bewusst loswerden sollte, bevor noch mehr dazukommt.
|
||||
|
||||
---
|
||||
|
||||
## 1. Architektur und Grundidee
|
||||
|
||||
Der Aufbau ist nicht gewachsen, er ist gestaltet. Das sieht man sofort an drei Stellen:
|
||||
|
||||
Erstens trennt das Repo Verantwortlichkeiten konsequent über die Top-Level-Ordner `core/`, `security/`, `infra/`, `apps/`, `ops/`, `host-services/`, `monitoring/`, `traefik/` und `services/`. Das ist keine willkürliche Kosmetik, das spiegelt die Tier-Hierarchie aus DR und Restore wider. Ein neuer Dienst weiß durch das Einordnungsschema in `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 6 sofort, wo er hin gehört und in welche Netze er kommt. Das ist überdurchschnittlich.
|
||||
|
||||
Zweitens ist das Netzmodell schlicht und gleichzeitig diszipliniert: `frontend_net` für alles mit Web-UI oder Internetbedarf, `backend_net` `internal: true` für DB/Redis, und app-interne Netze (`mealie_internal`, `immich_default`, `nextcloud_internal`, `monitoring_net`) für Stack-Isolation. Es gibt keine Kunstnetze wie `admin_net` oder `media_net` aus reiner Symmetriesucht. Das ist genau die Linie, die viele Homelabs verfehlen, weil sie entweder alles in ein Bridge-Netz werfen oder fünfzehn semantische Netze erfinden, ohne dass sie was tun.
|
||||
|
||||
Drittens ist die Source-of-Truth-Hierarchie explizit (Gitea Online → lokaler Clone → Komodo → Docker → Host) und es gibt ein Drift-Runbook (`docs/GITOPS_DRIFT_RUNBOOK.md`) mit echter Messreihenfolge. Das schlägt 95% der "Selfhoster mit Portainer und Glück".
|
||||
|
||||
**Wo es trotzdem hakt:** Die Trennung Monitoring/Spielerei ist noch nicht sauber. Es gibt `ops/grafana-influxdb` (Altstand), `ops/loki` (Altstand) und `monitoring/` (Zielstack) gleichzeitig im Repo. Solange die Migration nicht abgeschlossen und die Altstände nicht entfernt sind, ist das echte Doppelpflege-Risiko — und genau so entstehen die Bugs, die man nachher zwei Wochen sucht. Die Doku sagt klar "nicht parallel betreiben", aber das Repo macht es trotzdem möglich. Das ist eine offene Baustelle, kein Architekturproblem.
|
||||
|
||||
**Note für diesen Block: 1-2.**
|
||||
|
||||
---
|
||||
|
||||
## 2. Nutzen und Mehrwert
|
||||
|
||||
Hier wird es ehrlicher: Das Setup hat sehr viel Substanz, aber auch klare Spielereien.
|
||||
|
||||
Echter Alltagsnutzen, der den Aufwand rechtfertigt:
|
||||
|
||||
- **Vaultwarden** als Passwort-Tresor — der Klassiker, der wirklich täglich genutzt wird.
|
||||
- **Paperless-ngx** mit Scan-Inbox, Barcode/ASN-Workflow und Tika aus — das ist klassische Familien-Dokumentenverwaltung mit echtem Wert, sobald man Briefe digitalisiert. Die Barcode-Konfiguration (`PAPERLESS_CONSUMER_BARCODE_DPI=600`, `PAPERLESS_CONSUMER_ENABLE_ASN_BARCODE=1`) zeigt, dass der Workflow durchdacht ist.
|
||||
- **Immich** für Fotos, mit `family_archive`-Mount — das ersetzt sinnvoll Google Photos für eine Familie.
|
||||
- **Nextcloud** für Dateifreigabe und WebDAV/CardDAV — wenn das wirklich genutzt wird, ist es ein echtes Google-Drive/iCloud-Replacement.
|
||||
- **Mealie** für Rezepte — nett, aber das ist ein Lebensmittel-Ding, nicht Infrastruktur.
|
||||
- **Mail-Archiver** — sehr persönlicher Mehrwert, wenn IMAP-Archive aus GMX/Gmail langfristig durchsuchbar bleiben sollen.
|
||||
- **ntfy** als Push-Backbone für `homelab-alerts` und `homelab-info` — operativ unverzichtbar.
|
||||
- **Gitea** — primär als GitOps-Quelle. Für andere Projekte ein Bonus.
|
||||
- **AdGuard Home + Unbound** — ja, das hat Alltagsnutzen für alle Geräte im LAN.
|
||||
- **Tailscale** — Remote-Zugang ohne Port-Freigabe nach außen, klar wertvoll.
|
||||
|
||||
Spielerei oder Overengineering, das ehrlich auf den Prüfstand gehört:
|
||||
|
||||
- **Plex zusätzlich zu Jellyfin**: Beide sind Medienserver mit derselben Bibliothek (`/mnt/user/media`, `/mnt/user/photos`). Plex bringt zwar Remote-Streaming und bessere Clients, Jellyfin bringt native Open-Source-Auth und keine Lizenz. Einen davon kann man weglassen — die ehrlichste Antwort ist, das nach 30 Tagen Nutzungs-Tracking zu entscheiden.
|
||||
- **Glance + Homepage + Komodo-UI als drei parallele Dashboards**: Homepage als Startseite, Glance als zweites Dashboard mit Widgets, Komodo als Stack-Sicht. Hier ist mindestens eines redundant. Glance ist erst seit kurzem live und wirkt eher wie "weil cool" als "weil nötig".
|
||||
- **paperless-gpt**: Coole Idee (LLM für Tagging), aber wenn das nicht aktiv genutzt wird, ist es nur ein Container, der idle Ressourcen frisst. Frage an dich: Wann hast du das letzte Mal eine GPT-Vorschlags-Tag-Liste angenommen?
|
||||
- **BentoPDF**: Ist als "vorbereitet" markiert, Fachabnahme offen. Wenn du in zwei Monaten noch keine PDFs verarbeitet hast: weglassen.
|
||||
- **Hermes-Agent**: Das ist die eindeutigste Spielerei. Ein LLM-Agent über SSH-Runner zu einer separaten VM, mit eigenem Dashboard, dessen NAS-Seite bewusst deaktiviert ist, weil die VM-Seite "offen" ist. Komplexes Modell C, abhängig von einer dedizierten Linux-VM, mit Provider-Keys und Dashboard-Domain. Das ist klassisches Nerd-Lieblingsprojekt-ohne-klaren-Alltagsnutzen-Symptom. Solange du nicht ehrlich beschreiben kannst, was Hermes für dich täglich tut, ist es Reifegrad "Experiment".
|
||||
- **Speedtest-Tracker**: Nett für Monitoring der ISP-Qualität, aber ein einziger Speedtest-Container für eine private Leitung ist eher "ich messe gerne" als "ich brauche das wirklich".
|
||||
- **code-server**: Web-IDE im Browser. Sinnvoll, wenn du wirklich vom iPad aus arbeitest. Sonst: VSCode lokal reicht.
|
||||
|
||||
Use Cases, die echten Mehrwert hätten und fehlen:
|
||||
|
||||
- **Finanzen**: Im DR-Doc steht `/mnt/user/finance` als Share, aber kein App-Stack. Firefly III oder Actual Budget würden hier sofort spürbaren Alltagsnutzen liefern — Konten konsolidieren, Budgets verfolgen, Steuer-Vorbereitung.
|
||||
- **Familien-SSO**: Du hast Authelia, aber Authelia ist primär für Admin-UIs konfiguriert. Wenn deine Familie Nextcloud, Immich, Mealie und Vaultwarden mit einem Login nutzen könnte (Authelia OIDC-Provider), wäre das ein echter Mehrwert für andere als dich.
|
||||
- **Smartphone-Foto-Auto-Backup**: Immich kann das nativ. Wenn das nicht eingerichtet ist und alle Familien-Smartphones automatisch in `immich` landen würden, wäre das die Killer-App für deine Frau und Kinder, nicht für dich.
|
||||
- **Tagliche Familien-Übersicht auf einem Wandtablet**: Homepage oder Glance auf einem alten Tablet im Flur, mit Kalender (Nextcloud), Wetter (Ecowitt), und ntfy-Notifications.
|
||||
- **Kalender/Aufgaben/CardDAV-Nutzung**: Nextcloud kann das, aber ich sehe in der Doku keinen Hinweis, dass die Familie das tatsächlich nutzt. Wenn nicht: Migration weg von Google Calendar/iCloud wäre ein echter Souveränitäts-Gewinn.
|
||||
|
||||
**Note für diesen Block: 2-3.** Die infrastrukturelle Substanz ist top, aber der Anteil "Container läuft, weil ich ihn ausprobieren wollte" ist höher als nötig.
|
||||
|
||||
---
|
||||
|
||||
## 3. Best Practices
|
||||
|
||||
Was richtig gut ist gemessen an dem, was professionelle Setups machen würden:
|
||||
|
||||
- **Image-Pinning mit Tag und Digest** für Stateful Services (Postgres 17.9, Redis 7.4-alpine, Mongo 7.0.32, alle mit `@sha256:...`). Das machen die wenigsten Homelabs. Echt vorbildlich.
|
||||
- **Secrets via Docker `_FILE`-Mounts oder Komodo Stack ENV, niemals im Git** — und das ist konsequent durchgezogen, inklusive `.gitignore` für `.env`-Dateien und expliziter Doku in `docs/SECRETS_MAP.md`.
|
||||
- **`no-new-privileges:true`** als Standard, mit dokumentierten Ausnahmen für Scrutiny (SMART) und Glances (Host-Observability) statt versteckter Lockerungen.
|
||||
- **Policy-as-Code light** über `ops/policy-checks/check_repo.ps1` — der letzte Report zeigt 0 Critical und 4 dokumentierte Warnings. Das ist Tooling-Disziplin, die viele Firmen nicht haben.
|
||||
- **Restore-Tests mit Schedule** (`ops/restore-tests/schedule.md`): wöchentliche Freshness-Checks, monatliche Mini-Restores für Vaultwarden und Gitea, alle zwei Monate Paperless. Erfolg ist explizit als "Smoke-Test passt", nicht "Container startet" definiert. Das ist seltene Reife.
|
||||
- **Pre-Backup-Dumps statt rohe Live-DB-Verzeichnisse als primärer Restore-Pfad** — das ist die Lehre, die viele erst nach dem ersten kaputten Restore lernen.
|
||||
- **Posture-Check + Docker-Critical-Events → ntfy** als Live-Alarmierung, bereits mit Wiederholungsschutz (`ALERT_REPEAT_SECONDS=86400`) und Dedup. Das ist Operations-Reife.
|
||||
- **Cloudflare DNS Challenge für ACME** statt HTTP-01, ermöglicht Wildcard-Zertifikate und keine Port-80-Abhängigkeit für Erneuerung.
|
||||
- **GitOps mit Webhook-Pflicht für neue Stacks** (`docs/WORKFLOW.md`, Abschnitt "Pflicht bei neuen Komodo-Stacks"). Das verhindert "deployed-once-then-forgotten"-Stacks.
|
||||
|
||||
Was Standard wäre und du sinnvoll davon abweichst:
|
||||
|
||||
- **Komodo bewusst ohne pauschale ForwardAuth-Middleware** — richtig, weil Webhooks, API und Periphery sonst brechen. Die meisten würden hier blind Authelia davor schalten und dann zwei Tage debuggen.
|
||||
- **Authelia ohne Redis-Session-Backend** — bewusste Vereinfachung. Du bezahlst dafür mit Re-Login nach Authelia-Restart, gewinnst dafür weniger Tier-1-Abhängigkeiten. Vertretbarer Trade-off.
|
||||
- **Traefik dynamic config als manuelle Host-Sync-Ausnahme** — pragmatisch dokumentiert, statt eines komplexen Auto-Sync-Workarounds.
|
||||
|
||||
Wo du gefährlich von Best Practice abweichst:
|
||||
|
||||
- **Externer Repo-Mirror als DR-Voraussetzung ist offenes TODO** (`docs/DISASTER_RECOVERY.md`, Abschnitt 11). Wenn Gitea ausfällt — und Gitea hängt auch noch an Traefik und PostgreSQL — kannst du Komodo nicht aus Git deployen, kannst die Repo-Doku nicht lesen, und je nach Schaden hast du den lokalen Clone als einzigen Pfad. Das ist ein echter Single Point of Failure. Ein Push-Mirror nach GitHub/GitLab (privat) oder zumindest ein versionierter Sync nach BorgBase würde das in 30 Minuten lösen.
|
||||
- **Unraid USB-Flash-Backup ist offenes TODO**. Wenn der USB-Stick stirbt, ist das nicht das Ende der Welt (Daten leben), aber es kostet einen vollen Wiederaufsetzungs-Tag. Unraid hat dafür einen eingebauten Backup-Mechanismus.
|
||||
- **Komodo Self-Stack Drift Mai 2026**: Du hattest schon einen Vorfall, wo Komodo selbst nicht mehr sauber managebar war ("Recovery-ENV als Tier-1-Secret-Material"). Das Bootstrap-Problem — Komodo verwaltet Komodo — ist nicht gelöst, nur dokumentiert. Eine echte Lösung wäre: Komodo-Self-Stack explizit aus Komodo herauslassen und nur als `docker compose`-Script in `services/` halten.
|
||||
- **Kein Fail2Ban / CrowdSec vor Traefik**. Vaultwarden und Nextcloud sind im Internet erreichbar mit eigener Auth. Die meisten Anti-Brute-Force-Maßnahmen liegen in den Apps selbst, nicht auf Layer 7. Bei einer ernsten Bot-Welle würde Authelia die Last tragen, ohne IP-Bans auszusprechen. CrowdSec als Bouncer für Traefik wäre eine sinnvolle Härtung mit überschaubarem Aufwand.
|
||||
|
||||
**Note für diesen Block: 2.**
|
||||
|
||||
---
|
||||
|
||||
## 4. Nerd-Level / Advanced Homelab
|
||||
|
||||
Was sehr erfahrene Selfhoster mit so einem Repo zusätzlich machen würden:
|
||||
|
||||
- **Renovate Bot oder ein vergleichbares Image-Update-Tracking**: Du pinnst Digests, was richtig ist, aber damit hast du dich auch in die manuelle Update-Pflicht begeben. Renovate gegen Gitea würde wöchentliche PRs für neue Patch-Versionen auf master öffnen, die du mergen oder ignorieren kannst. Das ist deutlich besser als "irgendwann manuell den Digest aktualisieren".
|
||||
- **Staging-Path**: Aktuell hast du master und das ist gleichzeitig produktiv. Ein zweiter Branch (`staging`) der gegen einen zweiten Komodo-Server (in einer Tailscale-VM oder einem zweiten Unraid-Share) deployed, würde Risiko-Aenderungen testbar machen. Das ist viel Aufwand für ein Homelab, aber wenn dich die Stabilität ernsthaft kümmert, ist es der nächste Reifegrad.
|
||||
- **OIDC-Provider statt nur ForwardAuth**: Authelia kann OIDC. Wenn Nextcloud, Immich, Grafana, Komodo (theoretisch), Vaultwarden (via OIDC-Bridge) per SSO laufen, ist das die "echte" Konsolidierung. Heute hast du ForwardAuth für Admin-Dienste, aber Apps mit eigener Auth (Nextcloud, Immich, Jellyfin) sind Eigeninseln.
|
||||
- **Restore-Tests automatisiert in CI**: Du hast Skripts und Cron-Slots, aber kein CI gegen das Repo, das die Restore-Test-Skripte syntaktisch und semantisch prüft. Ein Gitea Actions oder Drone-Setup auf dem Host könnte das gegen jeden Commit laufen lassen.
|
||||
- **Backup-Test-Härtung: Restore in eine echte Test-Domain mit Traefik-Route hinter Authelia** (heute bewusst ohne Domain — siehe `docs/RESTORE_MATRIX.md`). Das ist eine bewusste Entscheidung, würde aber einen "End-to-End restore drill" möglich machen, der einmal pro Quartal komplett durchläuft.
|
||||
- **Disk1 NTFS → XFS Phase 2**: Im Repo dokumentiert, im posture-check temporär toleriert mit `ALLOW_DISK1_NTFS=1`. Das ist die offensichtlichste offene Hardening-Baustelle.
|
||||
- **Loki-Retention und Log-Volume mal anschauen**: 30 Tage Retention ist gut, aber im aktuellen Stand wirst du irgendwann Storage-Probleme bekommen, wenn du nicht weißt, wie viel der Stack pro Tag produziert.
|
||||
|
||||
Was sie bewusst weglassen würden:
|
||||
|
||||
- **Hermes-Agent**: Genau dieses "ich baue mir einen Agenten der über SSH meine VM bedient und ein Dashboard hat" ist das, wovor erfahrene Leute nach dem dritten Homelab warnen. Es bringt Komplexität, Wartungslast und keine messbare Reduktion deiner manuellen Arbeit. Wenn Hermes nicht in den nächsten 60 Tagen produktiv und unverzichtbar wird: entfernen.
|
||||
- **Drei Dashboard-Tools**: Sie würden eines wählen (vermutlich Homepage), die anderen rauswerfen.
|
||||
- **Zwei Medienserver**: Plex und Jellyfin parallel ist Tool-Sammlerei.
|
||||
- **Eigenes paperless-gpt-Container** wenn nicht aktiv im Workflow: lieber das LLM ein-zwei mal manuell auf eine PDF werfen als einen Container 24/7 idle laufen lassen.
|
||||
|
||||
**Note für diesen Block: 2-3.** Sehr nahe am nächsten Reifegrad, aber an drei, vier Stellen würde erfahrene Hand jetzt entrümpeln statt erweitern.
|
||||
|
||||
---
|
||||
|
||||
## 5. Betrieb und Wartbarkeit
|
||||
|
||||
Hier ist die Bewertung am eindeutigsten positiv. Dieses Setup ist langfristig wartbar.
|
||||
|
||||
Die Dokumentation ist auf einem Niveau, das ich selten sehe. `docs/SERVICE_CATALOG.md` ist ein vollständiger Dienst-Katalog mit Restore-Quelle, Smoke-Test und Besonderheiten pro Dienst. `docs/REPO_MAP.md` ist eine technische Landkarte. `docs/RESTORE_MATRIX.md` ist nicht nur "wo ist das Backup", sondern "was ist die führende Quelle", "welche Dumps", "welche Secrets müssen vor Start da sein", "was ist der Smoke-Test". Das ist Doku, die in sechs Monaten noch funktioniert.
|
||||
|
||||
Der Workflow ist klar (`docs/WORKFLOW.md`): Fetch → Pull → ändern → Commit → Push → Komodo. Es gibt eine explizite Stop-Regel ("wenn zwei Reparaturversuche nicht funktionieren, Pflichtmatrix ausfüllen"), die viele Selfhoster nicht haben und stattdessen in Mut-Spiralen rutschen.
|
||||
|
||||
Drei Stellen, wo Wartbarkeit gefährdet ist:
|
||||
|
||||
- **Hermes-Agent**: Spätestens nach sechs Monaten ohne aktive Pflege verstehst du die Model-C-Architektur nicht mehr ohne `ops/hermes-agent/README.md` zu lesen — und dann ist die Frage, warum überhaupt.
|
||||
- **Doppelter Monitoring-Stack (`ops/grafana-influxdb`, `ops/loki`, `monitoring/`)**: Solange beide Welten im Repo sind, vergisst du in einem halben Jahr, welche live ist. Die Migration muss abgeschlossen und die Altstände müssen entfernt werden.
|
||||
- **Authelia Repo-Baseline vs. Host-Config**: Du dokumentierst selbst, dass die Repo-`configuration.yml` "manuell auf den Host gemerged" werden muss, mit OIDC und Secrets hostseitig. Das ist Drift-Risiko per Design. Ein zweiter Mechanismus (z. B. das manuelle Pendant zum Traefik-dynamic-Sync) oder mindestens ein expliziter Diff-Check vor jeder Auth-Änderung wäre Pflicht.
|
||||
|
||||
**Note für diesen Block: 1-2.**
|
||||
|
||||
---
|
||||
|
||||
## 6. Sicherheit und Zugriff
|
||||
|
||||
Du hast eine durchdachte Schichtung:
|
||||
|
||||
- Authelia für Admin-UIs (`uptime`, `borg`, `files`, `code`, `grafana`, `monitoring`, `pdf`, `glance`, `glances`, `scrutiny`, `paperless-gpt`, `speedtest`, `hermes`, `traefik`-Dashboard, `homepage`).
|
||||
- Native App-Auth für User-Apps (`vaultwarden`, `nextcloud`, `immich`, `jellyfin`, `paperless`).
|
||||
- Komodo mit eigener Auth ohne ForwardAuth (bewusste Ausnahme).
|
||||
- Tailscale für Admin-Zugriff von außen.
|
||||
|
||||
Was wirklich gut ist:
|
||||
|
||||
- Authelia mit Argon2id, `iterations=3`, `memory=65536`, `parallelism=4`, `key_length=32`, `salt_length=16` — das ist solide Konfiguration, nicht Default-Müll.
|
||||
- Secrets durchgängig per File-Mount oder Komodo Stack ENV, nie im Compose im Klartext.
|
||||
- Gitea Webhook-Allowlist (`GITEA__webhook__ALLOWED_HOST_LIST=komodo-core,localhost,127.0.0.1,192.168.178.0/24`) und Registrierung deaktiviert — das schließt Webhook-SSRF-Vektoren.
|
||||
- `cloudflare_dns_api_token` als Docker Secret, nicht als ENV.
|
||||
|
||||
Wo du härter trennen solltest:
|
||||
|
||||
- **AdGuard Admin-Port 8082 ist direkt am LAN gebunden ohne Authelia**. Das ist im Architekturdokument als offenes TODO ("Block F") markiert. Im Home-LAN ist das verschmerzbar, aber wenn du eines Tages einen Gast im WLAN hast oder ein IoT-Gerät kompromittiert wird, ist das ein direkter Pfad in die DNS-Konfiguration.
|
||||
- **Nextcloud läuft ohne ForwardAuth** (bewusst wegen WebDAV/CardDAV). Wenn deine Familie schwache Passwörter setzt, ist Nextcloud im Internet das primäre Angriffsziel. Nextcloud-eigene Maßnahmen (Brute-Force-Protection, 2FA-Pflicht für Admin) sollten dokumentiert aktiv sein.
|
||||
- **2FA-Pflicht in Authelia**: In der Doku nicht klar erwähnt. Wenn 2FA nur "optional" ist, läuft die Härtung ins Leere.
|
||||
|
||||
Wo Komfort wichtiger ist und das sinnvoll so bleibt:
|
||||
|
||||
- Komodo ohne ForwardAuth — richtig.
|
||||
- Authelia ohne Redis-Session-Backend — vertretbar.
|
||||
- Plex/Jellyfin mit nativer Auth — sinnvoll, weil die Clients eigene Auth machen.
|
||||
|
||||
**Note für diesen Block: 2.**
|
||||
|
||||
---
|
||||
|
||||
## 7. Backup und Disaster Recovery
|
||||
|
||||
Das ist eine der stärksten Säulen.
|
||||
|
||||
Was du richtig machst:
|
||||
|
||||
- Borg statt Backrest — dokumentierte Entscheidung, eine Backup-Technologie statt zwei.
|
||||
- **Pre-Backup-Dumps als kanonische Restore-Quelle**, nicht rohe Live-DB-Verzeichnisse. Explizit dokumentiert in `ops/borg-ui/BACKUP_SCOPE.md` ("Do not back up raw live database storage directories as the primary recovery artifact").
|
||||
- **Restore-Tests mit Schedule** und expliziter Erfolgsregel ("Container läuft reicht nicht — Smoke-Test muss greifen").
|
||||
- Dump-Skript für SQLite-Container (Gitea, Vaultwarden, Uptime-Kuma, Speedtest-Tracker), BoltDB-Snapshot für Filebrowser, `pg_dump` für die einzelnen Postgres-Datenbanken, `mongodump` für Komodo-Mongo.
|
||||
- Borg-Scope erweitert um `/mnt/user/services` für GitOps-Recovery (Repo, Stack-Workspaces, Posture-Check-State).
|
||||
- Tier-Modell in `docs/RESTORE_MATRIX.md` mit klarer Reihenfolge.
|
||||
- Dokumentierte Restore-Lab-Praxis: Testpfad `/mnt/user/backups/restore-lab/<dienst>`, Reports unter `/mnt/user/backups/restore-reports`, ohne Traefik-Route — keine Vermischung von Test und Produktion.
|
||||
|
||||
Was wirklich offen ist:
|
||||
|
||||
- **Externer Backup-Mirror oder Off-Site-Ziel**: BorgBase ist erwähnt (`ops/borg-ui` als Borg-UI auf BorgBase-Repo), aber die Frage "was passiert, wenn der Unraid-Host und BorgBase gleichzeitig down sind" hat keine dokumentierte Antwort. Zwei Repos (z. B. BorgBase + ein zweites lokales NAS oder ein Hetzner Storage Box) wären die Standardlösung.
|
||||
- **Externer Repo-Mirror als DR-Voraussetzung** — in DR.md als TODO markiert. Wenn Gitea nicht aufsteht, ist das Repo nur über deinen lokalen Clone erreichbar.
|
||||
- **Unraid USB-Flash-Backup** — in DR.md als TODO markiert.
|
||||
- **Borg-Passphrase extern sicher hinterlegt** — als TODO markiert. Das ist die typische "wenn das Haus brennt"-Frage. Vaultwarden hilft dir nicht, wenn Vaultwarden gerade restauriert werden soll. Eine zweite Kopie der Passphrase (verschlüsselt auf einem USB-Stick im Bankschließfach, oder bei einem Familienmitglied) ist Standard.
|
||||
- **Komodo-Mongo Dump nach Major-Upgrades verifizieren** — als Watchpoint dokumentiert, aber nicht im automatischen Restore-Test-Cron.
|
||||
|
||||
Restore-Tests sind monatlich für Vaultwarden und Gitea, alle zwei Monate für Paperless, "später" für Immich. Das ist gut, aber Immich-Restore-Tests sind die kritischsten, weil dort die größten Datenmengen liegen und ein silent corruption am schmerzhaftesten wäre.
|
||||
|
||||
**Note für diesen Block: 1-2.** Wenn die offenen DR-Vorbereitungs-TODOs abgehakt wären, klare 1.
|
||||
|
||||
---
|
||||
|
||||
## 8. Monitoring und Transparenz
|
||||
|
||||
Das ist der Bereich mit dem größten Übergang. Du hast viele Tools, mit Überschneidungen, und der zentrale Monitoring-Stack ist im Aufbau.
|
||||
|
||||
Was du heute hast:
|
||||
|
||||
- **Uptime-Kuma**: HTTP/TCP-Uptime-Checks mit Web-UI.
|
||||
- **Glances**: Live-System-Sicht (CPU/RAM/Disk pro Host).
|
||||
- **Scrutiny**: SMART-Monitoring für Laufwerke.
|
||||
- **Speedtest-Tracker**: Periodische Speedtests gegen den ISP.
|
||||
- **Glance**: Status-Dashboard mit Widgets (Immich, AdGuard, Speedtest, Docker-Container).
|
||||
- **Homepage**: Start-Dashboard mit Service-Cards.
|
||||
- **Posture-Check**: Host-Filesystem, NVMe-SMART, Mover, Füllstand → ntfy.
|
||||
- **Docker-Critical-Events**: `die`/`oom`/`kill` → ntfy.
|
||||
- **`monitoring/`-Zielstack**: Prometheus, Alertmanager, ntfy-Bridge, Blackbox, Loki, Promtail, Grafana, node-exporter, cAdvisor, InfluxDB 3 Core.
|
||||
|
||||
Was richtig gut ist:
|
||||
|
||||
- **Ein zentraler Alert-Pfad**: alle problemrelevanten Meldungen landen auf `homelab-alerts` per ntfy. Das ist die wichtigste Disziplin und du hast sie. `docs/ALERTING_MAP.md` listet alle Sender.
|
||||
- Prometheus-Stack mit Alertmanager + Bridge zu ntfy, also nicht "Grafana sendet Email" sondern "Alertmanager-Pflicht-Pfad".
|
||||
- Blackbox-Exporter ersetzt mittelfristig Uptime-Kuma (richtige Strategie).
|
||||
- 30 Tage Retention für Prometheus und Loki — sinnvoll für Diagnose-Daten, kein Backup-Surrogat.
|
||||
- node-exporter + cAdvisor + Traefik-Metrics → wirklich vollständige Infrastruktur-Telemetrie.
|
||||
|
||||
Was fehlt oder zu viel ist:
|
||||
|
||||
- **Doppelte Beobachtungs-Tools nebeneinander**: Uptime-Kuma vs. Blackbox, Glances vs. node-exporter+cAdvisor, Glance vs. Homepage. Du weißt das, die Migration ist im Gang. Bis sie fertig ist, gibt es Verwirrung darüber, welches die "Wahrheit" ist.
|
||||
- **Smoke-Test-Dashboards**: In `monitoring/grafana/dashboards/` sind ein paar Dashboards, aber die "Family-View" — "alles grün, alles erreichbar, Backup heute Nacht durchgelaufen" — fehlt als explizites Dashboard. Das wäre der Wert für dich selbst: morgens kurz draufschauen und wissen, ob etwas die Aufmerksamkeit braucht.
|
||||
- **Alert-Regeln explizit listen**: `monitoring/prometheus/alerts.yml` existiert, aber eine kurze Doku, welche Regeln wann feuern (Disk > 90%, Borg älter 36h, Cert läuft in 14 Tagen ab, etc.), würde die Operations-Reife komplettieren.
|
||||
- **Cert-Token-Check** läuft (laut ALERTING_MAP) — gut, das ist die einzige sinnvolle Methode, "TLS-Cert läuft ab" früh genug zu sehen.
|
||||
|
||||
**Note für diesen Block: 3.** Bricht ab, sobald die Monitoring-Migration sauber abgeschlossen ist und die Altstände entfernt sind — dann eine 2.
|
||||
|
||||
---
|
||||
|
||||
## 9. Konkreter Mehrwert-Fahrplan
|
||||
|
||||
### Quick Wins (≤ eine Woche, hoher Nutzen)
|
||||
|
||||
- **Externer Push-Mirror für das Repo nach GitHub privat** einrichten. Das ist ein Webhook in Gitea + ein leerer GitHub-Privat-Repo. 30 Minuten. Löst das wichtigste DR-Risiko.
|
||||
- **Borg-Passphrase auf einen USB-Stick im Bankschließfach** oder in eine versiegelte Umschlag-Box. Eine analoge Sicherung gegen das digitale Worst-Case-Szenario.
|
||||
- **Plex oder Jellyfin entscheiden**: einen davon weg. 14 Tage Nutzungs-Tracking via Server-Logs oder einfach beobachten, wer welchen Client öffnet. Dann den ungenutzten Stack archivieren.
|
||||
- **Glance ODER Homepage** als einziges Dashboard wählen. Heute laufen beide. Es gibt keinen technischen Grund für zwei.
|
||||
- **Authelia 2FA-Pflicht für alle aktiven User** verifizieren — wenn nicht gesetzt, jetzt setzen.
|
||||
- **Disk1 NTFS → XFS Phase 2 abschließen** — das ist im Repo dokumentiert und im posture-check als Übergangsausnahme markiert. Loswerden.
|
||||
|
||||
### Phase 1 (zwei bis vier Wochen, Stabilität und Ordnung)
|
||||
|
||||
- **Monitoring-Migration abschließen und Altstände entfernen**: `monitoring/` produktiv, dann `ops/grafana-influxdb` und `ops/loki` aus dem Repo löschen (mit Backup-Branch fürs Gewissen).
|
||||
- **Uptime-Kuma ablösen durch Blackbox + Grafana-Alerts**: nach den sieben Tagen Parallelbetrieb, die in `docs/SERVICE_CATALOG.md` als Pflicht stehen.
|
||||
- **Hermes-Agent ehrliche Entscheidung**: produktiv machen mit klarem Alltagsnutzen, oder entfernen. Kein "halb da, halb deaktiviert"-Zustand für ein weiteres Quartal.
|
||||
- **paperless-gpt und BentoPDF Status**: gleiche Frage. Produktiv oder weg.
|
||||
- **Unraid USB-Flash-Backup** einrichten (Unraid hat einen eingebauten Mechanismus).
|
||||
- **Ein Family-View-Dashboard in Grafana** bauen: alles-grün-Übersicht für den Morgen-Check.
|
||||
|
||||
### Phase 2 (vier bis zwölf Wochen, Automatisierung und Transparenz)
|
||||
|
||||
- **Authelia OIDC-Provider aktivieren** und Nextcloud, Immich, Grafana als OIDC-Clients konfigurieren. Echtes SSO für die Familie.
|
||||
- **Renovate Bot gegen Gitea** für kontrollierte Image-Updates (PRs statt manuelle Digest-Pflege).
|
||||
- **Restore-Test für Immich** als eigener Sprint einplanen — der größte Datentopf und der einzige Tier-2-Dienst ohne Mini-Restore-Test.
|
||||
- **Familie onboarden**: Smartphone-Auto-Backup zu Immich für alle Familien-Geräte. Das ist der Schritt vom "ich betreibe Container" zum "meine Familie benutzt aktiv was Selbstgebautes".
|
||||
- **CrowdSec vor Traefik** als Bouncer für die öffentlich erreichbaren Apps (Vaultwarden, Nextcloud, Immich, Gitea).
|
||||
|
||||
### Phase 3 (drei bis sechs Monate, Advanced Nerd-Level)
|
||||
|
||||
- **Staging-Branch + zweites Komodo-Ziel** in einer Tailscale-VM, für Risiko-Änderungen.
|
||||
- **Restore-Test-Automatisierung als CI** (Gitea Actions oder Drone).
|
||||
- **Off-Site-Backup zu einem zweiten Ziel** (zweites BorgBase-Repo, Hetzner Storage Box, oder zweites NAS bei einem Familienmitglied).
|
||||
- **Cold-Standby-Konzept** dokumentieren: was passiert, wenn der Unraid-Host stirbt und du erst in zwei Wochen Ersatz hast?
|
||||
- **Komodo-Self-Stack rausnehmen** und als handgepflegten `docker compose`-Service in `services/` halten — löst das Bootstrap-Problem.
|
||||
|
||||
### Phase 4 (Spielwiese, nice-to-have)
|
||||
|
||||
- Firefly III oder Actual Budget für Finanz-Übersicht.
|
||||
- Wandtablet-Setup im Flur mit Family-Dashboard.
|
||||
- Smart-Home-Automatisierungen über Home Assistant tiefer mit ntfy verzahnen (Frost-Warnung, PV-Überschuss-Hinweis, Briefkasten-Sensor).
|
||||
- Ein eigenes kleines Dashboard für Ecowitt-Wetterdaten (sobald die Pipeline aus `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md` läuft).
|
||||
|
||||
---
|
||||
|
||||
## Schulnote, Top-5-Listen, klare Empfehlung
|
||||
|
||||
### Schulnote
|
||||
|
||||
**2- (gut bis befriedigend, eher 2).**
|
||||
|
||||
Auf der Skala "durchschnittliches Homelab" wäre das eine 1. Die strukturelle Disziplin, GitOps-Konsequenz, Doku-Qualität, Backup-Reife und Architektur-Klarheit liegen weit über dem, was die meisten Selfhoster jemals erreichen. Was die Note von einer 1 runterzieht: drei bis fünf offene Baustellen, die nicht trivial sind (externer Repo-Mirror, Monitoring-Migration unfertig, Hermes-Agent im Schwebezustand, zwei Medienserver parallel, AdGuard Admin-Port ohne ForwardAuth). Wenn du Phase 1 abschließt, bist du klar bei einer 1.
|
||||
|
||||
### Top 5 sofort verbessern
|
||||
|
||||
1. **Externer Repo-Mirror** (GitHub privat, BorgBase, oder zweites Gitea). 30 Minuten Aufwand, schließt das wichtigste DR-Loch.
|
||||
2. **Borg-Passphrase analog außerhalb des Systems sichern** (Bankschließfach, Familienmitglied, Tresor).
|
||||
3. **Plex oder Jellyfin entscheiden**, einen davon entfernen.
|
||||
4. **Glance oder Homepage** als einziges Dashboard wählen.
|
||||
5. **AdGuard Admin-Port hinter Authelia** oder mindestens nur via Tailscale erreichbar (heute LAN-direkt).
|
||||
|
||||
### Top 5 mit dem größten zusätzlichen Mehrwert
|
||||
|
||||
1. **Smartphone-Auto-Backup zu Immich für die ganze Familie**: macht aus deinem Foto-Server eine echte Killer-App für andere als dich.
|
||||
2. **Authelia OIDC-Provider aktivieren** und Nextcloud + Immich + Grafana per SSO: ein Login für alle wichtigen Apps.
|
||||
3. **Renovate Bot gegen Gitea**: automatisierte Update-PRs für deine Digest-pinnten Images.
|
||||
4. **Family-View-Dashboard in Grafana**: morgens 30 Sekunden draufschauen statt Tools-Tour.
|
||||
5. **Finanz-App (Firefly III oder Actual Budget)**: füllt den `/mnt/user/finance`-Share mit echtem Alltagsnutzen.
|
||||
|
||||
### Top 5 lieber NICHT machen
|
||||
|
||||
1. **Hermes-Agent ausbauen statt loswerden**. Wenn du in 60 Tagen nicht ehrlich sagen kannst, was Hermes dir täglich abnimmt: weg damit. Komplexität ohne Gegenwert ist das größte Anti-Pattern in jedem Homelab.
|
||||
2. **Noch mehr Dashboards einbauen**. Du hast bereits Homepage, Glance, Komodo-UI und kommst gleich noch mit Grafana-Family-View. Mehr wäre Sammlerei.
|
||||
3. **Pauschale Authelia-ForwardAuth vor Komodo** schalten. Dokumentierte Ausnahme aus gutem Grund. Webhooks, API und Periphery würden brechen.
|
||||
4. **Backend_net auf `external: true` statt `internal: true`** umstellen, weil "ist ja einfacher". Genau das ist die Mauer, die viele Apps vor öffentlichem Zugriff schützt.
|
||||
5. **Komodo Self-Stack komplett über Komodo managen lassen**. Du hattest schon einen Drift-Vorfall. Komodo verwaltet Komodo ist ein Bootstrap-Problem ohne befriedigende Lösung.
|
||||
|
||||
### Klare Empfehlung
|
||||
|
||||
**Vereinfachen und konsolidieren, NICHT weiter ausbauen.**
|
||||
|
||||
Du bist an einem Punkt, an dem das Setup mehr Substanz hat, als aktiv genutzt wird. Die nächsten sechs Monate sollten weniger neue Dienste sehen und mehr Entrümpelung (Plex vs. Jellyfin, Glance vs. Homepage, Hermes-Entscheidung, Monitoring-Altstände raus, paperless-gpt/BentoPDF-Entscheidung), mehr Familien-Aktivierung (Immich-Smartphone-Backup, OIDC-SSO, Family-Dashboard), und mehr DR-Resilienz (externer Mirror, Off-Site-Backup-Ziel, Borg-Passphrase analog gesichert).
|
||||
|
||||
Wenn du das in den nächsten drei Monaten machst, hast du eine private Plattform mit echtem Alltagsnutzen, klarer Wartbarkeit, und einer Wiederherstellbarkeit, die seriöser ist als das, was viele Mittelstandsfirmen für ihre Office-IT haben. Das ist das Ziel, nicht "noch ein Container".
|
||||
|
||||
Wenn du dann weiterausbauen willst, bist du in der Position, das aus einer Stärke heraus zu tun, nicht aus dem "ich muss noch das hier probieren"-Reflex.
|
||||
|
||||
---
|
||||
|
||||
## Status-Anhang 2026-05-30
|
||||
|
||||
Dieser Anhang ist nicht Teil der Originalbewertung vom 2026-05-23. Er ordnet jedem konkret handelbaren Befund den tatsaechlichen Stand nach den Audit-Sprints zu, damit das Dokument selbststaendig lesbar bleibt.
|
||||
|
||||
### Block 1 - Architektur
|
||||
|
||||
| Originalbefund | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| ops/grafana-influxdb + ops/loki + monitoring/ parallel im Repo | **erledigt** 2026-05-26: Altstaende entfernt, monitoring/ einziger aktiver Observability-Stack |
|
||||
|
||||
### Block 2 - Nutzen und Mehrwert
|
||||
|
||||
| Originalbefund | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Plex zusaetzlich zu Jellyfin | **erledigt** 2026-05-25: Jellyfin entfernt, Plex bleibt einziger Medienserver |
|
||||
| Glance + Homepage + Komodo-UI als drei parallele Dashboards | **erledigt** 2026-05-25: Homepage entfernt, Glance bleibt einziges Dashboard |
|
||||
| paperless-gpt — produktiv oder weg? | **entschieden** 2026-05-28: behalten bis Paperless-NGX 3.0 native KI-Features, dann neu bewerten |
|
||||
| BentoPDF — produktiv oder weg? | **entschieden** 2026-05-28: behalten als situatives Tool (~4 MB RAM-Footprint) |
|
||||
| Hermes-Agent als Spielerei, Review-Deadline gesetzt | **geparkt** mit Review-Deadline 2026-07-25 |
|
||||
| Speedtest-Tracker als "ich messe gerne" | unveraendert, keine Operator-Entscheidung getroffen |
|
||||
| code-server — sinnvoll oder weg? | unveraendert, keine Operator-Entscheidung getroffen |
|
||||
| Finanz-App (Firefly III / Actual Budget) als fehlender Mehrwert | offen, nice-to-have ohne aktiven Termin |
|
||||
| Familien-SSO ueber Authelia OIDC | **geparkt** im Auth-Block (F-13) |
|
||||
| Smartphone-Auto-Backup zu Immich | offen, Anwendungsentscheidung pro Familienmitglied |
|
||||
| Wandtablet im Flur mit Family-Dashboard | offen, Spielwiese |
|
||||
| Kalender/Aufgaben/CardDAV-Nutzung dokumentieren | offen, Operator-Frage |
|
||||
|
||||
### Block 3 - Best Practices
|
||||
|
||||
| Originalbefund | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Externer Repo-Mirror als DR-Voraussetzung offen | **erledigt**: GitHub-Push-Mirror `michaelkaleschke-spec/homelab-infra` aktiv |
|
||||
| Unraid USB-Flash-Backup offen | **erledigt** 2026-05-25: `unraid-flash-config.tar.gz` im Borg-Scope |
|
||||
| Komodo Self-Stack Drift Mai 2026 nur dokumentiert, nicht geloest | **teilweise erledigt** 2026-05-29/30: Trockenlauf-Skript + erfolgreicher Erstlauf belegen `ops/komodo/docker-compose.yml` als Recovery-Anker; Self-Stack-Entkopplung selbst bleibt offen |
|
||||
| Kein Fail2Ban/CrowdSec vor Traefik | **geparkt** im Auth-Block (F-14) |
|
||||
| Renovate Bot fehlt | **erledigt** 2026-05-29: live, erster Lauf erfolgreich, 5 PRs in Gitea |
|
||||
|
||||
### Block 4 - Nerd-Level
|
||||
|
||||
| Originalbefund | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Renovate Bot oder vergleichbares Update-Tracking | **erledigt** 2026-05-29 |
|
||||
| Staging-Path mit zweitem Komodo-Ziel | offen, Phase 3 nice-to-have |
|
||||
| OIDC-Provider statt nur ForwardAuth | **geparkt** im Auth-Block (F-13) |
|
||||
| Restore-Tests automatisiert in CI (Gitea Actions / Drone) | offen, Phase 3 |
|
||||
| End-to-End restore drill mit Test-Domain hinter Traefik | offen, bewusst nicht (Test-Lab bleibt ohne Domain) |
|
||||
| Disk1 NTFS -> XFS Phase 2 | **erledigt** (`ALLOW_DISK1_NTFS=0` als Default im posture-check, XFS-Erwartung aktiv) |
|
||||
| Loki-Retention und Log-Volume bewerten | offen, Detail-Sweep |
|
||||
| Hermes-Agent loswerden | **geparkt** mit Review 2026-07-25 |
|
||||
| Drei Dashboard-Tools auf eines reduzieren | **erledigt**: Glance bleibt als einziges |
|
||||
| Zwei Medienserver | **erledigt**: Jellyfin entfernt |
|
||||
|
||||
### Block 5 - Betrieb und Wartbarkeit
|
||||
|
||||
| Originalbefund | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Doppelter Monitoring-Stack als Wartbarkeits-Risiko | **erledigt** 2026-05-26 |
|
||||
| Authelia Repo-Baseline vs. Host-Config Drift "by design" | **erledigt** 2026-05-30 (F-10): `services/authelia-diff.sh` + Posture-Check ueberwacht ACL-Drift automatisch, WORKFLOW.md hat eigene Pflicht-Sektion |
|
||||
| Hermes-Agent verstaendnis-kritisch nach 6 Monaten | **geparkt** mit Review 2026-07-25 |
|
||||
|
||||
### Block 6 - Sicherheit und Zugriff
|
||||
|
||||
| Originalbefund | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| AdGuard Admin-Port 8082 LAN-direkt ohne Authelia | **erledigt** 2026-05-26: auf Tailscale-IP `100.80.98.33:8082` gebunden, LAN-Zugriff blockiert |
|
||||
| Nextcloud ohne ForwardAuth, Brute-Force-Doku offen | **geparkt** im Auth-Block (F-18) |
|
||||
| Authelia 2FA-Pflicht nicht klar dokumentiert | **geparkt** im Auth-Block (F-04) |
|
||||
|
||||
### Block 7 - Backup und Disaster Recovery
|
||||
|
||||
| Originalbefund | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Externer Backup-Mirror / zweites Off-Site-Ziel | **entschieden** 2026-05-28: kein zweites Off-Site; 3-2-1 mit Live + lokalem Borg + Hetzner + H:/-Nearline erfuellt; Hetzner-Haertungen als Folge-TODOs |
|
||||
| Externer Repo-Mirror | **erledigt**: GitHub-Push-Mirror aktiv |
|
||||
| Unraid USB-Flash-Backup | **erledigt** 2026-05-25 |
|
||||
| Borg-Passphrase analog gesichert | **erledigt** 2026-05-26: Operator bestaetigt, offline gesichert |
|
||||
| Komodo-Mongo Dump-Verifikation nach Major-Upgrades | offen, Watchpoint dokumentiert, nicht im automatischen Cron |
|
||||
| Restore-Tests Immich (groesster Datentopf ohne Mini-Restore) | **erledigt** 2026-05-27: erster Host-Lauf erfolgreich (`SUCCESS`, 11977 Assets) |
|
||||
|
||||
### Block 8 - Monitoring und Transparenz
|
||||
|
||||
| Originalbefund | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Doppelte Tools (Uptime-Kuma vs. Blackbox, Glance vs. Homepage) | **erledigt** 2026-05-25: Uptime-Kuma und Homepage entfernt |
|
||||
| Family-View Dashboard fehlt als Morgens-Check | **Spec da, JSON offen**: `docs/FAMILY_VIEW_DASHBOARD.md` definiert Layout/Queries/Thresholds; JSON wird gebaut, sobald Metriken 7+ Tage stabil sind |
|
||||
| Alert-Regeln explizit listen | **teilweise**: `monitoring/prometheus/alerts.yml` enthaelt Regeln (Borg-Stale, Cert-Expiry, Container-Down), `docs/ALERTING_MAP.md` mappt Sender — eine Doku-Zusammenfassung "welche Regel feuert wann" ist noch nicht zentralisiert |
|
||||
|
||||
### Block 9 - Konkreter Mehrwert-Fahrplan
|
||||
|
||||
#### Quick Wins (≤ 1 Woche)
|
||||
|
||||
| Original-Punkt | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Externer Push-Mirror GitHub privat | **erledigt** |
|
||||
| Borg-Passphrase analog sichern | **erledigt** 2026-05-26 |
|
||||
| Plex oder Jellyfin entscheiden | **erledigt** 2026-05-25: Jellyfin weg |
|
||||
| Glance oder Homepage waehlen | **erledigt** 2026-05-25: Homepage weg |
|
||||
| Authelia 2FA-Pflicht aktivieren | **geparkt** (F-04) |
|
||||
| Disk1 NTFS -> XFS Phase 2 | **erledigt** |
|
||||
| AdGuard Admin Tailscale-only | **erledigt** 2026-05-26 |
|
||||
|
||||
#### Phase 1 (2-4 Wochen)
|
||||
|
||||
| Original-Punkt | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Monitoring-Migration abschliessen, Altstaende entfernen | **erledigt** 2026-05-26 |
|
||||
| Uptime-Kuma abloesen durch Blackbox + Grafana | **erledigt** 2026-05-25 |
|
||||
| Hermes-Agent Entscheidung | **geparkt** mit Review 2026-07-25 |
|
||||
| paperless-gpt / BentoPDF Entscheidung | **entschieden** 2026-05-28: beide behalten mit Begruendung |
|
||||
| Unraid USB-Flash-Backup | **erledigt** 2026-05-25 |
|
||||
| Family-View-Dashboard | Spec da, JSON wartet |
|
||||
|
||||
#### Phase 2 (4-12 Wochen)
|
||||
|
||||
| Original-Punkt | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Authelia OIDC fuer Nextcloud/Immich/Grafana | **geparkt** (F-13) |
|
||||
| Renovate Bot gegen Gitea | **erledigt** 2026-05-29 |
|
||||
| Restore-Test fuer Immich | **erledigt** 2026-05-27 |
|
||||
| Familien-Smartphone-Auto-Backup zu Immich | offen, Operator-Anwendungsentscheidung |
|
||||
| CrowdSec vor Traefik | **geparkt** (F-14) |
|
||||
|
||||
#### Phase 3 (3-6 Monate)
|
||||
|
||||
| Original-Punkt | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Staging-Branch + zweites Komodo-Ziel | offen |
|
||||
| Restore-Test-Automatisierung als CI | offen |
|
||||
| Off-Site-Backup zu zweitem Ziel | **entschieden** 2026-05-28: bewusst nicht |
|
||||
| Cold-Standby-Konzept dokumentieren | offen |
|
||||
| Komodo-Self-Stack rausnehmen | teilweise erledigt: Bootstrap-Anker und Trockenlauf-Skript da, Entkopplung selbst noch nicht |
|
||||
|
||||
#### Phase 4 (Spielwiese)
|
||||
|
||||
| Original-Punkt | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| Firefly III / Actual Budget | offen |
|
||||
| Wandtablet mit Family-Dashboard | offen |
|
||||
| Home Assistant + ntfy enger verzahnen | offen |
|
||||
| Ecowitt-Wetter-Dashboard | offen |
|
||||
|
||||
### Top-5-Listen vom 2026-05-23
|
||||
|
||||
#### Top 5 sofort verbessern
|
||||
|
||||
| Original-Top-5 | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| 1. Externer Repo-Mirror | **erledigt** |
|
||||
| 2. Borg-Passphrase analog sichern | **erledigt** |
|
||||
| 3. Plex oder Jellyfin entscheiden | **erledigt** |
|
||||
| 4. Glance oder Homepage waehlen | **erledigt** |
|
||||
| 5. AdGuard Admin-Port haerten | **erledigt** |
|
||||
|
||||
**Alle 5 erledigt.**
|
||||
|
||||
#### Top 5 mit groesstem zusaetzlichen Mehrwert
|
||||
|
||||
| Original-Top-5 | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| 1. Smartphone-Auto-Backup zu Immich | offen, Anwendungsentscheidung |
|
||||
| 2. Authelia OIDC fuer SSO | **geparkt** |
|
||||
| 3. Renovate Bot gegen Gitea | **erledigt** |
|
||||
| 4. Family-View-Dashboard | Spec da, JSON wartet |
|
||||
| 5. Finanz-App | offen |
|
||||
|
||||
#### Top 5 lieber NICHT machen
|
||||
|
||||
| Original-Anti-Top-5 | Stand 2026-05-30 |
|
||||
|---|---|
|
||||
| 1. Hermes-Agent ausbauen statt loswerden | gehalten — Agent geparkt mit Review, nicht ausgebaut |
|
||||
| 2. Noch mehr Dashboards einbauen | gehalten — Homepage entfernt, Glance bleibt einziges |
|
||||
| 3. Pauschale Authelia vor Komodo | gehalten — Komodo bleibt ohne ForwardAuth |
|
||||
| 4. backend_net auf external statt internal | gehalten — backend_net bleibt internal |
|
||||
| 5. Komodo Self-Stack komplett via Komodo | teilweise gehalten — Trockenlauf-Skript als Gegenmaszahme, vollstaendige Entkopplung offen |
|
||||
|
||||
### Zusammenfassung des Status-Anhangs
|
||||
|
||||
- **Top 5 sofort**: 5/5 erledigt.
|
||||
- **Quick Wins (7)**: 6 erledigt, 1 geparkt.
|
||||
- **Phase 1 (6)**: 4 erledigt, 1 geparkt, 1 wartend.
|
||||
- **Phase 2 (5)**: 2 erledigt, 2 geparkt, 1 offen.
|
||||
- **Phase 3 (5)**: 1 entschieden (nicht umgesetzt), 1 teilweise, 3 offen.
|
||||
- **Phase 4 (Spielwiese)**: alle offen, bewusst niedrige Prioritaet.
|
||||
- **Auth-Block (F-04/13/14/18)**: vollstaendig geparkt nach Operator-Entscheidung 2026-05-26, gebuendelte Bearbeitung ausserhalb des aktuellen Zyklus.
|
||||
|
||||
Wer hier weiterarbeiten will, schaut auf `docs/AUDIT_2026-05-25_TODO.md` — dort ist der operative Stand gepflegt.
|
||||
+9
-4
@@ -361,7 +361,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`, `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 7.8 (Entfernt), `docs/MIGRATION_LOG.md` nachziehen.
|
||||
9. `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md` und `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 7.8 (Entfernt) nachziehen.
|
||||
|
||||
Wenn ein Stack `webhook_enabled` in Komodo hatte, zusaetzlich pruefen, ob der zugehoerige Gitea-Hook deaktiviert oder geloescht wurde.
|
||||
|
||||
@@ -369,9 +369,14 @@ Wenn ein Stack `webhook_enabled` in Komodo hatte, zusaetzlich pruefen, ob der zu
|
||||
|
||||
## Dokumentationspflicht
|
||||
|
||||
Nach jeder erfolgreichen Migration oder relevanten Aenderung muessen diese Dateien geprueft werden:
|
||||
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
|
||||
|
||||
- `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
|
||||
@@ -403,7 +408,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. ggf. `docs/MIGRATION_LOG.md`
|
||||
> 4. die relevante Betriebsdoku aus `docs/README.md`
|
||||
|
||||
Erst danach duerfen Aenderungen vorgeschlagen werden.
|
||||
|
||||
|
||||
@@ -0,0 +1,504 @@
|
||||
# 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.
|
||||
```
|
||||
+8
-1
@@ -1,8 +1,15 @@
|
||||
# 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.
|
||||
|
||||
## Live-Stand 2026-05-04
|
||||
## Historischer 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,86 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,132 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,137 @@
|
||||
# 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
|
||||
```
|
||||
@@ -0,0 +1,401 @@
|
||||
# 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".
|
||||
@@ -0,0 +1,148 @@
|
||||
# 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
-2
@@ -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\docs\windows-neuaufsetzen-masterplan.md
|
||||
G:\Gitea_Clone\homelab-infra\ops\windows-reinstall\docs\windows-neuaufsetzen-masterplan.md
|
||||
```
|
||||
|
||||
Dann Codex/ChatGPT sagen:
|
||||
@@ -100,4 +100,3 @@ 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.
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,303 @@
|
||||
# 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.
|
||||
+24
-10
@@ -43,12 +43,20 @@ Erledigt:
|
||||
Noch offen:
|
||||
|
||||
- Manuelle Screenshots in `H:\Windows-Neuaufsetzen-Backup\14_Screenshots` ablegen.
|
||||
- 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.
|
||||
- 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").
|
||||
- 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.
|
||||
@@ -462,7 +470,7 @@ Direkt nach der Installation:
|
||||
- Windows-Aktivierung prüfen
|
||||
- Laufwerksbuchstaben sauber vergeben
|
||||
- Windows Defender und Firewall prüfen
|
||||
- BitLocker bewusst aktivieren oder deaktiviert lassen
|
||||
- BitLocker bewusst deaktiviert lassen (Entscheidung 2026-06-06)
|
||||
- Wiederherstellungspunkt erstellen
|
||||
|
||||
Basisprogramme:
|
||||
@@ -528,16 +536,22 @@ 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
|
||||
- [ ] Passwortmanager geprüft
|
||||
- [ ] 2FA-Recovery-Codes gesichert
|
||||
- [x] Passwortmanager geprüft
|
||||
- [x] 2FA-Recovery-Codes gesichert
|
||||
- [ ] SSH/API/GPG/Zertifikate gesichert
|
||||
- [ ] Banking4-Speicherort geprüft und gesichert
|
||||
- [x] 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
|
||||
@@ -0,0 +1,25 @@
|
||||
# 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` |
|
||||
@@ -0,0 +1,228 @@
|
||||
# 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?
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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>
|
||||
@@ -0,0 +1,107 @@
|
||||
# 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.
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
adguard:
|
||||
image: adguard/adguardhome:v0.107.76@sha256:7157eb1dc3b26c7af1d6898759a7b3f7d0fa09891fbd2d3caa6abc1057a9179b
|
||||
image: adguard/adguardhome:v0.107.77@sha256:e6f2b8bcda06064ab055b44933a4f0e983c35558b9cdb8d2e7ab1efcee36d890
|
||||
container_name: adguard
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
services:
|
||||
tailscale:
|
||||
image: tailscale/tailscale:stable@sha256:25cde9ad76020b0e29229136d0c38b5962e9a0e1774ffac9b0df68e4a37d6cf0
|
||||
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:
|
||||
postgresql17:
|
||||
image: postgres:17.10@sha256:0027bef26712baaee437a4ea48fdf3d2d2e2bc5f0d81615374408ca320f3c7e3
|
||||
image: postgres:18.4@sha256:8ff36f3c66371cba71d20ceedccfc3de9669a68737607888c4ef0af93abe8e39
|
||||
container_name: postgresql17
|
||||
restart: unless-stopped
|
||||
|
||||
@@ -9,10 +9,10 @@ services:
|
||||
POSTGRES_USER: mailarchiver
|
||||
POSTGRES_DB: mailarchiver
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
|
||||
PGDATA: /var/lib/postgresql/data
|
||||
PGDATA: /var/lib/postgresql/18/docker
|
||||
|
||||
volumes:
|
||||
- /mnt/user/appdata/postgresql17:/var/lib/postgresql/data
|
||||
- /mnt/user/appdata/postgresql18:/var/lib/postgresql
|
||||
- /mnt/user/appdata/secrets/postgres_password.txt:/run/secrets/postgres_password:ro
|
||||
|
||||
networks:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
services:
|
||||
redis:
|
||||
image: redis:7.4-alpine@sha256:6ab0b6e7381779332f97b8ca76193e45b0756f38d4c0dcda72dbb3c32061ab99
|
||||
image: redis:8.8.0-alpine@sha256:09160599abd229764c0fb44cb6be640294e1d360a54b19985ab4843dcf2d90f1
|
||||
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-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.
|
||||
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.
|
||||
|
||||
## 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`, `Traefik Official Standalone Dashboard`.
|
||||
- Dashboard-Zielbestand: `Homelab / Availability`, `Homelab / Containers + Logs`, `Homelab / Host Overview`, `Homelab / Family Status`, `Traefik Official Standalone Dashboard`.
|
||||
|
||||
## Alerting
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ services:
|
||||
- cadvisor
|
||||
|
||||
alertmanager:
|
||||
image: prom/alertmanager:v0.32.1@sha256:51a825c2a40acc3e338fdd00d622e01ec090f72be2b3ea46be0839cd47a4d286
|
||||
image: prom/alertmanager:v0.32.2@sha256:b85533a2eb45865835315810315f6951331b2dbc8c93a6cf9a51e156a006a706
|
||||
container_name: monitoring-alertmanager
|
||||
restart: unless-stopped
|
||||
command:
|
||||
@@ -66,15 +66,18 @@ services:
|
||||
image: prom/blackbox-exporter:v0.28.0@sha256:e753ff9f3fc458d02cca5eddab5a77e1c175eee484a8925ac7d524f04366c2fc
|
||||
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:
|
||||
- 1.1.1.1
|
||||
- 8.8.8.8
|
||||
- 172.23.0.3
|
||||
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:
|
||||
@@ -115,8 +118,9 @@ services:
|
||||
- loki
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:12.4.3@sha256:2e986801428cd689c2358605289c90ab37d2b39e24808874971f54c99bcdc412
|
||||
image: grafana/grafana:13.0.2@sha256:5dad0df181cb644a14e13617b913b261a54f7d4fd4510721dba420929f35bea2
|
||||
container_name: monitoring-grafana
|
||||
user: "0"
|
||||
restart: unless-stopped
|
||||
dns:
|
||||
- 1.1.1.1
|
||||
@@ -127,6 +131,21 @@ 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
|
||||
@@ -143,6 +162,7 @@ services:
|
||||
secrets:
|
||||
- monitoring_grafana_admin_password
|
||||
- monitoring_grafana_influxdb_token
|
||||
- grafana_oidc_client_secret
|
||||
expose:
|
||||
- "3000"
|
||||
security_opt:
|
||||
@@ -158,7 +178,8 @@ services:
|
||||
- traefik.http.routers.monitoring-grafana.entrypoints=websecure
|
||||
- traefik.http.routers.monitoring-grafana.tls=true
|
||||
- traefik.http.routers.monitoring-grafana.tls.certresolver=le
|
||||
- traefik.http.routers.monitoring-grafana.middlewares=authelia@file,secure-headers@file
|
||||
# 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.services.monitoring-grafana.loadbalancer.server.port=3000
|
||||
|
||||
grafana-dashboard-importer:
|
||||
@@ -316,7 +337,7 @@ services:
|
||||
- no-new-privileges:true
|
||||
|
||||
influxdb3-core:
|
||||
image: influxdb:3.9.2-core@sha256:31ad94df2248134989b2cf73d965e51dd5f35dfae22d7ed8f4776b12e6f69f4e
|
||||
image: influxdb:3.9.3-core@sha256:c27c9b2ca2625b5b6966f0b09baa448102310e63a471fd60dff22646a2522e29
|
||||
container_name: monitoring-influxdb3-core
|
||||
user: "0"
|
||||
restart: unless-stopped
|
||||
@@ -349,6 +370,8 @@ networks:
|
||||
driver: bridge
|
||||
frontend_net:
|
||||
external: true
|
||||
dns_net:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
prometheus_data:
|
||||
@@ -362,5 +385,7 @@ 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
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
{
|
||||
"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"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Borg Backup Scope for KalliLabcore
|
||||
|
||||
Stand: 2026-05-16
|
||||
Stand: 2026-05-31
|
||||
|
||||
This file defines the target state for replacing Backrest with Borg in this homelab.
|
||||
|
||||
@@ -45,9 +45,13 @@ 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 + file data | `/local/borg-dumps`, `/local/appdata/grafana` |
|
||||
| Grafana | SQLite dump from `monitoring_grafana_data` + provisioned config in Git | `/local/borg-dumps`, `monitoring/grafana/provisioning`, `monitoring/grafana/dashboards` |
|
||||
| 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 |
|
||||
|
||||
@@ -69,7 +73,7 @@ The live Unraid User Scripts execute repo scripts from `/mnt/user/services/homel
|
||||
|
||||
## Database Dumps Required
|
||||
|
||||
### Shared PostgreSQL (`postgresql17`)
|
||||
### Shared PostgreSQL (`postgresql17`, runtime PostgreSQL 18)
|
||||
|
||||
- `mailarchiver`
|
||||
- `paperless`
|
||||
@@ -87,17 +91,20 @@ 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/postgresql17`
|
||||
- `/mnt/user/appdata/mealie/postgres`
|
||||
- `/mnt/user/appdata/immich_postgres`
|
||||
- `/mnt/user/appdata/nextcloud/postgres`
|
||||
- `/mnt/user/appdata/postgresql18`
|
||||
- `/mnt/user/appdata/mealie/postgres18`
|
||||
- `/mnt/user/appdata/immich_postgres_vectorchord`
|
||||
- `/mnt/user/appdata/nextcloud/postgres18`
|
||||
- `/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,5 +20,9 @@
|
||||
/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:b44c0a92b650d80f215a986dadda5c2604c61eb28a7571e19c046eff41d761e7
|
||||
image: ainullcode/borg-ui@sha256:0922157e8f77a1b2bd23cd09366a458ea6de07fd9306aa1485f9cfe623eca17f
|
||||
container_name: borg-ui
|
||||
restart: unless-stopped
|
||||
security_opt:
|
||||
|
||||
@@ -278,7 +278,7 @@ main() {
|
||||
need_cmd sha256sum
|
||||
ensure_dirs
|
||||
|
||||
# Shared PostgreSQL 17
|
||||
# Shared PostgreSQL 18 (historischer Containername: postgresql17)
|
||||
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 "/mnt/user/appdata/grafana/grafana.db" "$LATEST_DIR/grafana.sqlite" "grafana"
|
||||
dump_sqlite_file "/var/lib/docker/volumes/monitoring_grafana_data/_data/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