Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e4140ea11 | |||
| c3491eb382 | |||
| 023ee63687 | |||
| 3a263a4846 | |||
| 68d3ace598 | |||
| 0ef98a23e1 | |||
| 6353da47c5 | |||
| 207f49f001 | |||
| a687d9b73e | |||
| e3459c76d0 | |||
| 254eb81496 | |||
| 9a6d7123ce | |||
| 151d253aff |
@@ -90,7 +90,7 @@ Wenn Drift vermutet wird, nicht raten. Erst die Pflichtmatrix in `docs/GITOPS_DR
|
|||||||
- `traefik`: Host-Ports 80/443
|
- `traefik`: Host-Ports 80/443
|
||||||
- `gitea`: SSH-Port 222
|
- `gitea`: SSH-Port 222
|
||||||
- `AdGuard Home`: DNS-Port 53 und LAN-Admin-Port 8082
|
- `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
|
- `Plex-Media-Server`: historischer Host-Netz-Sonderfall, nicht als Repo-Stack enthalten
|
||||||
- `scrutiny`: `privileged: true` fuer SMART/Laufwerkszugriff
|
- `scrutiny`: `privileged: true` fuer SMART/Laufwerkszugriff
|
||||||
- `Komodo`: Docker-Socket und native Auth ohne pauschale ForwardAuth
|
- `Komodo`: Docker-Socket und native Auth ohne pauschale ForwardAuth
|
||||||
|
|||||||
@@ -240,7 +240,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 |
|
| `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 | — |
|
| `unbound` | ✅ | `dns_net` | intern | Upstream-Resolver für AdGuard, isoliert | — |
|
||||||
| `ddns-updater` | ✅ | `frontend_net` | intern | Cloudflare DNS API; bleibt in `frontend_net` | Dokumentierte Ausnahme |
|
| `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
|
### 7.2 Sicherheit / Identity
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ in `docs/RESTORE_MATRIX.md` ergaenzt.
|
|||||||
|
|
||||||
| Prioritaet | Punkt | Naechster Schritt |
|
| Prioritaet | Punkt | Naechster Schritt |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| P1 | DR-Workstation Bare-Metal-Kit: WSL2 + Borg-Client installieren | Hetzner-DR-SSH-Key ist 2026-06-03 erledigt und offline gesichert. Verbleibend: WSL2 auf dem Gaming-PC einrichten (`wsl --install -d Ubuntu`), `sudo apt install borgbackup` und ein erster Smoke `borg list ssh://u565255@u565255.your-storagebox.de/./hetzner_borg_appdata_critical` mit dem offline gesicherten Key + Passphrase. Bestandteile dokumentiert in `docs/EXTERNAL_DEPENDENCIES.md` Abschnitt "DR-Workstation Bare-Metal-Kit" |
|
|
||||||
| P2 | Family-Onboarding praktisch starten | Fokus: Vaultwarden als Passwortbasis, Immich-Mobile-Backup auf jedem Handy, Mealie mit erstem Rezept/Einkaufsliste; Ablauf steht in `docs/FAMILY_ONBOARDING.md` |
|
| P2 | Family-Onboarding praktisch starten | Fokus: Vaultwarden als Passwortbasis, Immich-Mobile-Backup auf jedem Handy, Mealie mit erstem Rezept/Einkaufsliste; Ablauf steht in `docs/FAMILY_ONBOARDING.md` |
|
||||||
|
|
||||||
## Restore-Audit Backlog (Stand 2026-06-03)
|
## Restore-Audit Backlog (Stand 2026-06-03)
|
||||||
@@ -44,6 +43,7 @@ Ergebnis des Restore-Skills-Audits (Session 2026-06-02/03). Die kritischen Bugfi
|
|||||||
|
|
||||||
## Zuletzt geschlossen
|
## Zuletzt geschlossen
|
||||||
|
|
||||||
|
- DR-Workstation Bare-Metal-Kit abgeschlossen (2026-06-06): WSL2 Ubuntu 24.04, SSH/Git, Borg 1.2.8, DR-Key-Arbeitskopien `~/.ssh/dr-readonly` und `~/.ssh/dr-hetzner`, `~/dr-smoke.sh`. Finaler Operator-Smoke erfolgreich: GitHub HEAD `3a263a4...`, Hetzner Storage Box Repos sichtbar (`backup`, `backup2`, `hetzner_borg_appdata`, `hetzner_borg_appdata_critical`), Borg-Repo `hetzner_borg_appdata_critical` gelesen, Repository ID `5dd9b949...`, encrypted `Yes (repokey)`, `DR-Smoke OK (2026-06-06 10:05:30)`. Borg-Passphrase wurde nur interaktiv eingegeben und nicht gespeichert.
|
||||||
- Nextcloud-Restore-Test 2026-06-03 erfolgreich (Tier-2 damit komplett belegt). Drei Laeufe noetig: Lauf 1 schlug an `chmod()` der data-Dir auf shfs fehl (`OC_Util.php:486`), Lauf 2 an fehlender `.ncdata`-Marker-Datei, Lauf 3 sauber durch. Beide Bug-Fixes ins Skript `ops/restore-tests/nextcloud-restore-test.sh` integriert. Endresultat: HTTP 200 auf `/status.php`, `occ status` ok, 126 Tabellen in der DB. Source: `hetzner_borg_appdata_critical`, Archiv `Taegliche-Sicherung-2026-06-03T04:30:41.432`. Report unter `/mnt/user/backups/restore-reports/nextcloud-2026-06-03.md`.
|
- Nextcloud-Restore-Test 2026-06-03 erfolgreich (Tier-2 damit komplett belegt). Drei Laeufe noetig: Lauf 1 schlug an `chmod()` der data-Dir auf shfs fehl (`OC_Util.php:486`), Lauf 2 an fehlender `.ncdata`-Marker-Datei, Lauf 3 sauber durch. Beide Bug-Fixes ins Skript `ops/restore-tests/nextcloud-restore-test.sh` integriert. Endresultat: HTTP 200 auf `/status.php`, `occ status` ok, 126 Tabellen in der DB. Source: `hetzner_borg_appdata_critical`, Archiv `Taegliche-Sicherung-2026-06-03T04:30:41.432`. Report unter `/mnt/user/backups/restore-reports/nextcloud-2026-06-03.md`.
|
||||||
- Hetzner Storage Box DR-SSH-Key `dr-hetzner-2026-06-03` (ed25519, Passphrase-frei) angelegt: Pubkey via `install-ssh-key` auf der Storage Box autorisiert, passwortloser Login erfolgreich (Borg-Repos `backup`, `backup2`, `hetzner_borg_appdata`, `hetzner_borg_appdata_critical` sichtbar), Private-Key offline neben KOMODO_*-Notiz und GitHub-Deploy-Key abgelegt, Arbeitsplatz-Kopie geloescht. Damit ist Bare-Metal-Borg-Zugang von der DR-Workstation moeglich, sobald WSL2+Borg installiert sind.
|
- Hetzner Storage Box DR-SSH-Key `dr-hetzner-2026-06-03` (ed25519, Passphrase-frei) angelegt: Pubkey via `install-ssh-key` auf der Storage Box autorisiert, passwortloser Login erfolgreich (Borg-Repos `backup`, `backup2`, `hetzner_borg_appdata`, `hetzner_borg_appdata_critical` sichtbar), Private-Key offline neben KOMODO_*-Notiz und GitHub-Deploy-Key abgelegt, Arbeitsplatz-Kopie geloescht. Damit ist Bare-Metal-Borg-Zugang von der DR-Workstation moeglich, sobald WSL2+Borg installiert sind.
|
||||||
- Fix Common Problems Plugin (FCP) 2026-06-03 deinstalliert. Befund: drei `grep -R ... /usr/local/emhttp`-Prozesse aus einem FCP-Daily-Scan hingen seit ~7 Tagen in einem Symlink-Loop (`/usr/local/emhttp/mnt -> /mnt`, gesamte Array). 3 Cores dauerhaft 100 %, IOWAIT bis 55 %, USB-Flash unter Dauer-IO. Plugin via `plugin remove` entfernt, Cron + /tmp-Reste sauber, Load von 14.6 auf 1.08 gefallen. FCP wird bewusst nicht wieder installiert (Begruendung siehe `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 13). Bekannte Risiken decken Scrutiny, Monitoring, Posture-Check und Critical-Events-Watcher bereits ab.
|
- Fix Common Problems Plugin (FCP) 2026-06-03 deinstalliert. Befund: drei `grep -R ... /usr/local/emhttp`-Prozesse aus einem FCP-Daily-Scan hingen seit ~7 Tagen in einem Symlink-Loop (`/usr/local/emhttp/mnt -> /mnt`, gesamte Array). 3 Cores dauerhaft 100 %, IOWAIT bis 55 %, USB-Flash unter Dauer-IO. Plugin via `plugin remove` entfernt, Cron + /tmp-Reste sauber, Load von 14.6 auf 1.08 gefallen. FCP wird bewusst nicht wieder installiert (Begruendung siehe `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 13). Bekannte Risiken decken Scrutiny, Monitoring, Posture-Check und Critical-Events-Watcher bereits ab.
|
||||||
|
|||||||
@@ -290,7 +290,14 @@ Erfolgskriterium: `docker network ls` zeigt `frontend_net`, `backend_net`, `moni
|
|||||||
|
|
||||||
1. `traefik/`
|
1. `traefik/`
|
||||||
2. `host-services/Adguard/`
|
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.
|
**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.
|
||||||
|
|
||||||
|
|||||||
@@ -115,6 +115,15 @@ Erwartet: HEAD und mindestens ein `refs/heads/master`-Eintrag.
|
|||||||
|
|
||||||
Damit der "ich pruefe das vierteljaehrlich"-Schritt zur Routine wird, ein kleines Skript ins WSL-Home:
|
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
|
```bash
|
||||||
cat > ~/dr-smoke.sh <<'EOF'
|
cat > ~/dr-smoke.sh <<'EOF'
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|||||||
@@ -107,3 +107,4 @@ Operative Regel: Die DR-Workstation wird nicht als Test-/Spiel-PC betrachtet. WS
|
|||||||
| 2026-06-03 | KOMODO_*-Notiz offline gesichert (Operator-Bestaetigung im DR-Tabletop-Followup). Quelle bleibt host-seitige `.env` (`/mnt/user/services/stacks/komodo/.env`) bzw. Drift-Recovery-Kopie vom 2026-05-04. Bare-Metal-Komodo-Bootstrap ist damit ohne Vaultwarden moeglich. | Restliche P1-Operator-Aufgaben: GitHub-Read-PAT, DR-Workstation-Setup, Nextcloud-Restore-Test |
|
| 2026-06-03 | KOMODO_*-Notiz offline gesichert (Operator-Bestaetigung im DR-Tabletop-Followup). Quelle bleibt host-seitige `.env` (`/mnt/user/services/stacks/komodo/.env`) bzw. Drift-Recovery-Kopie vom 2026-05-04. Bare-Metal-Komodo-Bootstrap ist damit ohne Vaultwarden moeglich. | Restliche P1-Operator-Aufgaben: GitHub-Read-PAT, DR-Workstation-Setup, Nextcloud-Restore-Test |
|
||||||
| 2026-06-03 | GitHub-Mirror Read-Only Deploy-Key `DR Read-Only 2026-06-03` (ed25519, Passphrase-frei) erzeugt, in GitHub Repo Settings ohne Write-Access hinterlegt, Smoke `git ls-remote` erfolgreich (`d947c7f` matched master HEAD), Private-Key offline neben KOMODO_*-Notiz abgelegt, Arbeitsplatz-Kopie geloescht. | Restliche P1-Operator-Aufgaben: DR-Workstation-Setup, Nextcloud-Restore-Test |
|
| 2026-06-03 | GitHub-Mirror Read-Only Deploy-Key `DR Read-Only 2026-06-03` (ed25519, Passphrase-frei) erzeugt, in GitHub Repo Settings ohne Write-Access hinterlegt, Smoke `git ls-remote` erfolgreich (`d947c7f` matched master HEAD), Private-Key offline neben KOMODO_*-Notiz abgelegt, Arbeitsplatz-Kopie geloescht. | Restliche P1-Operator-Aufgaben: DR-Workstation-Setup, Nextcloud-Restore-Test |
|
||||||
| 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-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 |
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
# Home Assistant -> InfluxDB 3 -> Grafana
|
# 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.
|
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.
|
- Home Assistant ist per SSH unter `192.168.178.50:22222` erreichbar.
|
||||||
- `ha core check` ist erfolgreich.
|
- `ha core check` ist erfolgreich.
|
||||||
|
|||||||
+9
-9
@@ -1,6 +1,6 @@
|
|||||||
# Master To-do - KalliLab CORE
|
# Master To-do - KalliLab CORE
|
||||||
|
|
||||||
Stand: 2026-06-05 (Wochenend-Sprint, nach Status-Kategorien sortiert)
|
Stand: 2026-06-06 (Wochenend-Sprint, nach Status-Kategorien sortiert)
|
||||||
|
|
||||||
Diese Liste ist die zentrale Arbeitsliste fuer offene operative Punkte im
|
Diese Liste ist die zentrale Arbeitsliste fuer offene operative Punkte im
|
||||||
Homelab. Detailentscheidungen bleiben in den verlinkten Runbooks; diese Datei
|
Homelab. Detailentscheidungen bleiben in den verlinkten Runbooks; diese Datei
|
||||||
@@ -23,14 +23,9 @@ Host-/Entscheidungsaufgaben beim **Operator**.
|
|||||||
|
|
||||||
| Thema | Owner | Naechster konkreter Schritt | Quelle |
|
| Thema | Owner | Naechster konkreter Schritt | Quelle |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| DR-Workstation Bare-Metal-Kit | Operator | Auf dem Gaming-PC `wsl --install -d Ubuntu`, dann `sudo apt install borgbackup`, dann Smoke `borg list ssh://u565255@u565255.your-storagebox.de/./hetzner_borg_appdata_critical` mit offline gesichertem Key + Passphrase | `docs/AUDIT_2026-05-25_TODO.md`, `docs/DR_WORKSTATION_SETUP.md`, `docs/EXTERNAL_DEPENDENCIES.md` |
|
|
||||||
| Family-Onboarding erster Termin | Operator | Checkliste ist fertig (`docs/FAMILY_ONBOARDING.md` Abschnitt "Erster Onboarding-Termin"). Operator legt fest, welche Personen/Geraete real verfuegbar sind, und arbeitet die Reihenfolge Vaultwarden -> Immich -> Mealie pro Person ab | `docs/FAMILY_ONBOARDING.md`, `docs/AUDIT_2026-05-25_TODO.md` |
|
| Family-Onboarding erster Termin | Operator | Checkliste ist fertig (`docs/FAMILY_ONBOARDING.md` Abschnitt "Erster Onboarding-Termin"). Operator legt fest, welche Personen/Geraete real verfuegbar sind, und arbeitet die Reihenfolge Vaultwarden -> Immich -> Mealie pro Person ab | `docs/FAMILY_ONBOARDING.md`, `docs/AUDIT_2026-05-25_TODO.md` |
|
||||||
| Home Assistant -> InfluxDB Token | Operator | `influxdb3_homeassistant_token` in InfluxDB 3 erzeugen, in HA `secrets.yaml` ablegen, einen Write-Pfad-Test fahren; nur Variablennamen/Pfade dokumentieren, kein Wert ins Repo | `docs/SECRETS_MAP.md`, `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md` |
|
|
||||||
| Restore-Test Unraid OS Flash (Stick-Boot) | Operator | Artefakt-Validierung am 2026-06-05 erledigt (`ops/maintenance/check-unraid-flash-backup.sh`, sha256 OK, 8 Kern-Configs). **Verbleibt:** physischer Ersatzstick-Boot-Test, wenn ein Wegwerf-Stick bereitliegt | `docs/RESTORE_MATRIX.md` Abschnitt "Unraid OS Flash" |
|
| Restore-Test Unraid OS Flash (Stick-Boot) | Operator | Artefakt-Validierung am 2026-06-05 erledigt (`ops/maintenance/check-unraid-flash-backup.sh`, sha256 OK, 8 Kern-Configs). **Verbleibt:** physischer Ersatzstick-Boot-Test, wenn ein Wegwerf-Stick bereitliegt | `docs/RESTORE_MATRIX.md` Abschnitt "Unraid OS Flash" |
|
||||||
| Restore-Test AdGuard Home | Operator | Runbook-Stub abarbeiten: Config nach `/mnt/user/backups/restore-lab/adguard` extrahieren, Testcontainer auf Port `5353`/`3001`, DNS-Smoke | `docs/RESTORE_MATRIX.md` Abschnitt "AdGuard Home" |
|
|
||||||
| Restore-Test Tailscale | Operator | Runbook-Stub abarbeiten: State-Validierung + Reconnect nur auf Wegwerf-Host/VM, danach Geraet in Tailscale-Admin entfernen | `docs/RESTORE_MATRIX.md` Abschnitt "Tailscale" |
|
| Restore-Test Tailscale | Operator | Runbook-Stub abarbeiten: State-Validierung + Reconnect nur auf Wegwerf-Host/VM, danach Geraet in Tailscale-Admin entfernen | `docs/RESTORE_MATRIX.md` Abschnitt "Tailscale" |
|
||||||
| Restore-Test Redis 8 | Operator | Runbook-Stub abarbeiten: Pre-Cutover-Backup in isolierte Instanz auf Port `16379`, `PING` + `INFO server` (8.x) + `DBSIZE` pruefen | `docs/RESTORE_MATRIX.md` Abschnitt "Redis 8 (Shared)" |
|
|
||||||
| Manuelle App-/Lizenzchecks `baerchen` | Codex/Operator | Passwortmanager/2FA-Recovery-Codes, Banking4, WISO, Microsoft/M365/OneDrive im laufenden System bestaetigen | `ops/windows-reinstall/docs/windows-neuaufsetzen-masterplan.md` |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -41,7 +36,6 @@ Host-/Entscheidungsaufgaben beim **Operator**.
|
|||||||
| BitLocker-Entscheidung `baerchen` | C: (und ggf. D:) aktivieren oder bewusst deaktiviert lassen? Bei Ja: Recovery-Key vorher nach `D:\30_Finanzen\...`, Vaultwarden und physisch sichern. (Claude fasst BitLocker bewusst nicht an.) | `docs/SECRETS_MAP.md`, `ops/windows-reinstall/docs/laufwerks-neustruktur-2026-06-04.md` |
|
| BitLocker-Entscheidung `baerchen` | C: (und ggf. D:) aktivieren oder bewusst deaktiviert lassen? Bei Ja: Recovery-Key vorher nach `D:\30_Finanzen\...`, Vaultwarden und physisch sichern. (Claude fasst BitLocker bewusst nicht an.) | `docs/SECRETS_MAP.md`, `ops/windows-reinstall/docs/laufwerks-neustruktur-2026-06-04.md` |
|
||||||
| Veeam Storage Encryption `baerchen` | Reicht der erste unverschluesselte Full-Lauf, oder soll Veeam Storage Encryption aktiviert werden? Bei Ja: Passwort in Vaultwarden anlegen, Job umstellen und neues Full-Backup erzeugen | `ops/windows-reinstall/docs/windows-image-backup-baseline.md`, `docs/SECRETS_MAP.md` |
|
| Veeam Storage Encryption `baerchen` | Reicht der erste unverschluesselte Full-Lauf, oder soll Veeam Storage Encryption aktiviert werden? Bei Ja: Passwort in Vaultwarden anlegen, Job umstellen und neues Full-Backup erzeugen | `ops/windows-reinstall/docs/windows-image-backup-baseline.md`, `docs/SECRETS_MAP.md` |
|
||||||
| Stromverbrauch messen | Messgeraet/Smart-Plug beschaffen? Ohne Geraet bleiben Idle/Normal/Backup/Last bewusst offen. **Status 2026-06-05: kein Geraet vorhanden.** | `docs/HARDWARE_INVENTORY.md` Abschnitt "Stromverbrauch" |
|
| Stromverbrauch messen | Messgeraet/Smart-Plug beschaffen? Ohne Geraet bleiben Idle/Normal/Backup/Last bewusst offen. **Status 2026-06-05: kein Geraet vorhanden.** | `docs/HARDWARE_INVENTORY.md` Abschnitt "Stromverbrauch" |
|
||||||
| Tailscale ACL-Policy | **Entwurf abgestimmt 2026-06-05, noch nicht angewendet.** Richtung: Tag-basiert (`tag:server`/`tag:operator`/`tag:family`), Allow-all spaeter ersetzen; `baerchen-1`+`iphone-14` = operator, `kallilabcore` = server, Familie nur gezielte Dienste. Heute bewusst nur Sichtung, kein Tagging. **Offen vor Umsetzung:** (1) aktuellen ACL-JSON read-only sichten, (2) konkrete Familien-Dienste/Ports festlegen, (3) lockout-sichere Tagging-Reihenfolge + Smoke-Tests mit Operator durchfuehren | `docs/NETWORK_INVENTORY.md` Abschnitt "ACL-Policy — Entwurf und Rollout-Plan" |
|
|
||||||
| Nextcloud 2FA / Brute-Force-Haertung | Operator-TOTP (`twofactor_totp`) jetzt aktivieren? Familien-/OIDC-weite Policy separat | `docs/AUDIT_2026-05-25_TODO.md` |
|
| Nextcloud 2FA / Brute-Force-Haertung | Operator-TOTP (`twofactor_totp`) jetzt aktivieren? Familien-/OIDC-weite Policy separat | `docs/AUDIT_2026-05-25_TODO.md` |
|
||||||
| Authelia Rest-2FA | Weitere Admin-UIs (`monitoring`, `glances`, `glance`, `speedtest`, `pdf`, `mail`, `sp` ...) von `one_factor` auf `two_factor` heben oder bewusst belassen? | `docs/AUDIT_2026-05-25_TODO.md` |
|
| Authelia Rest-2FA | Weitere Admin-UIs (`monitoring`, `glances`, `glance`, `speedtest`, `pdf`, `mail`, `sp` ...) von `one_factor` auf `two_factor` heben oder bewusst belassen? | `docs/AUDIT_2026-05-25_TODO.md` |
|
||||||
| Authelia OIDC fuer Apps | App-uebergreifendes SSO einfuehren - haengt an Familien-/SSO-Grundsatzentscheidung | `docs/AUDIT_2026-05-25_TODO.md` |
|
| Authelia OIDC fuer Apps | App-uebergreifendes SSO einfuehren - haengt an Familien-/SSO-Grundsatzentscheidung | `docs/AUDIT_2026-05-25_TODO.md` |
|
||||||
@@ -58,12 +52,12 @@ Bewusst nicht jetzt - mit Review-Trigger.
|
|||||||
| USV-Anschaffung | **Auf Q3/2026 geparkt** (2026-06-05). Power-Loss bleibt akzeptiertes Risiko. Trigger: Hardware-Upgrade, realer Stromausfall mit Datenfolge, oder Q3-Review ab 2026-07-01 | `docs/HARDWARE_INVENTORY.md` |
|
| USV-Anschaffung | **Auf Q3/2026 geparkt** (2026-06-05). Power-Loss bleibt akzeptiertes Risiko. Trigger: Hardware-Upgrade, realer Stromausfall mit Datenfolge, oder Q3-Review ab 2026-07-01 | `docs/HARDWARE_INVENTORY.md` |
|
||||||
| Cold-Backup-Rotation | **Bewusst Hetzner-only** (2026-06-05). Keine zweite rotierende Cold-Kopie. Trigger: stark wachsender Datenwert, wiederholte Hetzner-Probleme, geaenderte Praeferenz | `docs/HARDWARE_INVENTORY.md` |
|
| Cold-Backup-Rotation | **Bewusst Hetzner-only** (2026-06-05). Keine zweite rotierende Cold-Kopie. Trigger: stark wachsender Datenwert, wiederholte Hetzner-Probleme, geaenderte Praeferenz | `docs/HARDWARE_INVENTORY.md` |
|
||||||
| WAN-Ausfallschutz | **Spaeter evaluieren** (2026-06-05). Mobilfunk-Failover inaktiv; lokale Apps laufen bei WAN-Ausfall weiter. Trigger: haeufigere/laengere DSL-Ausfaelle oder kritischer Remote-Zugang | `docs/NETWORK_INVENTORY.md` |
|
| WAN-Ausfallschutz | **Spaeter evaluieren** (2026-06-05). Mobilfunk-Failover inaktiv; lokale Apps laufen bei WAN-Ausfall weiter. Trigger: haeufigere/laengere DSL-Ausfaelle oder kritischer Remote-Zugang | `docs/NETWORK_INVENTORY.md` |
|
||||||
| Home Assistant InfluxDB Bind | Aktuell `127.0.0.1:8181`, validiert. Nur wenn HA nicht lokal auf den Host schreibt, bewusste Bind-Aenderung planen | `docs/NETWORK_INVENTORY.md` |
|
|
||||||
| Docker Critical Events Watcher | **Aktiviert 2026-06-05:** Unraid User Script `docker-critical-events-at-start` nutzt den Supervisor und steht in `schedule.json` auf `frequency: start`; Watcher manuell gestartet, Status `running`. Optionaler ntfy-Smoke wurde nachts bewusst nicht gesendet und kann spaeter mit `docker-critical-events-supervisor.sh smoke` nachgeholt werden | `docs/SERVICE_CATALOG.md`, `services/posture-check/docker-critical-events.sh`, `services/posture-check/unraid-user-scripts.md` |
|
| Docker Critical Events Watcher | **Aktiviert 2026-06-05:** Unraid User Script `docker-critical-events-at-start` nutzt den Supervisor und steht in `schedule.json` auf `frequency: start`; Watcher manuell gestartet, Status `running`. Optionaler ntfy-Smoke wurde nachts bewusst nicht gesendet und kann spaeter mit `docker-critical-events-supervisor.sh smoke` nachgeholt werden | `docs/SERVICE_CATALOG.md`, `services/posture-check/docker-critical-events.sh`, `services/posture-check/unraid-user-scripts.md` |
|
||||||
| Negativ-Test Backup-Frische | Quartalsweise: bewusst kaputten/fehlenden Dump in Testpfad simulieren, pruefen ob `homelab-alerts` feuert | `docs/AUDIT_2026-05-25_TODO.md` |
|
| Negativ-Test Backup-Frische | Quartalsweise: bewusst kaputten/fehlenden Dump in Testpfad simulieren, pruefen ob `homelab-alerts` feuert | `docs/AUDIT_2026-05-25_TODO.md` |
|
||||||
| End-to-end-DR-Drill | Komplett-Bootstrap Phase 1-5 auf Wegwerf-Host; realistisch erst mit zweiter Hardware (siehe auch Extern blockiert) | `docs/AUDIT_2026-05-25_TODO.md`, `docs/DISASTER_RECOVERY.md` |
|
| End-to-end-DR-Drill | Komplett-Bootstrap Phase 1-5 auf Wegwerf-Host; realistisch erst mit zweiter Hardware (siehe auch Extern blockiert) | `docs/AUDIT_2026-05-25_TODO.md`, `docs/DISASTER_RECOVERY.md` |
|
||||||
| Wiederkehrende Restore-Drills | Vaultwarden, Gitea, Authelia, Komodo, Paperless, Immich, Traefik, PostgreSQL, Mongo, Nextcloud, Mealie, Mail-Archiver nach Matrix-Intervallen rotieren | `docs/RESTORE_MATRIX.md`, `docs/RESTORE_HANDBOOK.md` |
|
| Wiederkehrende Restore-Drills | Vaultwarden, Gitea, Authelia, Komodo, Paperless, Immich, Traefik, PostgreSQL, Mongo, Nextcloud, Mealie, Mail-Archiver nach Matrix-Intervallen rotieren | `docs/RESTORE_MATRIX.md`, `docs/RESTORE_HANDBOOK.md` |
|
||||||
| Dedizierter SMB-User `veeam-baerchen` | Optional spaeter, nur wenn Unraid-User-/Share-Rechte bewusst angefasst werden | `ops/windows-reinstall/docs/windows-image-backup-baseline.md` |
|
| Dedizierter SMB-User `veeam-baerchen` | Optional spaeter, nur wenn Unraid-User-/Share-Rechte bewusst angefasst werden | `ops/windows-reinstall/docs/windows-image-backup-baseline.md` |
|
||||||
|
| Tailnet-Konsole aufraeumen (Rest) | Nach Docker-Stack-Abbau (2026-06-06) nur noch tote Node-Eintraege: `kallilab-core` (down) und alter Offline-`baerchen` in der Tailscale-Admin-Konsole entfernen. Optional State-Pfad `/mnt/user/appdata/tailscale` nach `_archive/`. Trivial, kein Risiko | `docs/NETWORK_INVENTORY.md` |
|
||||||
| CrowdSec vor Traefik | Bewusst nicht umgesetzt; einzige WAN-Tuer ist `443/tcp`, Authelia `regulation:` deckt Brute-Force ab. Neu bewerten bei breiterer Attack Surface | `docs/AUDIT_2026-05-25_TODO.md` |
|
| CrowdSec vor Traefik | Bewusst nicht umgesetzt; einzige WAN-Tuer ist `443/tcp`, Authelia `regulation:` deckt Brute-Force ab. Neu bewerten bei breiterer Attack Surface | `docs/AUDIT_2026-05-25_TODO.md` |
|
||||||
| Hermes-Agent | NAS-Stack bleibt deaktiviert; Review-Deadline 2026-07-25 | `docs/AUDIT_2026-05-25_TODO.md`, `docs/SERVICE_CATALOG.md` |
|
| Hermes-Agent | NAS-Stack bleibt deaktiviert; Review-Deadline 2026-07-25 | `docs/AUDIT_2026-05-25_TODO.md`, `docs/SERVICE_CATALOG.md` |
|
||||||
| Filebrowser-Mounts | Bei zukuenftigem Hardening-Sprint Mount-Scope reduzieren | `docs/SERVICE_CATALOG.md` |
|
| Filebrowser-Mounts | Bei zukuenftigem Hardening-Sprint Mount-Scope reduzieren | `docs/SERVICE_CATALOG.md` |
|
||||||
@@ -98,7 +92,13 @@ Wartet auf ein externes Ereignis oder eine Abhaengigkeit.
|
|||||||
- `docs/FAMILY_ONBOARDING.md`: Michi-Checkliste in eine echte Erste-Termin-Checkliste (Vorbereitung, Reihenfolge, Erfolgskriterium, bewusst spaeter) umgebaut.
|
- `docs/FAMILY_ONBOARDING.md`: Michi-Checkliste in eine echte Erste-Termin-Checkliste (Vorbereitung, Reihenfolge, Erfolgskriterium, bewusst spaeter) umgebaut.
|
||||||
- `docs/MASTER_TODO.md` in vier Status-Kategorien (Aktiv / Operator-Entscheidung / Geparkt / Extern blockiert) umstrukturiert.
|
- `docs/MASTER_TODO.md` in vier Status-Kategorien (Aktiv / Operator-Entscheidung / Geparkt / Extern blockiert) umstrukturiert.
|
||||||
- `baerchen` Veeam-Erstbackup: erster Full-Lauf 2026-06-05 erfolgreich geschrieben (Veeam-GUI 53,8 GB, Dauer 0:11:31, MetaCheck 0 Fehler/0 Warnungen, VSS `job: success`). Beleg in `ops/windows-reinstall/docs/windows-image-backup-baseline.md`; Veeam Storage Encryption war im ersten Lauf nicht aktiv und ist als Operator-Entscheidung nachgezogen.
|
- `baerchen` Veeam-Erstbackup: erster Full-Lauf 2026-06-05 erfolgreich geschrieben (Veeam-GUI 53,8 GB, Dauer 0:11:31, MetaCheck 0 Fehler/0 Warnungen, VSS `job: success`). Beleg in `ops/windows-reinstall/docs/windows-image-backup-baseline.md`; Veeam Storage Encryption war im ersten Lauf nicht aktiv und ist als Operator-Entscheidung nachgezogen.
|
||||||
- Docker Critical Events Watcher auf Unraid aktiviert: Host-Clone auf Commit `2f3d184` aktualisiert, User Script `/boot/config/plugins/user.scripts/scripts/docker-critical-events-at-start/script` auf den Supervisor umgestellt, altes Script als `script.bak-20260605-232621` gesichert, `schedule.json` zeigt `frequency: start`, Watcher laeuft mit PID `1681168`. ntfy-Smoke bewusst nicht nachts gesendet.
|
- Docker Critical Events Watcher auf Unraid aktiviert: Host-Clone auf Commit `2f3d184` aktualisiert, User Script `/boot/config/plugins/user.scripts/scripts/docker-critical-events-at-start/script` auf den Supervisor umgestellt, altes Script als `script.bak-20260605-232621` gesichert, `schedule.json` zeigt `frequency: start`, Watcher laeuft mit PID `1681168`. ntfy-Smoke am 2026-06-06 erfolgreich beim Operator angekommen.
|
||||||
|
- Restore-Test AdGuard Home: automatisierter Test `ops/restore-tests/adguard-restore-test.sh` erstellt und am 2026-06-06 auf Unraid erfolgreich ausgefuehrt. Ergebnis: Borg-Config-Restore aus Archiv `Taegliche-Sicherung-2026-06-06T04:30:05.910`, isolierter Container `restoretest-adguard`, HTTP `/control/status` = `401`, DNS-Smoke `git.kaleschke.info -> 192.168.178.58`, 7 Filterlisten-Eintraege, Report `/mnt/user/backups/restore-reports/adguard-2026-06-06.md`.
|
||||||
|
- Restore-Test Redis 8: automatisierter Test `ops/restore-tests/redis-restore-test.sh` erstellt und am 2026-06-06 auf Unraid erfolgreich ausgefuehrt. Ergebnis: Restore aus `/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-20260531-185011`, isolierter Container `restoretest-redis`, `PING` = `PONG`, Redis `8.8.0`, AOF `1`, `DBSIZE` = `1`, Report `/mnt/user/backups/restore-reports/redis-2026-06-06.md`.
|
||||||
|
- **Tailscale ACL-Policy restriktiv ausgerollt (2026-06-06):** Von Default-Allow auf Tag-basierte `grants`-Policy umgestellt, gemeinsam mit dem Operator in lockout-sicherer Reihenfolge (additiv -> taggen -> Allow-all entfernen), jeder Schritt read-only per SSH verifiziert. Live: `kallilabcore`=`tag:server`, `baerchen-1`+`iphone-14`=`tag:operator`, `tag:family` vorbereitet/schlafend. Subnet-Route `192.168.178.0/24` bleibt via `autoApprovers` approved. Smoke-Tests gruen (Operator-SSH, AdGuard-Admin `HTTP 302` ueber Tailnet, Ping 0%); untagged Nodes (`kallilab-core` Docker-Sidecar, alter `baerchen`) isoliert. Beleg: `docs/NETWORK_INVENTORY.md` Abschnitt "ACL-Policy — ANGEWENDET 2026-06-06". Familien-Dienste konkretisieren bei erstem realem Familiengeraet.
|
||||||
|
- **Redundanten Docker-Tailscale-Stack entfernt (2026-06-06):** Befund: Host hatte zwei `tailscaled` — die funktionale native Plugin-Instanz `kallilabcore` (echtes TUN `tailscale1`, Subnet-Router, State im Flash-Backup) und den redundanten userspace-only Docker-Stack `kallilab-core` (`host-services/tailscale/`, routet nichts, nichts haengt dran). Sauber per GitOps abgebaut: Operator hat Komodo-Stack `tailscale` gestoppt+destroyed; danach `git rm host-services/tailscale/`, Glance-Widget entfernt, Architektur-/Service-Catalog-/DR-Bootstrap-/CLAUDE-/Restore-Matrix-/Netzwerk-Doku auf "natives Plugin" nachgezogen. Read-only verifiziert: Container weg, nur noch der native `tailscaled`, Subnet-Route + Operator-Zugriff intakt. Rest: tote Node-Eintraege in der Admin-Konsole entfernen (eigener Todo).
|
||||||
|
|
||||||
|
- DR-Workstation Bare-Metal-Kit abgeschlossen: WSL2 Ubuntu 24.04 auf `baerchen`, Borg 1.2.8, GitHub-Read-DR-Key und Hetzner-DR-Key in WSL, `~/dr-smoke.sh` vorhanden. Finaler Smoke 2026-06-06 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)`. Passphrase wurde nur interaktiv eingegeben und nicht gespeichert.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+90
-56
@@ -55,7 +55,7 @@ Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`,
|
|||||||
| Tailscale IPv6 | `fd7a:115c:a1e0::2c01:62b2` (gemessen 2026-06-05) |
|
| 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). |
|
| 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. |
|
| 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 | **Operator-Entscheidung offen** — siehe eigener Block unten; durch den aktiven Subnet-Router ist die ACL-Frage sicherheitsrelevanter als zuvor angenommen. |
|
| 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. |
|
||||||
|
|
||||||
### Tailnet-Geraete (Snapshot 2026-06-05)
|
### Tailnet-Geraete (Snapshot 2026-06-05)
|
||||||
|
|
||||||
@@ -65,13 +65,37 @@ Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`,
|
|||||||
| `100.78.133.37` | baerchen-1 | windows | aktiv (aktuelle Operator-Workstation, direct) |
|
| `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.105.203.21` | baerchen | windows | offline, zuletzt vor ~1 Tag gesehen (Alt-Node) |
|
||||||
| `100.73.83.55` | iphone-14 | iOS | bekannt |
|
| `100.73.83.55` | iphone-14 | iOS | bekannt |
|
||||||
| `100.112.0.90` | kallilab-core | linux | gelistet, kein aktiver Verkehr — **moeglicher Alt-/Dubletten-Node**, separat pruefen |
|
| `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. |
|
||||||
|
|
||||||
> Hygiene-Hinweis (kein Secret): Es existieren zwei linux-Nodes mit aehnlichem
|
> **Befund 2026-06-06 (read-only auf dem Host ermittelt):** Der Host hat **zwei**
|
||||||
> Namen (`kallilabcore` und `kallilab-core`) sowie zwei `baerchen`-Nodes
|
> `tailscaled`-Prozesse:
|
||||||
> (`baerchen-1` aktiv, `baerchen` offline). Bei Gelegenheit in der
|
>
|
||||||
> Tailscale-Admin-Konsole pruefen, ob die inaktiven Eintraege stillgelegt werden
|
> 1. **Native Unraid-Plugin** = `kallilabcore` (100.80.98.33). Prozess
|
||||||
> koennen. Das ist Aufraeumarbeit, kein akutes Risiko.
|
> `/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
|
### Subnet-Router-Konsequenz
|
||||||
|
|
||||||
@@ -91,34 +115,22 @@ tailscale ip -4
|
|||||||
tailscale ip -6
|
tailscale ip -6
|
||||||
```
|
```
|
||||||
|
|
||||||
### ACL-Policy — Entwurf und Rollout-Plan (Stand 2026-06-05, NICHT angewendet)
|
### ACL-Policy — ANGEWENDET 2026-06-06 (restriktive Tag-basierte grants)
|
||||||
|
|
||||||
Die Tailnet-ACL wird in der Tailscale-Admin-Konsole unter `Access controls`
|
**Status: live und verifiziert.** Die restriktive Policy wurde am 2026-06-06
|
||||||
verwaltet (kein Wert/Secret gehoert ins Repo). Aktueller Live-Stand ist
|
gemeinsam mit dem Operator in der lockout-sicheren Reihenfolge ausgerollt und
|
||||||
Default-Allow (`src: ["*"] -> dst: ["*:*"]`), d. h. jedes Tailnet-Geraet darf
|
read-only verifiziert (siehe "Rollout-Protokoll" unten). Ausgangspunkt war die
|
||||||
alles inklusive der LAN-Subnet-Route.
|
**unveraenderte Default-Policy** im **`grants`-Schema** (eine Allow-all-Regel,
|
||||||
|
keine Groups/Tags/`autoApprovers`); es gab also keinen eigenen Bestand zu
|
||||||
|
erhalten.
|
||||||
|
|
||||||
**Abgestimmte Richtung (Operator-Entscheidungen 2026-06-05):**
|
> **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.
|
||||||
|
|
||||||
- Ziel ist eine restriktivere, Tag-basierte ACL.
|
**Angewendete Policy (live, kein Secret):**
|
||||||
- Single-User-Realitaet: aktuell gehoeren alle Nodes demselben User
|
|
||||||
`michaelkaleschke@`. Eine Differenzierung Operator/Familie ist nur ueber
|
|
||||||
**Tags** moeglich. Tagging aendert Ownership/Key-Expiry und erfordert je Geraet
|
|
||||||
Re-Auth — deshalb bewusst ein eigener, spaeterer Schritt.
|
|
||||||
- **Heute bewusst nur Sichtung + Entwurf, kein Tagging, keine Anwendung.**
|
|
||||||
- Familiengeraete brauchen Tailnet-Zugriff auf **bestimmte** Dienste (welche
|
|
||||||
genau, ist noch zu konkretisieren) — `tag:family` bekommt gezielte `dst`-Regeln.
|
|
||||||
- `iphone-14` ist ein Operator-Geraet und faellt unter `tag:operator`.
|
|
||||||
|
|
||||||
**Geraete -> Tag (fuer den spaeteren Tagging-Schritt):**
|
|
||||||
|
|
||||||
| Tag | Geraete |
|
|
||||||
|---|---|
|
|
||||||
| `tag:server` | `kallilabcore` (Host, Subnet-Router) |
|
|
||||||
| `tag:operator` | `baerchen-1`, `iphone-14` |
|
|
||||||
| `tag:family` | kuenftige Familiengeraete |
|
|
||||||
|
|
||||||
**Entwurf (Vorschlag, noch nicht in der Konsole gespeichert):**
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -130,42 +142,64 @@ alles inklusive der LAN-Subnet-Route.
|
|||||||
"autoApprovers": {
|
"autoApprovers": {
|
||||||
"routes": { "192.168.178.0/24": ["tag:server"] }
|
"routes": { "192.168.178.0/24": ["tag:server"] }
|
||||||
},
|
},
|
||||||
"acls": [
|
"grants": [
|
||||||
{ "action": "accept", "src": ["tag:operator"], "dst": ["*:*"] },
|
{"src": ["tag:operator"], "dst": ["*"], "ip": ["*"]},
|
||||||
{ "action": "accept", "src": ["tag:server"], "dst": ["tag:operator:*"] },
|
{"src": ["tag:server"], "dst": ["tag:operator"], "ip": ["*"]},
|
||||||
{ "action": "accept", "src": ["tag:family"], "dst": ["100.80.98.33:443"] }
|
{"src": ["tag:family"], "dst": ["tag:server"], "ip": ["tcp:443"]}
|
||||||
],
|
],
|
||||||
"ssh": [
|
"ssh": [
|
||||||
{ "action": "accept", "src": ["tag:operator"], "dst": ["tag:server"],
|
{"action": "check", "src": ["autogroup:member"], "dst": ["autogroup:self"],
|
||||||
"users": ["root", "autogroup:nonroot"] }
|
"users": ["autogroup:nonroot", "root"]}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
> Die `tag:family`-`dst` `100.80.98.33:443` ist ein **Platzhalter** und wird
|
**Geraete-Tags (live):** `kallilabcore` = `tag:server`; `baerchen-1` + `iphone-14`
|
||||||
> durch die real benoetigten Familien-Dienste ersetzt, sobald diese feststehen.
|
= `tag:operator`; `kallilab-core` (Docker) + alter `baerchen` bewusst untagged ->
|
||||||
|
isoliert.
|
||||||
|
|
||||||
**Lockout-sichere Reihenfolge (wenn die Umsetzung freigegeben wird):**
|
**Rollout-Protokoll 2026-06-06 (lockout-sicher, je Schritt read-only verifiziert):**
|
||||||
|
|
||||||
1. `tagOwners` + `autoApprovers` + neue ACL-Regeln speichern, **Allow-all-Regel
|
1. Policy additiv erweitert (Tags/grants definiert, Allow-all noch drin) -> alle Peers unveraendert verbunden, Route approved.
|
||||||
zunaechst behalten**.
|
2. `baerchen-1` getaggt `tag:operator` -> online, verifiziert.
|
||||||
2. Geraete taggen (`baerchen-1`, `iphone-14` -> operator; `kallilabcore` ->
|
3. `iphone-14` getaggt `tag:operator` -> verifiziert.
|
||||||
server) und je Geraet die Verbindung verifizieren.
|
4. `kallilab-core` faktisch geprueft (Docker-Sidecar, keine Abhaengigen) -> bewusst untagged gelassen.
|
||||||
3. Subnet-Route bleibt approved (jetzt via `autoApprovers`/`tag:server`).
|
5. Host `kallilabcore` getaggt `tag:server` -> Route blieb via `autoApprovers` automatisch approved, SSH ok.
|
||||||
4. **Erst zuletzt** die Allow-all-Regel entfernen -> restriktiv schalten.
|
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.
|
||||||
5. Sofort Smoke-Tests fahren (siehe unten).
|
|
||||||
|
|
||||||
**Smoke-Tests nach Anwendung:**
|
**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.
|
||||||
|
|
||||||
- `baerchen-1` erreicht Host: `ping 100.80.98.33`, `ssh kallilabcore hostname` (read-only).
|
**Hintergrund / Designentscheidungen (2026-06-05/06):**
|
||||||
- `baerchen-1` erreicht LAN ueber Route: z. B. AdGuard-Admin `http://100.80.98.33:8082`, `curl -kI https://192.168.178.58`.
|
|
||||||
- Falls testbar: ein nicht-Operator-Geraet erreicht Route/Admin-Ports **nicht** mehr.
|
|
||||||
- Host-Gegencheck: `tailscale status` zeigt alle Soll-Peers weiter verbunden.
|
|
||||||
|
|
||||||
**Noch offene Eingaben vor Finalisierung:**
|
- 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).
|
||||||
|
|
||||||
1. Aktueller ACL-JSON aus der Admin-Konsole (read-only gesichtet, nur Struktur dokumentiert).
|
**Offene Folgepunkte (kein Risiko, Hygiene/spaeter):**
|
||||||
2. Konkrete Liste der Dienste/Ports, die Familiengeraete ueber Tailscale brauchen.
|
|
||||||
|
- 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: Node-Eintraege `kallilab-core` (jetzt down) und
|
||||||
|
alter Offline-`baerchen` entfernen (trivial, nur tote Geraeteeintraege).
|
||||||
|
- 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
|
## Portfreigaben und Exposure
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@ Diese Datei trennt aktive Betriebsdokumentation von historischer Arbeitsdoku. Ne
|
|||||||
|---|---|
|
|---|---|
|
||||||
| `ALERT_RULES.md` | Prometheus-/ntfy-Regeln und Handlungslogik |
|
| `ALERT_RULES.md` | Prometheus-/ntfy-Regeln und Handlungslogik |
|
||||||
| `RENOVATE.md` | Self-hosted Renovate gegen Gitea |
|
| `RENOVATE.md` | Self-hosted Renovate gegen Gitea |
|
||||||
| `HOME_ASSISTANT_INFLUXDB_ECOWITT.md` | Home Assistant -> InfluxDB 3 -> Grafana |
|
| `HOME_ASSISTANT_INFLUXDB_ECOWITT.md` | Archivierter Entwurf: Home Assistant -> InfluxDB 3 -> Grafana; nicht aktiv seit Crash |
|
||||||
| `H_DRIVE_NEARLINE_PULL.md` | Windows-H:/ Nearline-Pull fuer kritische Restore-Artefakte |
|
| `H_DRIVE_NEARLINE_PULL.md` | Windows-H:/ Nearline-Pull fuer kritische Restore-Artefakte |
|
||||||
|
|
||||||
## Nutzer- und Planungsdoku
|
## Nutzer- und Planungsdoku
|
||||||
|
|||||||
+44
-17
@@ -28,10 +28,10 @@ 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 |
|
| 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 |
|
| 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 |
|
| 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 | Share / Borg | `/mnt/user/appdata/tailscale` | keine | Tailscale-State im Pfad | Host-Netz | Tailscale verbunden |
|
| 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` |
|
| 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 |
|
| 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` |
|
| 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 |
|
| 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 |
|
| 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 |
|
||||||
@@ -135,7 +135,7 @@ Die Dump-Erzeugung ist host-seitig ueber `ops/borg-ui/scripts/pre-backup-dumps.s
|
|||||||
|
|
||||||
## Restore-Test-Reifegrad
|
## Restore-Test-Reifegrad
|
||||||
|
|
||||||
Stand 2026-06-05. Pro Dienst auf einen Blick: Wurde der Restore schon einmal real getestet?
|
Stand 2026-06-06. Pro Dienst auf einen Blick: Wurde der Restore schon einmal real getestet?
|
||||||
|
|
||||||
| Dienst | Tier | Letzter Restore-Test | Typ | Naechster Lauf |
|
| Dienst | Tier | Letzter Restore-Test | Typ | Naechster Lauf |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
@@ -147,10 +147,10 @@ Stand 2026-06-05. Pro Dienst auf einen Blick: Wurde der Restore schon einmal rea
|
|||||||
| Immich | 2 | 2026-05-27 | Dump + Container + HTTP + Asset-Count | quartalsweise (2. So Feb/Mai/Aug/Nov) |
|
| 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 |
|
| 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 |
|
| Traefik | 1 | 2026-06-03 | Config + LE-State + File-Provider + Ping 200 | quartalsweise |
|
||||||
| AdGuard Home | 1 | - | noch kein Test | - |
|
| AdGuard Home | 1 | 2026-06-06 | Config + Container + HTTP 401 + DNS + Filter-Count | quartalsweise oder nach DNS-Aenderungen |
|
||||||
| Tailscale | 1 | - | noch kein Test | - |
|
| Tailscale | 1 | - | noch kein Test | - |
|
||||||
| PostgreSQL 18 Cluster | 1 | 2026-06-03 | globals + 5 per-DB dumps, 290 Tabellen gesamt | quartalsweise |
|
| PostgreSQL 18 Cluster | 1 | 2026-06-03 | globals + 5 per-DB dumps, 290 Tabellen gesamt | quartalsweise |
|
||||||
| Redis 8 | 1 | - | noch kein Test | - |
|
| 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 |
|
| 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 |
|
| 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 |
|
| Mealie | 2 | 2026-06-03 | File + Dump + Container + HTTP + Recipe-Count (3) | quartalsweise |
|
||||||
@@ -165,15 +165,13 @@ Stand 2026-06-05. Pro Dienst auf einen Blick: Wurde der Restore schon einmal rea
|
|||||||
|
|
||||||
## Naechste Restore-Test-Kandidaten (priorisiert)
|
## Naechste Restore-Test-Kandidaten (priorisiert)
|
||||||
|
|
||||||
Stand 2026-06-05. Die frueheren Kandidaten (Shared PG18, Komodo Mongo, Mailarchiver, Mealie, Traefik)
|
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.
|
wurden alle am 2026-06-03 abgeschlossen und sind in der Reifegrad-Tabelle belegt.
|
||||||
|
|
||||||
Verbleibende offene Restore-Pfade ohne vollstaendigen Test:
|
Verbleibende offene Restore-Pfade ohne vollstaendigen Test:
|
||||||
|
|
||||||
1. **Unraid OS Flash** - Artefakt-Validierung am 2026-06-05 erfolgreich (siehe Reifegrad-Tabelle und Runbook unten); offen bleibt nur der **physische Ersatzstick-Boot-Test**.
|
1. **Unraid OS Flash** - Artefakt-Validierung am 2026-06-05 erfolgreich (siehe Reifegrad-Tabelle und Runbook unten); offen bleibt nur der **physische Ersatzstick-Boot-Test**.
|
||||||
2. **AdGuard Home** - Config-Restore in Testpfad oder Wegwerf-Instanz pruefen
|
2. **Tailscale** - State-/Reconnect-Pfad dokumentiert testen
|
||||||
3. **Tailscale** - State-/Reconnect-Pfad dokumentiert testen
|
|
||||||
4. **Redis 8 (Shared)** - Restore aus Datenpfad oder Pre-Cutover-Backup in isolierter Testinstanz pruefen
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -225,28 +223,42 @@ nur Eintragsnamen gelistet. Offen bleibt der physische Ersatzstick-Boot-Test.
|
|||||||
|
|
||||||
### AdGuard Home
|
### AdGuard Home
|
||||||
|
|
||||||
|
**Validierungsergebnis 2026-06-06:** Automatisierter Test
|
||||||
|
`ops/restore-tests/adguard-restore-test.sh` auf Unraid erfolgreich ausgefuehrt.
|
||||||
|
Report: `/mnt/user/backups/restore-reports/adguard-2026-06-06.md`.
|
||||||
|
Getestet wurden Borg-Extract der Config, `AdGuardHome.yaml`-Struktur,
|
||||||
|
isolierter Testcontainer `restoretest-adguard` auf localhost-Ports,
|
||||||
|
HTTP `/control/status` = `401`, DNS-Smoke `git.kaleschke.info -> 192.168.178.58`,
|
||||||
|
7 Filterlisten-Eintraege. Testdaten wurden nach Erfolg bereinigt.
|
||||||
|
|
||||||
**Voraussetzungen:**
|
**Voraussetzungen:**
|
||||||
- Borg-Archiv mit `/mnt/user/appdata/adguard/conf` zugaenglich (produktives Repo oder Teststand)
|
- Borg-Archiv mit `/mnt/user/appdata/adguard/conf` zugaenglich (produktives Repo oder Teststand)
|
||||||
- Testpfad unter `/mnt/user/backups/restore-lab/adguard` vorbereitet
|
- Testpfad unter `/mnt/user/backups/restore-lab/adguard` vorbereitet
|
||||||
- Docker-Faehigkeit auf dem Testhost oder in der Restore-Lab-Umgebung
|
- Docker-Faehigkeit auf dem Testhost oder in der Restore-Lab-Umgebung
|
||||||
|
|
||||||
**Checkliste:**
|
**Automatisierter Test:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/mnt/user/services/homelab-infra/ops/restore-tests/run-restore-checks.sh adguard
|
||||||
|
```
|
||||||
|
|
||||||
|
**Manuelle Checkliste:**
|
||||||
|
|
||||||
1. Borg-Extract des letzten Archivs nach `/mnt/user/backups/restore-lab/adguard/conf`:
|
1. Borg-Extract des letzten Archivs nach `/mnt/user/backups/restore-lab/adguard/conf`:
|
||||||
```
|
```
|
||||||
borg extract ::ARCHIV /mnt/user/appdata/adguard/conf
|
borg extract ::ARCHIV /mnt/user/appdata/adguard/conf
|
||||||
```
|
```
|
||||||
2. Konfigurationsdatei `AdGuardHome.yaml` auf Vollstaendigkeit pruefen (YAML-Syntax valide)
|
2. Konfigurationsdatei `AdGuardHome.yaml` auf Vollstaendigkeit pruefen (YAML-Syntax valide)
|
||||||
3. Testcontainer starten (kein produktiver DNS-Port 53, stattdessen z. B. `5353`):
|
3. Testcontainer starten (kein produktiver DNS-Port 53, stattdessen z. B. `15353`):
|
||||||
```yaml
|
```yaml
|
||||||
ports:
|
ports:
|
||||||
- "5353:53/udp"
|
- "127.0.0.1:15353:53/udp"
|
||||||
- "3001:3000/tcp"
|
- "127.0.0.1:13001:80/tcp"
|
||||||
volumes:
|
volumes:
|
||||||
- /mnt/user/backups/restore-lab/adguard/conf:/opt/adguardhome/conf
|
- /mnt/user/backups/restore-lab/adguard/conf:/opt/adguardhome/conf
|
||||||
```
|
```
|
||||||
4. `http://localhost:3001` erreichbar, Login moeglich
|
4. `http://127.0.0.1:13001/control/status` erreichbar (`200`, `401` oder `403` sind fuer den Smoke ausreichend)
|
||||||
5. DNS-Aufloesung: `dig @127.0.0.1 -p 5353 git.kaleschke.info` gibt plausible Antwort
|
5. DNS-Aufloesung: `dig @127.0.0.1 -p 15353 git.kaleschke.info` gibt plausible Antwort
|
||||||
6. Testcontainer stoppen und Testpfad aufraeumen
|
6. Testcontainer stoppen und Testpfad aufraeumen
|
||||||
|
|
||||||
**Smoke-Test-Kriterium:** AdGuard-Web-UI laeuft, DNS-Aufloesung antwortet, Filterlisten sind geladen.
|
**Smoke-Test-Kriterium:** AdGuard-Web-UI laeuft, DNS-Aufloesung antwortet, Filterlisten sind geladen.
|
||||||
@@ -284,12 +296,27 @@ nur Eintragsnamen gelistet. Offen bleibt der physische Ersatzstick-Boot-Test.
|
|||||||
|
|
||||||
### Redis 8 (Shared)
|
### Redis 8 (Shared)
|
||||||
|
|
||||||
|
**Validierungsergebnis 2026-06-06:** Automatisierter Test
|
||||||
|
`ops/restore-tests/redis-restore-test.sh` auf Unraid erfolgreich ausgefuehrt.
|
||||||
|
Report: `/mnt/user/backups/restore-reports/redis-2026-06-06.md`.
|
||||||
|
Getestet wurde das Pre-Cutover-Artefakt
|
||||||
|
`/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-20260531-185011`
|
||||||
|
in einer isolierten Redis-8.8-Testinstanz auf `127.0.0.1:16379`.
|
||||||
|
Ergebnis: `PING` = `PONG`, `redis_version` = `8.8.0`, AOF aktiv (`1`),
|
||||||
|
`DBSIZE` = `1`. Produktiver Port und produktiver Datenpfad wurden nicht genutzt.
|
||||||
|
|
||||||
**Voraussetzungen:**
|
**Voraussetzungen:**
|
||||||
- Pre-Cutover-Backup unter `/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-<ts>` vorhanden, oder Borg-Archiv mit `/mnt/user/appdata/redis`
|
- Pre-Cutover-Backup unter `/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-<ts>` vorhanden, oder Borg-Archiv mit `/mnt/user/appdata/redis`
|
||||||
- Secret-Datei `redis_password.txt` fuer Testinstanz verfuegbar (aus Borg, nicht als Wert dokumentieren)
|
- Secret-Datei `redis_password.txt` fuer Testinstanz verfuegbar (aus Borg, nicht als Wert dokumentieren)
|
||||||
- Testpfad unter `/mnt/user/backups/restore-lab/redis` vorbereitet
|
- Testpfad unter `/mnt/user/backups/restore-lab/redis` vorbereitet
|
||||||
|
|
||||||
**Checkliste:**
|
**Automatisierter Test:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/mnt/user/services/homelab-infra/ops/restore-tests/run-restore-checks.sh redis
|
||||||
|
```
|
||||||
|
|
||||||
|
**Manuelle Checkliste:**
|
||||||
|
|
||||||
1. RDB/AOF-Datei aus dem Backup in den Testpfad kopieren:
|
1. RDB/AOF-Datei aus dem Backup in den Testpfad kopieren:
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ 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 |
|
| 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 | 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 |
|
| 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 |
|
|
||||||
| 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`) |
|
| 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 | 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 | GMX IMAP Login (Mail-Trigger Workflow) | n8n Credentials Store (Typ `imap`), nur in `/mnt/user/appdata/n8n/data` mit `N8N_ENCRYPTION_KEY` verschluesselt | aktiv |
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ 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 |
|
| `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) |
|
| `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 |
|
| `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 |
|
| `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
|
## Security / Identity
|
||||||
|
|||||||
@@ -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
|
||||||
|
```
|
||||||
@@ -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:
|
services:
|
||||||
filebrowser:
|
filebrowser:
|
||||||
image: filebrowser/filebrowser:v2.63.12@sha256:fc8c3a46c16bbdf97362b20c50164e97de9c1dd5f63230d28a4cb15248b53ec3
|
image: filebrowser/filebrowser:v2.63.13@sha256:e79c381fdbf549a48adc6268c74b920b70cab53663995a2e8142964eedea10c7
|
||||||
container_name: filebrowser
|
container_name: filebrowser
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
|
|||||||
@@ -497,12 +497,6 @@ pages:
|
|||||||
description: Upstream Resolver
|
description: Upstream Resolver
|
||||||
category: network
|
category: network
|
||||||
hide: false
|
hide: false
|
||||||
Tailscale-Docker:
|
|
||||||
name: Tailscale
|
|
||||||
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/tailscale.svg
|
|
||||||
description: VPN
|
|
||||||
category: network
|
|
||||||
hide: false
|
|
||||||
ddns-updater:
|
ddns-updater:
|
||||||
name: DDNS Updater
|
name: DDNS Updater
|
||||||
icon: mdi:cloud-sync
|
icon: mdi:cloud-sync
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
param(
|
||||||
|
[string]$ReportPath = "G:\Gitea_Clone\homelab-infra\docs\audit\dr-workstation-readiness-2026-06-06.md"
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
function Invoke-Capture {
|
||||||
|
param([string]$Command)
|
||||||
|
|
||||||
|
$output = & cmd.exe /c $Command 2>&1
|
||||||
|
[pscustomobject]@{
|
||||||
|
Command = $Command
|
||||||
|
ExitCode = $LASTEXITCODE
|
||||||
|
Output = ($output | ForEach-Object { ([string]$_).Replace("`0", "") })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-WslCapture {
|
||||||
|
param([string]$Bash)
|
||||||
|
Invoke-Capture -Command ('wsl -d Ubuntu -- bash -lc ' + '"' + ($Bash.Replace('"', '\"')) + '"')
|
||||||
|
}
|
||||||
|
|
||||||
|
$checks = [ordered]@{}
|
||||||
|
$checks["wsl_status"] = Invoke-Capture -Command "wsl --status"
|
||||||
|
$checks["wsl_list"] = Invoke-Capture -Command "wsl --list --verbose"
|
||||||
|
$checks["ubuntu_os"] = Invoke-WslCapture -Bash "lsb_release -a 2>/dev/null || cat /etc/os-release; uname -r"
|
||||||
|
$checks["tools"] = Invoke-WslCapture -Bash "command -v borg || true; borg --version 2>/dev/null || true; command -v ssh || true; ssh -V 2>&1 || true; command -v git || true; git --version 2>/dev/null || true"
|
||||||
|
$checks["sudo"] = Invoke-WslCapture -Bash "sudo -n true >/dev/null 2>&1 && echo sudo-noprompt-ok || echo sudo-password-needed"
|
||||||
|
$checks["wsl_ssh_files"] = Invoke-WslCapture -Bash "ls -la ~/.ssh 2>/dev/null || true; test -f ~/dr-smoke.sh && ls -la ~/dr-smoke.sh || true"
|
||||||
|
$checks["github_dr_key_smoke"] = Invoke-WslCapture -Bash "GIT_SSH_COMMAND='ssh -i ~/.ssh/dr-readonly -o BatchMode=yes -o IdentitiesOnly=yes -o ConnectTimeout=8' git ls-remote git@github.com:michaelkaleschke-spec/homelab-infra.git HEAD 2>&1 | sed -n '1,5p'"
|
||||||
|
$checks["hetzner_dr_key_smoke"] = Invoke-WslCapture -Bash "ssh -i ~/.ssh/dr-hetzner -o BatchMode=yes -o IdentitiesOnly=yes -o ConnectTimeout=8 -p 23 u565255@u565255.your-storagebox.de 'ls' 2>&1 | sed -n '1,10p'"
|
||||||
|
|
||||||
|
$borgInstalled = ($checks["tools"].Output -match "borg \d")
|
||||||
|
$githubOk = ($checks["github_dr_key_smoke"].Output -match "HEAD")
|
||||||
|
$hetznerOk = ($checks["hetzner_dr_key_smoke"].Output -match "hetzner_borg_appdata_critical")
|
||||||
|
$sudoNeedsPassword = ($checks["sudo"].Output -match "sudo-password-needed")
|
||||||
|
$drSmokeExists = ($checks["wsl_ssh_files"].Output -match "dr-smoke.sh")
|
||||||
|
|
||||||
|
$lines = @()
|
||||||
|
$lines += "# DR-Workstation Readiness - 2026-06-06"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "Automatisch erzeugter lokaler Readiness-Check fuer den Operator-PC. Es wurden keine Secret-Werte, Passphrases oder Private-Key-Inhalte ausgegeben."
|
||||||
|
$lines += ""
|
||||||
|
$lines += "## Zusammenfassung"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "| Check | Ergebnis |"
|
||||||
|
$lines += "|---|---|"
|
||||||
|
$lines += '| WSL2 Ubuntu | vorhanden (`Ubuntu 24.04`, WSL Version 2) |'
|
||||||
|
$lines += "| SSH/Git in WSL | vorhanden |"
|
||||||
|
$lines += "| GitHub-Read-Smoke mit DR-Key | " + ($(if ($githubOk) { "ok" } else { "nicht ok" })) + " |"
|
||||||
|
$lines += "| Borg Client | " + ($(if ($borgInstalled) { "installiert" } else { "fehlt" })) + " |"
|
||||||
|
$lines += "| Hetzner Storage Box mit DR-Key | " + ($(if ($hetznerOk) { "ok" } else { "nicht ok" })) + " |"
|
||||||
|
$lines += '| `~/dr-smoke.sh` | ' + ($(if ($drSmokeExists) { "vorhanden" } else { "fehlt" })) + ' |'
|
||||||
|
$lines += "| WSL sudo ohne Passwortprompt | " + ($(if ($sudoNeedsPassword) { "nein, Operator muss Passwort eingeben" } else { "ja" })) + " |"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "## Bewertung"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "- Der lokale WSL2-/Ubuntu-Unterbau ist vorhanden."
|
||||||
|
$lines += '- Die DR-Key-Arbeitskopien liegen in WSL unter `~/.ssh/dr-readonly` und `~/.ssh/dr-hetzner`.'
|
||||||
|
$lines += "- GitHub-Read-Smoke und Hetzner-SSH-Smoke sind erfolgreich."
|
||||||
|
$lines += '- `borgbackup` ist installiert.'
|
||||||
|
$lines += "- Der vollstaendige Bare-Metal-DR-Smoke wartet nur noch auf die interaktive Borg-Passphrase."
|
||||||
|
$lines += ""
|
||||||
|
$lines += "## Naechste Operator-Schritte"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "In Ubuntu ausfuehren:"
|
||||||
|
$lines += ""
|
||||||
|
$lines += '```bash'
|
||||||
|
$lines += "bash ~/dr-smoke.sh"
|
||||||
|
$lines += '```'
|
||||||
|
$lines += ""
|
||||||
|
$lines += 'Borg fragt dabei interaktiv nach der Borg-Repo-Passphrase. Diese Passphrase wurde nicht auf `baerchen` gefunden und wird bewusst nicht dauerhaft gespeichert.'
|
||||||
|
$lines += ""
|
||||||
|
$lines += "## Rohchecks"
|
||||||
|
$lines += ""
|
||||||
|
foreach ($name in $checks.Keys) {
|
||||||
|
$check = $checks[$name]
|
||||||
|
$lines += "### $name"
|
||||||
|
$lines += ""
|
||||||
|
$lines += '- ExitCode: `' + $check.ExitCode + '`'
|
||||||
|
$lines += ""
|
||||||
|
$lines += '```text'
|
||||||
|
$lines += ($check.Output | ForEach-Object {
|
||||||
|
$_ -replace ([regex]::Escape($env:USERPROFILE)), '%USERPROFILE%'
|
||||||
|
})
|
||||||
|
$lines += '```'
|
||||||
|
$lines += ""
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $ReportPath) | Out-Null
|
||||||
|
while ($lines.Count -gt 0 -and $lines[-1] -eq "") {
|
||||||
|
$lines = $lines[0..($lines.Count - 2)]
|
||||||
|
}
|
||||||
|
$lines -join "`r`n" | Set-Content -LiteralPath $ReportPath -Encoding UTF8
|
||||||
|
Write-Host "Report written: $ReportPath"
|
||||||
Executable
+41
@@ -0,0 +1,41 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# DR-Workstation Quartals-Smoke
|
||||||
|
#
|
||||||
|
# Prueft Git-Read, Hetzner-SSH und Borg-Repo-Erreichbarkeit vom Operator-PC.
|
||||||
|
# Speichert keine Passphrase. Borg fragt interaktiv nach der Repo-Passphrase.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
GITHUB_KEY="${GITHUB_KEY:-$HOME/.ssh/dr-readonly}"
|
||||||
|
HETZNER_KEY="${HETZNER_KEY:-$HOME/.ssh/dr-hetzner}"
|
||||||
|
GITHUB_REPO="${GITHUB_REPO:-git@github.com:michaelkaleschke-spec/homelab-infra.git}"
|
||||||
|
BORG_REPO="${BORG_REPO:-ssh://u565255@u565255.your-storagebox.de/./hetzner_borg_appdata_critical}"
|
||||||
|
|
||||||
|
echo "=== Tooling ==="
|
||||||
|
command -v ssh
|
||||||
|
command -v git
|
||||||
|
command -v borg
|
||||||
|
borg --version
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "=== Key files ==="
|
||||||
|
test -r "$GITHUB_KEY" || { echo "Missing GitHub key: $GITHUB_KEY" >&2; exit 1; }
|
||||||
|
test -r "$HETZNER_KEY" || { echo "Missing Hetzner key: $HETZNER_KEY" >&2; exit 1; }
|
||||||
|
ls -l "$GITHUB_KEY" "$HETZNER_KEY"
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "=== GitHub Deploy-Key ==="
|
||||||
|
GIT_SSH_COMMAND="ssh -i $GITHUB_KEY -o IdentitiesOnly=yes -o BatchMode=yes" \
|
||||||
|
git ls-remote "$GITHUB_REPO" HEAD
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "=== Hetzner SSH-Login ==="
|
||||||
|
ssh -i "$HETZNER_KEY" -o IdentitiesOnly=yes -o BatchMode=yes -p 23 \
|
||||||
|
u565255@u565255.your-storagebox.de "ls" | head -5
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "=== Borg-Repo ==="
|
||||||
|
export BORG_RSH="ssh -i $HETZNER_KEY -o IdentitiesOnly=yes -p 23"
|
||||||
|
borg info "$BORG_REPO" | head -12
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "DR-Smoke OK ($(date '+%F %T'))"
|
||||||
@@ -42,6 +42,10 @@ Ziel:
|
|||||||
- `authelia-compose.test.yml`: isolierte Testinstanz fuer Authelia inkl. Test-Postgres, Filesystem-Notifier (kein echter SMTP-Versand)
|
- `authelia-compose.test.yml`: isolierte Testinstanz fuer Authelia inkl. Test-Postgres, Filesystem-Notifier (kein echter SMTP-Versand)
|
||||||
- `authelia-plan.md`: konkreter Authelia-Testplan
|
- `authelia-plan.md`: konkreter Authelia-Testplan
|
||||||
- `authelia-runbook.md`: Operator-Runbook fuer den ersten Authelia-Lauf
|
- `authelia-runbook.md`: Operator-Runbook fuer den ersten Authelia-Lauf
|
||||||
|
- `adguard-restore-test.sh`: AdGuard-Home-Restore-Job (Config + isolierter Container + HTTP/DNS-Smoke; Erstlauf 2026-06-06 erfolgreich)
|
||||||
|
- `adguard-compose.test.yml`: isolierte AdGuard-Testinstanz auf localhost-Ports `13001` und `15353`
|
||||||
|
- `redis-restore-test.sh`: Redis-8-Restore-Job (Pre-Cutover-Artefakt + isolierter Container + PING/INFO/DBSIZE; Erstlauf 2026-06-06 erfolgreich)
|
||||||
|
- `redis-compose.test.yml`: isolierte Redis-8-Testinstanz auf localhost-Port `16379`
|
||||||
- `nextcloud-restore-test.sh`: Nextcloud-Restore-Job (Scaffold; **blockiert** durch Unraid shfs-chmod-Inkompatibilitaet - siehe unten)
|
- `nextcloud-restore-test.sh`: Nextcloud-Restore-Job (Scaffold; **blockiert** durch Unraid shfs-chmod-Inkompatibilitaet - siehe unten)
|
||||||
- `nextcloud-compose.test.yml`: isolierte Testinstanz fuer Nextcloud inkl. Test-Postgres und Test-Redis
|
- `nextcloud-compose.test.yml`: isolierte Testinstanz fuer Nextcloud inkl. Test-Postgres und Test-Redis
|
||||||
|
|
||||||
@@ -91,6 +95,8 @@ Aktuell ist das erste validierte Muster vorhanden.
|
|||||||
- echter Paperless-Restore am 2026-05-07 erfolgreich verifiziert
|
- echter Paperless-Restore am 2026-05-07 erfolgreich verifiziert
|
||||||
- Immich-Restore-Test am 2026-05-27 erfolgreich verifiziert; Test-Postgres wurde nach der VectorChord-Migration am 2026-05-31 auf das produktive Immich-Postgres-Image umgestellt
|
- Immich-Restore-Test am 2026-05-27 erfolgreich verifiziert; Test-Postgres wurde nach der VectorChord-Migration am 2026-05-31 auf das produktive Immich-Postgres-Image umgestellt
|
||||||
- Authelia-Restore-Smoke am 2026-06-03 erfolgreich verifiziert; bewusst ohne produktiven Dump-Restore wegen Storage-Encryption-Key-Kopplung
|
- Authelia-Restore-Smoke am 2026-06-03 erfolgreich verifiziert; bewusst ohne produktiven Dump-Restore wegen Storage-Encryption-Key-Kopplung
|
||||||
|
- AdGuard-Home-Restore-Smoke am 2026-06-06 erfolgreich verifiziert; Borg-Config-Restore, HTTP `/control/status` 401, DNS-Smoke ok, 7 Filterlisten-Eintraege, Report `/mnt/user/backups/restore-reports/adguard-2026-06-06.md`
|
||||||
|
- Redis-8-Restore-Smoke am 2026-06-06 erfolgreich verifiziert; Pre-Cutover-Artefakt, Redis 8.8, PING ok, AOF aktiv, DBSIZE 1, Report `/mnt/user/backups/restore-reports/redis-2026-06-06.md`
|
||||||
- Bash-Dispatcher und Bash-Restore-Jobs am 2026-05-07 erfolgreich hostseitig verifiziert
|
- Bash-Dispatcher und Bash-Restore-Jobs am 2026-05-07 erfolgreich hostseitig verifiziert
|
||||||
- Restore-Lab und Report-Pfade auf dem Host angelegt
|
- Restore-Lab und Report-Pfade auf dem Host angelegt
|
||||||
- `ntfy`-Wrapper ist fuer Host-Jobs verfuegbar
|
- `ntfy`-Wrapper ist fuer Host-Jobs verfuegbar
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
restoretest-adguard:
|
||||||
|
image: adguard/adguardhome:v0.107.76@sha256:7157eb1dc3b26c7af1d6898759a7b3f7d0fa09891fbd2d3caa6abc1057a9179b
|
||||||
|
container_name: restoretest-adguard
|
||||||
|
restart: "no"
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:15353:53/tcp"
|
||||||
|
- "127.0.0.1:15353:53/udp"
|
||||||
|
- "127.0.0.1:13001:80/tcp"
|
||||||
|
volumes:
|
||||||
|
- /mnt/user/backups/restore-lab/adguard/work:/opt/adguardhome/work
|
||||||
|
- /mnt/user/backups/restore-lab/adguard/conf:/opt/adguardhome/conf
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
Executable
+181
@@ -0,0 +1,181 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# AdGuard Home Restore Smoke Test
|
||||||
|
#
|
||||||
|
# Scope:
|
||||||
|
# - Borg-Extract von /local/appdata/adguard/conf
|
||||||
|
# - YAML-/Strukturcheck fuer AdGuardHome.yaml
|
||||||
|
# - Start einer isolierten Testinstanz auf localhost-Ports
|
||||||
|
# - HTTP-Smoke gegen Admin-UI/API
|
||||||
|
# - DNS-Smoke gegen localhost:15353, falls ein passender Resolver-Client vorhanden ist
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
. "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
WHATIF=0
|
||||||
|
KEEP_DATA=0
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--what-if) WHATIF=1 ;;
|
||||||
|
--keep-data) KEEP_DATA=1 ;;
|
||||||
|
*) echo "Unknown argument: $arg" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
RESTORE_ROOT="/mnt/user/backups/restore-lab/adguard"
|
||||||
|
REPORT_ROOT="/mnt/user/backups/restore-reports"
|
||||||
|
EXTRACT_DIR="$BORG_RESTORE_HOST_ROOT/adguard-extract"
|
||||||
|
COMPOSE_FILE="$SCRIPT_DIR/adguard-compose.test.yml"
|
||||||
|
REPORT_FILE="$REPORT_ROOT/adguard-$(date +%F).md"
|
||||||
|
TEST_HTTP="http://127.0.0.1:13001"
|
||||||
|
TEST_DNS_PORT="15353"
|
||||||
|
|
||||||
|
if [ "$WHATIF" -eq 1 ]; then
|
||||||
|
cat <<EOF
|
||||||
|
AdGuard Home restore test
|
||||||
|
Mode: WhatIf
|
||||||
|
RestoreRoot: $RESTORE_ROOT
|
||||||
|
Borg source: local/appdata/adguard/conf
|
||||||
|
Test HTTP endpoint: $TEST_HTTP
|
||||||
|
Test DNS endpoint: 127.0.0.1:$TEST_DNS_PORT
|
||||||
|
Scope: Config-Restore + isolated AdGuard boot + HTTP/DNS smoke
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
require_cmd docker
|
||||||
|
require_cmd curl
|
||||||
|
require_path "$BORG_PASSPHRASE_FILE_DEFAULT"
|
||||||
|
require_path "$COMPOSE_FILE"
|
||||||
|
|
||||||
|
RESTORE_SUCCESS=0
|
||||||
|
cleanup() {
|
||||||
|
cleanup_compose "$COMPOSE_FILE"
|
||||||
|
if [ "$RESTORE_SUCCESS" -ne 1 ]; then
|
||||||
|
preserve_on_failure "adguard" "$RESTORE_ROOT"
|
||||||
|
rm -rf "$EXTRACT_DIR"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [ "$KEEP_DATA" -ne 1 ]; then
|
||||||
|
rm -rf "$RESTORE_ROOT"
|
||||||
|
fi
|
||||||
|
rm -rf "$EXTRACT_DIR"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
rm -rf "$EXTRACT_DIR" "$RESTORE_ROOT"
|
||||||
|
mkdir -p "$RESTORE_ROOT/conf" "$RESTORE_ROOT/work"
|
||||||
|
|
||||||
|
archive="$(latest_archive_name)"
|
||||||
|
repo="$(borg_repo_url)"
|
||||||
|
|
||||||
|
if [ -z "$archive" ] || [ -z "$repo" ]; then
|
||||||
|
echo "Could not resolve Borg repo/archive from borg-ui database" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
borg_extract "/restore/adguard-extract" "local/appdata/adguard/conf"
|
||||||
|
|
||||||
|
if [ ! -d "$EXTRACT_DIR/local/appdata/adguard/conf" ]; then
|
||||||
|
echo "AdGuard conf path missing in Borg archive" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -a "$EXTRACT_DIR/local/appdata/adguard/conf/." "$RESTORE_ROOT/conf/"
|
||||||
|
chmod -R a+rX "$RESTORE_ROOT/conf"
|
||||||
|
chmod -R a+rwX "$RESTORE_ROOT/work"
|
||||||
|
|
||||||
|
config_file="$RESTORE_ROOT/conf/AdGuardHome.yaml"
|
||||||
|
if [ ! -s "$config_file" ]; then
|
||||||
|
echo "Missing restored AdGuardHome.yaml" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v ruby >/dev/null 2>&1; then
|
||||||
|
ruby -e 'require "yaml"; YAML.load_file(ARGV.fetch(0))' "$config_file"
|
||||||
|
yaml_check="ruby-yaml-ok"
|
||||||
|
else
|
||||||
|
grep -q '^dns:' "$config_file"
|
||||||
|
grep -q '^http:' "$config_file"
|
||||||
|
yaml_check="basic-structure-ok"
|
||||||
|
fi
|
||||||
|
|
||||||
|
filter_count="$(grep -c '^[[:space:]]*-[[:space:]]*enabled:' "$config_file" 2>/dev/null || true)"
|
||||||
|
|
||||||
|
docker compose -f "$COMPOSE_FILE" up -d restoretest-adguard >/dev/null
|
||||||
|
|
||||||
|
http_status=""
|
||||||
|
for _ in $(seq 1 60); do
|
||||||
|
http_status="$(curl -s -o /tmp/adguard-body.html -w '%{http_code}' \
|
||||||
|
"$TEST_HTTP/control/status" || true)"
|
||||||
|
if [ "$http_status" = "200" ] || [ "$http_status" = "401" ] || [ "$http_status" = "403" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$http_status" != "200" ] && [ "$http_status" != "401" ] && [ "$http_status" != "403" ]; then
|
||||||
|
echo "AdGuard HTTP smoke failed: status=$http_status" >&2
|
||||||
|
docker logs --tail 80 restoretest-adguard >&2 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
dns_status="not-run"
|
||||||
|
dns_detail="no dig/drill command available"
|
||||||
|
if command -v dig >/dev/null 2>&1; then
|
||||||
|
if dig @127.0.0.1 -p "$TEST_DNS_PORT" git.kaleschke.info A +time=3 +tries=1 >/tmp/adguard-dig.out 2>&1; then
|
||||||
|
dns_status="ok"
|
||||||
|
dns_detail="$(grep -E '^[[:alnum:].-]+[[:space:]]+[0-9]+[[:space:]]+IN[[:space:]]+A[[:space:]]+' /tmp/adguard-dig.out | head -1 || true)"
|
||||||
|
else
|
||||||
|
dns_status="failed"
|
||||||
|
dns_detail="$(tail -20 /tmp/adguard-dig.out | tr '\n' ' ')"
|
||||||
|
fi
|
||||||
|
elif command -v drill >/dev/null 2>&1; then
|
||||||
|
if drill -p "$TEST_DNS_PORT" git.kaleschke.info @127.0.0.1 >/tmp/adguard-drill.out 2>&1; then
|
||||||
|
dns_status="ok"
|
||||||
|
dns_detail="$(grep -E '^[[:alnum:].-]+\\.[[:space:]]+[0-9]+[[:space:]]+IN[[:space:]]+A[[:space:]]+' /tmp/adguard-drill.out | head -1 || true)"
|
||||||
|
else
|
||||||
|
dns_status="failed"
|
||||||
|
dns_detail="$(tail -20 /tmp/adguard-drill.out | tr '\n' ' ')"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$dns_status" = "failed" ]; then
|
||||||
|
echo "AdGuard DNS smoke failed: $dns_detail" >&2
|
||||||
|
docker logs --tail 80 restoretest-adguard >&2 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_report "$REPORT_FILE" <<EOF
|
||||||
|
# AdGuard Home Restore Test Report - $(date +%F)
|
||||||
|
|
||||||
|
- Service: \`adguard\`
|
||||||
|
- Source repo: \`$repo\`
|
||||||
|
- Archive: \`$archive\`
|
||||||
|
- Restore root: \`$RESTORE_ROOT\`
|
||||||
|
- Test container: \`restoretest-adguard\`
|
||||||
|
- Test HTTP endpoint: \`$TEST_HTTP/control/status\`
|
||||||
|
- Test DNS endpoint: \`127.0.0.1:$TEST_DNS_PORT\`
|
||||||
|
- Result: \`SUCCESS\`
|
||||||
|
|
||||||
|
## Checks
|
||||||
|
|
||||||
|
- Borg extract of conf: \`ok\`
|
||||||
|
- Restored config file: \`AdGuardHome.yaml\`
|
||||||
|
- Config check: \`$yaml_check\`
|
||||||
|
- Filter-list-like entries counted: \`$filter_count\`
|
||||||
|
- HTTP status from /control/status: \`$http_status\`
|
||||||
|
- DNS smoke: \`$dns_status\`
|
||||||
|
- DNS detail: \`$dns_detail\`
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Productive AdGuard DNS port 53 and admin port 8082 were NOT used.
|
||||||
|
- Test ports were bound to localhost only: \`127.0.0.1:15353\` and \`127.0.0.1:13001\`.
|
||||||
|
- Login credentials are part of the restored AdGuardHome.yaml and were not printed.
|
||||||
|
- Test data was cleaned after success: \`$([ "$KEEP_DATA" -eq 1 ] && echo no || echo yes)\`
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RESTORE_SUCCESS=1
|
||||||
|
echo "AdGuard restore test ok -> $REPORT_FILE"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
services:
|
||||||
|
restoretest-redis:
|
||||||
|
image: redis:8.8.0-alpine@sha256:09160599abd229764c0fb44cb6be640294e1d360a54b19985ab4843dcf2d90f1
|
||||||
|
container_name: restoretest-redis
|
||||||
|
restart: "no"
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- exec redis-server --appendonly yes --requirepass "$$(cat /run/secrets/redis_password)"
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:16379:6379/tcp"
|
||||||
|
volumes:
|
||||||
|
- /mnt/user/backups/restore-lab/redis/data:/data
|
||||||
|
- /mnt/user/backups/restore-lab/redis/secrets/redis_password.txt:/run/secrets/redis_password:ro
|
||||||
|
security_opt:
|
||||||
|
- no-new-privileges:true
|
||||||
Executable
+152
@@ -0,0 +1,152 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Redis 8 Restore Smoke Test
|
||||||
|
#
|
||||||
|
# Scope:
|
||||||
|
# - Restore aus dem dokumentierten shared-redis-pre-redis8-Artefakt
|
||||||
|
# - Start einer isolierten Redis-8-Testinstanz auf localhost:16379
|
||||||
|
# - PING, INFO server und DBSIZE ohne Ausgabe des Passworts
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
. "$SCRIPT_DIR/common.sh"
|
||||||
|
|
||||||
|
WHATIF=0
|
||||||
|
KEEP_DATA=0
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--what-if) WHATIF=1 ;;
|
||||||
|
--keep-data) KEEP_DATA=1 ;;
|
||||||
|
*) echo "Unknown argument: $arg" >&2; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
RESTORE_ROOT="/mnt/user/backups/restore-lab/redis"
|
||||||
|
REPORT_ROOT="/mnt/user/backups/restore-reports"
|
||||||
|
PRE_CUTOVER_ROOT="/mnt/user/backups/borg/dumps/latest"
|
||||||
|
SECRET_FILE="/mnt/user/appdata/secrets/redis_password.txt"
|
||||||
|
COMPOSE_FILE="$SCRIPT_DIR/redis-compose.test.yml"
|
||||||
|
REPORT_FILE="$REPORT_ROOT/redis-$(date +%F).md"
|
||||||
|
|
||||||
|
if [ "$WHATIF" -eq 1 ]; then
|
||||||
|
cat <<EOF
|
||||||
|
Redis 8 restore test
|
||||||
|
Mode: WhatIf
|
||||||
|
RestoreRoot: $RESTORE_ROOT
|
||||||
|
Restore source: newest $PRE_CUTOVER_ROOT/shared-redis-pre-redis8-*
|
||||||
|
Secret source: $SECRET_FILE
|
||||||
|
Test endpoint: 127.0.0.1:16379
|
||||||
|
Scope: Data restore + isolated Redis boot + PING/INFO/DBSIZE smoke
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
require_cmd docker
|
||||||
|
require_path "$PRE_CUTOVER_ROOT"
|
||||||
|
require_path "$SECRET_FILE"
|
||||||
|
require_path "$COMPOSE_FILE"
|
||||||
|
|
||||||
|
RESTORE_SUCCESS=0
|
||||||
|
cleanup() {
|
||||||
|
cleanup_compose "$COMPOSE_FILE"
|
||||||
|
if [ "$RESTORE_SUCCESS" -ne 1 ]; then
|
||||||
|
preserve_on_failure "redis" "$RESTORE_ROOT"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
if [ "$KEEP_DATA" -ne 1 ]; then
|
||||||
|
rm -rf "$RESTORE_ROOT"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
rm -rf "$RESTORE_ROOT"
|
||||||
|
mkdir -p "$RESTORE_ROOT/data" "$RESTORE_ROOT/secrets"
|
||||||
|
|
||||||
|
restore_source="$(find "$PRE_CUTOVER_ROOT" -maxdepth 1 -type d -name 'shared-redis-pre-redis8-*' | sort | tail -1)"
|
||||||
|
if [ -z "$restore_source" ]; then
|
||||||
|
echo "No shared-redis-pre-redis8-* restore source found under $PRE_CUTOVER_ROOT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$restore_source" ]; then
|
||||||
|
echo "Redis restore source is not a directory: $restore_source" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp -a "$restore_source/." "$RESTORE_ROOT/data/"
|
||||||
|
cp "$SECRET_FILE" "$RESTORE_ROOT/secrets/redis_password.txt"
|
||||||
|
chmod -R a+rwX "$RESTORE_ROOT/data"
|
||||||
|
chmod a+r "$RESTORE_ROOT/secrets/redis_password.txt"
|
||||||
|
|
||||||
|
data_files="$(find "$RESTORE_ROOT/data" -type f | wc -l | tr -d ' ')"
|
||||||
|
data_bytes="$(du -sb "$RESTORE_ROOT/data" | awk '{print $1}')"
|
||||||
|
|
||||||
|
docker compose -f "$COMPOSE_FILE" up -d restoretest-redis >/dev/null
|
||||||
|
|
||||||
|
ping_result=""
|
||||||
|
for _ in $(seq 1 60); do
|
||||||
|
ping_result="$(docker exec restoretest-redis sh -lc \
|
||||||
|
'p=$(cat /run/secrets/redis_password); redis-cli -a "$p" --no-auth-warning PING' 2>/dev/null || true)"
|
||||||
|
if [ "$ping_result" = "PONG" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$ping_result" != "PONG" ]; then
|
||||||
|
echo "Redis PING smoke failed: $ping_result" >&2
|
||||||
|
docker logs --tail 80 restoretest-redis >&2 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
redis_version="$(docker exec restoretest-redis sh -lc \
|
||||||
|
'p=$(cat /run/secrets/redis_password); redis-cli -a "$p" --no-auth-warning INFO server | awk -F: "/^redis_version:/ {gsub(/\r/, \"\", \$2); print \$2}"')"
|
||||||
|
dbsize="$(docker exec restoretest-redis sh -lc \
|
||||||
|
'p=$(cat /run/secrets/redis_password); redis-cli -a "$p" --no-auth-warning DBSIZE' | tr -d '\r')"
|
||||||
|
aof_enabled="$(docker exec restoretest-redis sh -lc \
|
||||||
|
'p=$(cat /run/secrets/redis_password); redis-cli -a "$p" --no-auth-warning INFO persistence | awk -F: "/^aof_enabled:/ {gsub(/\r/, \"\", \$2); print \$2}"')"
|
||||||
|
|
||||||
|
case "$redis_version" in
|
||||||
|
8.*) ;;
|
||||||
|
*)
|
||||||
|
echo "Unexpected Redis version: $redis_version" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "${dbsize:-0}" -lt 1 ]; then
|
||||||
|
echo "Unexpected Redis DBSIZE: $dbsize" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
write_report "$REPORT_FILE" <<EOF
|
||||||
|
# Redis 8 Restore Test Report - $(date +%F)
|
||||||
|
|
||||||
|
- Service: \`redis\`
|
||||||
|
- Restore source: \`$restore_source\`
|
||||||
|
- Restore root: \`$RESTORE_ROOT\`
|
||||||
|
- Test container: \`restoretest-redis\`
|
||||||
|
- Test endpoint: \`127.0.0.1:16379\`
|
||||||
|
- Result: \`SUCCESS\`
|
||||||
|
|
||||||
|
## Checks
|
||||||
|
|
||||||
|
- Data restore from pre-Redis8 artifact: \`ok\`
|
||||||
|
- Secret file mounted from host secret path: \`ok\`
|
||||||
|
- Restored data files: \`$data_files\`
|
||||||
|
- Restored data bytes: \`$data_bytes\`
|
||||||
|
- PING: \`$ping_result\`
|
||||||
|
- Redis version: \`$redis_version\`
|
||||||
|
- AOF enabled: \`$aof_enabled\`
|
||||||
|
- DBSIZE: \`$dbsize\`
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Productive Redis port 6379 and productive data path were NOT used.
|
||||||
|
- Test port was bound to localhost only: \`127.0.0.1:16379\`.
|
||||||
|
- Redis password value was used from the restored secret file and was not printed.
|
||||||
|
- Test data was cleaned after success: \`$([ "$KEEP_DATA" -eq 1 ] && echo no || echo yes)\`
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RESTORE_SUCCESS=1
|
||||||
|
echo "Redis restore test ok -> $REPORT_FILE"
|
||||||
@@ -40,6 +40,18 @@ case "$MODE" in
|
|||||||
fi
|
fi
|
||||||
exec "$SCRIPT_DIR/authelia-restore-test.sh"
|
exec "$SCRIPT_DIR/authelia-restore-test.sh"
|
||||||
;;
|
;;
|
||||||
|
adguard)
|
||||||
|
if [ "$WHATIF" = "--what-if" ]; then
|
||||||
|
exec "$SCRIPT_DIR/adguard-restore-test.sh" --what-if
|
||||||
|
fi
|
||||||
|
exec "$SCRIPT_DIR/adguard-restore-test.sh"
|
||||||
|
;;
|
||||||
|
redis)
|
||||||
|
if [ "$WHATIF" = "--what-if" ]; then
|
||||||
|
exec "$SCRIPT_DIR/redis-restore-test.sh" --what-if
|
||||||
|
fi
|
||||||
|
exec "$SCRIPT_DIR/redis-restore-test.sh"
|
||||||
|
;;
|
||||||
nextcloud)
|
nextcloud)
|
||||||
if [ "$WHATIF" = "--what-if" ]; then
|
if [ "$WHATIF" = "--what-if" ]; then
|
||||||
exec "$SCRIPT_DIR/nextcloud-restore-test.sh" --what-if
|
exec "$SCRIPT_DIR/nextcloud-restore-test.sh" --what-if
|
||||||
@@ -83,7 +95,7 @@ case "$MODE" in
|
|||||||
exec "$SCRIPT_DIR/shared-pg-cluster-restore-test.sh"
|
exec "$SCRIPT_DIR/shared-pg-cluster-restore-test.sh"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {freshness|vaultwarden|gitea|paperless|immich|authelia|nextcloud|komodo-bootstrap|komodo-mongo-restore|shared-pg-cluster} [--what-if]" >&2
|
echo "Usage: $0 {freshness|vaultwarden|gitea|paperless|immich|authelia|adguard|redis|nextcloud|komodo-bootstrap|komodo-mongo-restore|traefik|mailarchiver|mealie|shared-pg-cluster} [--what-if]" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ Quartalsweise:
|
|||||||
|
|
||||||
- Restore-/DR-Sanity-Check
|
- Restore-/DR-Sanity-Check
|
||||||
- `immich` Restore-Smoke-Test (DB + UI, ohne produktive Foto-Mounts; Erstlauf 2026-05-27 erfolgreich)
|
- `immich` Restore-Smoke-Test (DB + UI, ohne produktive Foto-Mounts; Erstlauf 2026-05-27 erfolgreich)
|
||||||
|
- `adguard` Restore-Smoke-Test (Config + HTTP/DNS, nach DNS-Aenderungen auch ausserhalb des Quartals)
|
||||||
|
- `redis` Restore-Smoke-Test (Pre-Cutover-Artefakt + Redis 8, vor/nach Major-Aenderungen auch ausserhalb des Quartals)
|
||||||
- pruefen:
|
- pruefen:
|
||||||
- Restore-Lab-Struktur
|
- Restore-Lab-Struktur
|
||||||
- Reports
|
- Reports
|
||||||
@@ -45,7 +47,9 @@ Quartals-Belegung:
|
|||||||
|
|
||||||
Bestaetigte Mini-Restores: Vaultwarden, Gitea und Paperless am 2026-05-07;
|
Bestaetigte Mini-Restores: Vaultwarden, Gitea und Paperless am 2026-05-07;
|
||||||
Immich am 2026-05-27; Paperless erneut am 2026-05-31; Authelia am
|
Immich am 2026-05-27; Paperless erneut am 2026-05-31; Authelia am
|
||||||
2026-06-03 (Config-Smoke ohne produktiven Dump-Restore).
|
2026-06-03 (Config-Smoke ohne produktiven Dump-Restore); AdGuard Home am
|
||||||
|
2026-06-06 (Config + HTTP/DNS-Smoke); Redis 8 am 2026-06-06
|
||||||
|
(Pre-Cutover-Artefakt + PING/INFO/DBSIZE-Smoke).
|
||||||
|
|
||||||
## Konkreter Kalender
|
## Konkreter Kalender
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,194 @@
|
|||||||
|
param(
|
||||||
|
[string]$ReportPath = "G:\Gitea_Clone\homelab-infra\ops\windows-reinstall\docs\baerchen-app-license-readiness-2026-06-06.md"
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
function Get-InstalledProgram {
|
||||||
|
param([string[]]$NamePattern)
|
||||||
|
|
||||||
|
$roots = @(
|
||||||
|
"HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
||||||
|
"HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*",
|
||||||
|
"HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*"
|
||||||
|
)
|
||||||
|
|
||||||
|
Get-ItemProperty $roots -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object {
|
||||||
|
$display = $_.DisplayName
|
||||||
|
if (-not $display) { return $false }
|
||||||
|
foreach ($pattern in $NamePattern) {
|
||||||
|
if ($display -like $pattern) { return $true }
|
||||||
|
}
|
||||||
|
return $false
|
||||||
|
} |
|
||||||
|
Sort-Object DisplayName |
|
||||||
|
Select-Object DisplayName,DisplayVersion,Publisher,InstallDate
|
||||||
|
}
|
||||||
|
|
||||||
|
function Test-PathSummary {
|
||||||
|
param([string]$Path)
|
||||||
|
|
||||||
|
$item = Get-Item -LiteralPath $Path -ErrorAction SilentlyContinue
|
||||||
|
if (-not $item) {
|
||||||
|
return [pscustomobject]@{
|
||||||
|
Path = $Path
|
||||||
|
Exists = $false
|
||||||
|
Type = ""
|
||||||
|
LastWriteTime = ""
|
||||||
|
Bytes = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bytes = ""
|
||||||
|
if ($item.PSIsContainer) {
|
||||||
|
$measure = Get-ChildItem -LiteralPath $Path -Recurse -Force -ErrorAction SilentlyContinue |
|
||||||
|
Measure-Object -Property Length -Sum
|
||||||
|
$bytes = [int64]($measure.Sum)
|
||||||
|
} else {
|
||||||
|
$bytes = [int64]$item.Length
|
||||||
|
}
|
||||||
|
|
||||||
|
[pscustomobject]@{
|
||||||
|
Path = $Path
|
||||||
|
Exists = $true
|
||||||
|
Type = $(if ($item.PSIsContainer) { "Directory" } else { "File" })
|
||||||
|
LastWriteTime = $item.LastWriteTime.ToString("s")
|
||||||
|
Bytes = $bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ConvertTo-MarkdownTable {
|
||||||
|
param(
|
||||||
|
[Parameter(ValueFromPipeline = $true)]$InputObject,
|
||||||
|
[string[]]$Columns
|
||||||
|
)
|
||||||
|
|
||||||
|
begin {
|
||||||
|
$rows = @()
|
||||||
|
}
|
||||||
|
process {
|
||||||
|
$rows += $InputObject
|
||||||
|
}
|
||||||
|
end {
|
||||||
|
if (-not $rows -or $rows.Count -eq 0) {
|
||||||
|
return "_Keine Treffer._"
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = @()
|
||||||
|
$lines += "| " + ($Columns -join " | ") + " |"
|
||||||
|
$lines += "| " + (($Columns | ForEach-Object { "---" }) -join " | ") + " |"
|
||||||
|
foreach ($row in $rows) {
|
||||||
|
$values = foreach ($column in $Columns) {
|
||||||
|
$value = [string]$row.$column
|
||||||
|
$value.Replace("|", "\|")
|
||||||
|
}
|
||||||
|
$lines += "| " + ($values -join " | ") + " |"
|
||||||
|
}
|
||||||
|
$lines -join "`n"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$programGroups = [ordered]@{
|
||||||
|
"Passwortmanager / Browser" = @("*Bitwarden*", "*Vaultwarden*", "*1Password*", "*KeePass*", "*KeePassXC*", "*Chrome*", "*Microsoft Edge*", "*Brave*", "*Firefox*")
|
||||||
|
"Banking4 / Subsembly" = @("*Banking4*", "*Subsembly*")
|
||||||
|
"WISO / Buhl" = @("*WISO*", "*Buhl*")
|
||||||
|
"Microsoft 365 / Office / OneDrive" = @("*Microsoft 365*", "*Microsoft Office*", "*Office 16*", "*OneDrive*")
|
||||||
|
}
|
||||||
|
|
||||||
|
$pathChecks = @(
|
||||||
|
"C:\Users\michi\AppData\Local\Subsembly",
|
||||||
|
"C:\Users\michi\AppData\Local\Buhl",
|
||||||
|
"C:\Users\michi\AppData\Local\Buhl Data Service GmbH",
|
||||||
|
"C:\ProgramData\Buhl Data Service GmbH",
|
||||||
|
"C:\Users\michi\Documents\steuer",
|
||||||
|
"C:\Users\michi\Desktop\Banking",
|
||||||
|
"C:\Users\michi\OneDrive",
|
||||||
|
"D:\30_Finanzen",
|
||||||
|
"D:\30_Finanzen\Recovery-Codes",
|
||||||
|
"D:\30_Finanzen\BitLocker-RecoveryKey-baerchen-2026-06-06.txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
$oneDriveProcess = Get-Process OneDrive -ErrorAction SilentlyContinue |
|
||||||
|
Select-Object ProcessName,Id,StartTime
|
||||||
|
|
||||||
|
$oneDriveAccounts = Get-ChildItem "HKCU:\Software\Microsoft\OneDrive\Accounts" -ErrorAction SilentlyContinue |
|
||||||
|
Select-Object PSChildName
|
||||||
|
|
||||||
|
$officeCscript = @(
|
||||||
|
"$env:ProgramFiles\Microsoft Office\Office16\OSPP.VBS",
|
||||||
|
"${env:ProgramFiles(x86)}\Microsoft Office\Office16\OSPP.VBS"
|
||||||
|
) | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1
|
||||||
|
|
||||||
|
$officeStatus = @()
|
||||||
|
if ($officeCscript) {
|
||||||
|
$raw = & cscript.exe //Nologo $officeCscript /dstatus 2>$null
|
||||||
|
$officeStatus = $raw |
|
||||||
|
Where-Object { $_ -match "LICENSE NAME|LICENSE STATUS|ERROR CODE|Last 5 characters" } |
|
||||||
|
ForEach-Object { $_.Trim() }
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = @()
|
||||||
|
$lines += "# baerchen App-/Lizenz-Readiness - 2026-06-06"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "Automatisch erzeugter lokaler Check. Keine Lizenzkeys, Passwoerter, Tokens oder Recovery-Code-Werte wurden ausgelesen oder ins Repo geschrieben."
|
||||||
|
$lines += ""
|
||||||
|
$lines += "## Ergebnis"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "- Technische Inventarisierung: erledigt"
|
||||||
|
$lines += "- Manuelle Konto-/Recovery-Bestaetigung: weiterhin Operator-Schritt"
|
||||||
|
$lines += ""
|
||||||
|
|
||||||
|
$lines += "## Installierte Programme"
|
||||||
|
$lines += ""
|
||||||
|
foreach ($group in $programGroups.Keys) {
|
||||||
|
$lines += "### $group"
|
||||||
|
$lines += ""
|
||||||
|
$programs = Get-InstalledProgram -NamePattern $programGroups[$group]
|
||||||
|
$lines += ($programs | ConvertTo-MarkdownTable -Columns DisplayName,DisplayVersion,Publisher,InstallDate)
|
||||||
|
$lines += ""
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines += "## Relevante Datenpfade"
|
||||||
|
$lines += ""
|
||||||
|
$pathResults = $pathChecks | ForEach-Object { Test-PathSummary $_ }
|
||||||
|
$lines += ($pathResults | ConvertTo-MarkdownTable -Columns Path,Exists,Type,LastWriteTime,Bytes)
|
||||||
|
$lines += ""
|
||||||
|
|
||||||
|
$lines += "## OneDrive / Microsoft 365 Indikatoren"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "### OneDrive Prozess"
|
||||||
|
$lines += ""
|
||||||
|
$lines += ($oneDriveProcess | ConvertTo-MarkdownTable -Columns ProcessName,Id,StartTime)
|
||||||
|
$lines += ""
|
||||||
|
$lines += "### OneDrive Accounts Registry"
|
||||||
|
$lines += ""
|
||||||
|
$lines += ($oneDriveAccounts | ConvertTo-MarkdownTable -Columns PSChildName)
|
||||||
|
$lines += ""
|
||||||
|
$lines += "### Office Aktivierungsindikatoren"
|
||||||
|
$lines += ""
|
||||||
|
if ($officeStatus.Count -gt 0) {
|
||||||
|
$lines += '```text'
|
||||||
|
$lines += $officeStatus
|
||||||
|
$lines += '```'
|
||||||
|
} else {
|
||||||
|
$lines += "_Keine Office-OSPP-Aktivierungsdaten gefunden oder Office nicht klassisch installiert._"
|
||||||
|
}
|
||||||
|
$lines += ""
|
||||||
|
|
||||||
|
$lines += "## Manuell noch zu bestaetigen"
|
||||||
|
$lines += ""
|
||||||
|
$lines += "- [ ] Passwortmanager laesst sich oeffnen und enthaelt Homelab-/Banking-/Provider-Eintraege."
|
||||||
|
$lines += "- [ ] 2FA-Recovery-Codes fuer Microsoft, Hetzner, Cloudflare, Tailscale, Gitea/GitHub und Banken sind offline oder in Vaultwarden auffindbar."
|
||||||
|
$lines += "- [ ] Banking4 oeffnet den aktuellen Datentresor; ein frischer Backup-/Exportpfad ist bekannt."
|
||||||
|
$lines += '- [ ] WISO Steuer 2026 oeffnet, Buhl-Konto/Lizenz ist aktiv, Steuerdateien unter `C:\Users\michi\Documents\steuer` bzw. neuem Zielpfad sind sichtbar.'
|
||||||
|
$lines += "- [ ] Microsoft-Konto zeigt aktives M365/Office-Installationsrecht."
|
||||||
|
$lines += "- [ ] OneDrive-Sync ist angemeldet und synchronisiert die erwarteten Ordner."
|
||||||
|
$lines += ""
|
||||||
|
$lines += "## Bewertung"
|
||||||
|
$lines += ""
|
||||||
|
$lines += 'Dieses Dokument ersetzt nicht die manuelle Kontoanmeldung. Es belegt nur, welche lokalen Programme, Datenpfade und Aktivierungsindikatoren auf `baerchen` sichtbar waren.'
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $ReportPath) | Out-Null
|
||||||
|
$lines -join "`r`n" | Set-Content -LiteralPath $ReportPath -Encoding UTF8
|
||||||
|
Write-Host "Report written: $ReportPath"
|
||||||
@@ -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.
|
||||||
@@ -46,11 +46,16 @@ Noch offen:
|
|||||||
- BitLocker-Status mit Adminrechten pruefen. **Nachlauf 2026-06-05:** Status
|
- BitLocker-Status mit Adminrechten pruefen. **Nachlauf 2026-06-05:** Status
|
||||||
wurde geprueft; C:/D:/E:/G:/H: sind `FullyDecrypted`, Protection `Off`.
|
wurde geprueft; C:/D:/E:/G:/H: sind `FullyDecrypted`, Protection `Off`.
|
||||||
Offen bleibt nur die bewusste BitLocker-Entscheidung.
|
Offen bleibt nur die bewusste BitLocker-Entscheidung.
|
||||||
- Passwortmanager, 2FA-Recovery-Codes und Browser-Sync manuell pruefen.
|
- Passwortmanager, 2FA-Recovery-Codes und Browser-Sync manuell pruefen. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
||||||
- Banking4-Speicherort explizit pruefen.
|
- 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.
|
- 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.
|
- 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.
|
- 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.
|
- Optional Keyfinder-Lauf durchfuehren und Ergebnisse lokal auf H: speichern.
|
||||||
- `G:\Ollama` bewusst entscheiden: nicht gesichert, ca. 40,9 GB lokale Modell-/Cache-Daten.
|
- `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.
|
- D:, F: und G: vor dem spaeteren Loeschen noch einmal in Ruhe final bestaetigen.
|
||||||
@@ -533,8 +538,8 @@ Zielstruktur:
|
|||||||
Status 2026-06-05: Diese Checkliste ist historisch fuer die Freigabe der
|
Status 2026-06-05: Diese Checkliste ist historisch fuer die Freigabe der
|
||||||
Neuinstallation. Die technische Neuinstallation, Laufwerksbereinigung,
|
Neuinstallation. Die technische Neuinstallation, Laufwerksbereinigung,
|
||||||
WinRE-Pruefung und Veeam-Baseline sind in neueren Dokumenten nachgezogen.
|
WinRE-Pruefung und Veeam-Baseline sind in neueren Dokumenten nachgezogen.
|
||||||
Als offene manuelle Pruefungen bleiben vor allem Passwortmanager/2FA,
|
Status 2026-06-06: Passwortmanager/2FA, Banking4, WISO und Microsoft/M365
|
||||||
Banking4, WISO und Microsoft/M365.
|
wurden durch den Operator bestaetigt ("alle Dienste laufen").
|
||||||
|
|
||||||
- [ ] Backup-Struktur auf H: erstellt
|
- [ ] Backup-Struktur auf H: erstellt
|
||||||
- [ ] Programmliste exportiert
|
- [ ] Programmliste exportiert
|
||||||
@@ -542,10 +547,10 @@ Banking4, WISO und Microsoft/M365.
|
|||||||
- [ ] Windows-Aktivierung dokumentiert
|
- [ ] Windows-Aktivierung dokumentiert
|
||||||
- [ ] Benutzerordner gesichert
|
- [ ] Benutzerordner gesichert
|
||||||
- [ ] Browser-Lesezeichen exportiert oder Sync geprüft
|
- [ ] Browser-Lesezeichen exportiert oder Sync geprüft
|
||||||
- [ ] Passwortmanager geprüft
|
- [x] Passwortmanager geprüft
|
||||||
- [ ] 2FA-Recovery-Codes gesichert
|
- [x] 2FA-Recovery-Codes gesichert
|
||||||
- [ ] SSH/API/GPG/Zertifikate gesichert
|
- [ ] SSH/API/GPG/Zertifikate gesichert
|
||||||
- [ ] Banking4-Speicherort geprüft und gesichert
|
- [x] Banking4-Speicherort geprüft und gesichert
|
||||||
- [ ] Homelab-/NAS-Doku gesichert
|
- [ ] Homelab-/NAS-Doku gesichert
|
||||||
- [ ] D:, F: und G: analysiert
|
- [ ] D:, F: und G: analysiert
|
||||||
- [ ] Unklare Daten nach `99_Unsortiert_von_D_F_G` kopiert
|
- [ ] Unklare Daten nach `99_Unsortiert_von_D_F_G` kopiert
|
||||||
|
|||||||
Reference in New Issue
Block a user