Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb7dc8ab5a |
@@ -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`: natives Unraid-Plugin (`tailscale.plg`, Interface `tailscale1`), Subnet-Router fuers LAN; nicht repo-/Komodo-verwaltet. Der frueher repo-verwaltete userspace-Docker-Stack `host-services/tailscale/` wurde am 2026-06-06 entfernt.
|
- `tailscale`: `network_mode: host`
|
||||||
- `Plex-Media-Server`: historischer Host-Netz-Sonderfall, nicht als Repo-Stack enthalten
|
- `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 / Subnet-Router | **Natives Unraid-Plugin** (`tailscale.plg`, Interface `tailscale1`, State `/boot/config/plugins/tailscale/state`) — **nicht** repo-/Komodo-verwaltet | Subnet-Router fuer `192.168.178.0/24`; der redundante userspace-Docker-Stack `host-services/tailscale/` wurde am 2026-06-06 entfernt |
|
| `tailscale` | ✅ | `host` | VPN-Zugang | Git-Stack (`host-services/tailscale/`) | nutzt `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` als dokumentierte VPN-Ausnahme |
|
||||||
|
|
||||||
### 7.2 Sicherheit / Identity
|
### 7.2 Sicherheit / Identity
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ 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)
|
||||||
@@ -43,7 +44,6 @@ 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,14 +290,7 @@ 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,15 +115,6 @@ 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,4 +107,3 @@ 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,15 +1,8 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
## Historischer Live-Stand 2026-05-04
|
## 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-06 (Wochenend-Sprint, nach Status-Kategorien sortiert)
|
Stand: 2026-06-05 (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,9 +23,14 @@ 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` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -36,6 +41,7 @@ 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` |
|
||||||
@@ -52,12 +58,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` |
|
||||||
@@ -92,13 +98,7 @@ 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 am 2026-06-06 erfolgreich beim Operator angekommen.
|
- 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.
|
||||||
- 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.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+56
-90
@@ -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 | **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. |
|
| ACL-Policy extern dokumentiert | **Operator-Entscheidung offen** — siehe eigener Block unten; durch den aktiven Subnet-Router ist die ACL-Frage sicherheitsrelevanter als zuvor angenommen. |
|
||||||
|
|
||||||
### Tailnet-Geraete (Snapshot 2026-06-05)
|
### Tailnet-Geraete (Snapshot 2026-06-05)
|
||||||
|
|
||||||
@@ -65,37 +65,13 @@ 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 | **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. |
|
| `100.112.0.90` | kallilab-core | linux | gelistet, kein aktiver Verkehr — **moeglicher Alt-/Dubletten-Node**, separat pruefen |
|
||||||
|
|
||||||
> **Befund 2026-06-06 (read-only auf dem Host ermittelt):** Der Host hat **zwei**
|
> Hygiene-Hinweis (kein Secret): Es existieren zwei linux-Nodes mit aehnlichem
|
||||||
> `tailscaled`-Prozesse:
|
> Namen (`kallilabcore` und `kallilab-core`) sowie zwei `baerchen`-Nodes
|
||||||
>
|
> (`baerchen-1` aktiv, `baerchen` offline). Bei Gelegenheit in der
|
||||||
> 1. **Native Unraid-Plugin** = `kallilabcore` (100.80.98.33). Prozess
|
> Tailscale-Admin-Konsole pruefen, ob die inaktiven Eintraege stillgelegt werden
|
||||||
> `/usr/local/sbin/tailscaled -statedir /boot/config/plugins/tailscale/state
|
> koennen. Das ist Aufraeumarbeit, kein akutes Risiko.
|
||||||
> -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
|
||||||
|
|
||||||
@@ -115,22 +91,34 @@ tailscale ip -4
|
|||||||
tailscale ip -6
|
tailscale ip -6
|
||||||
```
|
```
|
||||||
|
|
||||||
### ACL-Policy — ANGEWENDET 2026-06-06 (restriktive Tag-basierte grants)
|
### ACL-Policy — Entwurf und Rollout-Plan (Stand 2026-06-05, NICHT angewendet)
|
||||||
|
|
||||||
**Status: live und verifiziert.** Die restriktive Policy wurde am 2026-06-06
|
Die Tailnet-ACL wird in der Tailscale-Admin-Konsole unter `Access controls`
|
||||||
gemeinsam mit dem Operator in der lockout-sicheren Reihenfolge ausgerollt und
|
verwaltet (kein Wert/Secret gehoert ins Repo). Aktueller Live-Stand ist
|
||||||
read-only verifiziert (siehe "Rollout-Protokoll" unten). Ausgangspunkt war die
|
Default-Allow (`src: ["*"] -> dst: ["*:*"]`), d. h. jedes Tailnet-Geraet darf
|
||||||
**unveraenderte Default-Policy** im **`grants`-Schema** (eine Allow-all-Regel,
|
alles inklusive der LAN-Subnet-Route.
|
||||||
keine Groups/Tags/`autoApprovers`); es gab also keinen eigenen Bestand zu
|
|
||||||
erhalten.
|
|
||||||
|
|
||||||
> **Schema-Hinweis:** Dieses Tailnet nutzt das `grants`-Modell
|
**Abgestimmte Richtung (Operator-Entscheidungen 2026-06-05):**
|
||||||
> (`{"src","dst","ip"}`), nicht das aeltere `acls`/`action:accept`-Modell.
|
|
||||||
> Normaler SSH-Zugriff (`ssh kallilabcore` ueber OpenSSH Port 22) wird ueber
|
|
||||||
> `grants` geregelt, nicht ueber den `ssh`-Block; letzterer betrifft nur die
|
|
||||||
> Tailscale-SSH-Funktion.
|
|
||||||
|
|
||||||
**Angewendete Policy (live, kein Secret):**
|
- Ziel ist eine restriktivere, Tag-basierte ACL.
|
||||||
|
- 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
|
||||||
{
|
{
|
||||||
@@ -142,64 +130,42 @@ erhalten.
|
|||||||
"autoApprovers": {
|
"autoApprovers": {
|
||||||
"routes": { "192.168.178.0/24": ["tag:server"] }
|
"routes": { "192.168.178.0/24": ["tag:server"] }
|
||||||
},
|
},
|
||||||
"grants": [
|
"acls": [
|
||||||
{"src": ["tag:operator"], "dst": ["*"], "ip": ["*"]},
|
{ "action": "accept", "src": ["tag:operator"], "dst": ["*:*"] },
|
||||||
{"src": ["tag:server"], "dst": ["tag:operator"], "ip": ["*"]},
|
{ "action": "accept", "src": ["tag:server"], "dst": ["tag:operator:*"] },
|
||||||
{"src": ["tag:family"], "dst": ["tag:server"], "ip": ["tcp:443"]}
|
{ "action": "accept", "src": ["tag:family"], "dst": ["100.80.98.33:443"] }
|
||||||
],
|
],
|
||||||
"ssh": [
|
"ssh": [
|
||||||
{"action": "check", "src": ["autogroup:member"], "dst": ["autogroup:self"],
|
{ "action": "accept", "src": ["tag:operator"], "dst": ["tag:server"],
|
||||||
"users": ["autogroup:nonroot", "root"]}
|
"users": ["root", "autogroup:nonroot"] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Geraete-Tags (live):** `kallilabcore` = `tag:server`; `baerchen-1` + `iphone-14`
|
> Die `tag:family`-`dst` `100.80.98.33:443` ist ein **Platzhalter** und wird
|
||||||
= `tag:operator`; `kallilab-core` (Docker) + alter `baerchen` bewusst untagged ->
|
> durch die real benoetigten Familien-Dienste ersetzt, sobald diese feststehen.
|
||||||
isoliert.
|
|
||||||
|
|
||||||
**Rollout-Protokoll 2026-06-06 (lockout-sicher, je Schritt read-only verifiziert):**
|
**Lockout-sichere Reihenfolge (wenn die Umsetzung freigegeben wird):**
|
||||||
|
|
||||||
1. Policy additiv erweitert (Tags/grants definiert, Allow-all noch drin) -> alle Peers unveraendert verbunden, Route approved.
|
1. `tagOwners` + `autoApprovers` + neue ACL-Regeln speichern, **Allow-all-Regel
|
||||||
2. `baerchen-1` getaggt `tag:operator` -> online, verifiziert.
|
zunaechst behalten**.
|
||||||
3. `iphone-14` getaggt `tag:operator` -> verifiziert.
|
2. Geraete taggen (`baerchen-1`, `iphone-14` -> operator; `kallilabcore` ->
|
||||||
4. `kallilab-core` faktisch geprueft (Docker-Sidecar, keine Abhaengigen) -> bewusst untagged gelassen.
|
server) und je Geraet die Verbindung verifizieren.
|
||||||
5. Host `kallilabcore` getaggt `tag:server` -> Route blieb via `autoApprovers` automatisch approved, SSH ok.
|
3. Subnet-Route bleibt approved (jetzt via `autoApprovers`/`tag:server`).
|
||||||
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.
|
4. **Erst zuletzt** die Allow-all-Regel entfernen -> restriktiv schalten.
|
||||||
|
5. Sofort Smoke-Tests fahren (siehe unten).
|
||||||
|
|
||||||
**Schema-/Erhaltungs-Hinweis fuer spaeter:** Die LAN-Subnet-Route
|
**Smoke-Tests nach Anwendung:**
|
||||||
`192.168.178.0/24` wird jetzt ueber `autoApprovers`/`tag:server` approved
|
|
||||||
(vorher manuell). Es gibt keinen eigenen Bestand zu erhalten; die Policy oben
|
|
||||||
ist die vollstaendige Wahrheit.
|
|
||||||
|
|
||||||
**Hintergrund / Designentscheidungen (2026-06-05/06):**
|
- `baerchen-1` erreicht Host: `ping 100.80.98.33`, `ssh kallilabcore hostname` (read-only).
|
||||||
|
- `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.
|
||||||
|
|
||||||
- Single-User-Realitaet: alle Nodes gehoeren demselben User `michaelkaleschke@`.
|
**Noch offene Eingaben vor Finalisierung:**
|
||||||
Eine Differenzierung Operator/Familie ist nur ueber **Tags** moeglich, deshalb
|
|
||||||
der Tag-Ansatz statt user-/gruppenbasiert.
|
|
||||||
- Erster Rollout bewusst klein: nur `tag:server` + `tag:operator`.
|
|
||||||
- **`tag:family` ist vorbereitet, aber schlafend:** Tag und eine konservative
|
|
||||||
Minimal-Regel (`dst: tag:server`, `ip: tcp:443`) sind definiert, aber **kein
|
|
||||||
Geraet traegt den Tag**, daher null Wirkung. Sobald ein echtes Familiengeraet
|
|
||||||
dazukommt, wird es einmal mit `tag:family` getaggt und die Regel greift sofort
|
|
||||||
— ohne Policy-Umbau. Vor dem ersten realen Familiengeraet die Regel auf die
|
|
||||||
dann benoetigten Dienste/Ports pruefen.
|
|
||||||
- Der `ssh`-Block bleibt der Default (Tailscale-SSH Check-Modus); normaler
|
|
||||||
OpenSSH-Zugriff laeuft ueber die `grants` (Port 22, fuer `tag:operator` ueber
|
|
||||||
`ip: ["*"]` abgedeckt).
|
|
||||||
|
|
||||||
**Offene Folgepunkte (kein Risiko, Hygiene/spaeter):**
|
1. Aktueller ACL-JSON aus der Admin-Konsole (read-only gesichtet, nur Struktur dokumentiert).
|
||||||
|
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` | Archivierter Entwurf: Home Assistant -> InfluxDB 3 -> Grafana; nicht aktiv seit Crash |
|
| `HOME_ASSISTANT_INFLUXDB_ECOWITT.md` | Home Assistant -> InfluxDB 3 -> Grafana |
|
||||||
| `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
|
||||||
|
|||||||
+17
-44
@@ -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; Restore-Smoke am 2026-06-06 erfolgreich |
|
| AdGuard Home | Share / Borg | `/mnt/user/appdata/adguard/conf` | keine | keine zusaetzlichen Repo-Secrets dokumentiert | `dns_net`, `frontend_net` | DNS-Aufloesung funktioniert |
|
||||||
| 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 |
|
| Tailscale | Share / Borg | `/mnt/user/appdata/tailscale` | keine | Tailscale-State im Pfad | Host-Netz | Tailscale verbunden |
|
||||||
| 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; Restore-Smoke am 2026-06-06 erfolgreich |
|
| 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 |
|
||||||
| 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-06. Pro Dienst auf einen Blick: Wurde der Restore schon einmal real getestet?
|
Stand 2026-06-05. 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-06. 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 | 2026-06-06 | Config + Container + HTTP 401 + DNS + Filter-Count | quartalsweise oder nach DNS-Aenderungen |
|
| AdGuard Home | 1 | - | noch kein Test | - |
|
||||||
| 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 | 2026-06-06 | Pre-Cutover-Artefakt + Container + PING + INFO + DBSIZE | quartalsweise oder vor/nach Redis-Major-Aenderungen |
|
| Redis 8 | 1 | - | noch kein Test | - |
|
||||||
| 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,13 +165,15 @@ Stand 2026-06-06. Pro Dienst auf einen Blick: Wurde der Restore schon einmal rea
|
|||||||
|
|
||||||
## Naechste Restore-Test-Kandidaten (priorisiert)
|
## Naechste Restore-Test-Kandidaten (priorisiert)
|
||||||
|
|
||||||
Stand 2026-06-06. Die frueheren Kandidaten (Shared PG18, Komodo Mongo, Mailarchiver, Mealie, Traefik)
|
Stand 2026-06-05. 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. **Tailscale** - State-/Reconnect-Pfad dokumentiert testen
|
2. **AdGuard Home** - Config-Restore in Testpfad oder Wegwerf-Instanz pruefen
|
||||||
|
3. **Tailscale** - State-/Reconnect-Pfad dokumentiert testen
|
||||||
|
4. **Redis 8 (Shared)** - Restore aus Datenpfad oder Pre-Cutover-Backup in isolierter Testinstanz pruefen
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -223,42 +225,28 @@ 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
|
||||||
|
|
||||||
**Automatisierter Test:**
|
**Checkliste:**
|
||||||
|
|
||||||
```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. `15353`):
|
3. Testcontainer starten (kein produktiver DNS-Port 53, stattdessen z. B. `5353`):
|
||||||
```yaml
|
```yaml
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:15353:53/udp"
|
- "5353:53/udp"
|
||||||
- "127.0.0.1:13001:80/tcp"
|
- "3001:3000/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://127.0.0.1:13001/control/status` erreichbar (`200`, `401` oder `403` sind fuer den Smoke ausreichend)
|
4. `http://localhost:3001` erreichbar, Login moeglich
|
||||||
5. DNS-Aufloesung: `dig @127.0.0.1 -p 15353 git.kaleschke.info` gibt plausible Antwort
|
5. DNS-Aufloesung: `dig @127.0.0.1 -p 5353 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.
|
||||||
@@ -296,27 +284,12 @@ HTTP `/control/status` = `401`, DNS-Smoke `git.kaleschke.info -> 192.168.178.58`
|
|||||||
|
|
||||||
### 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
|
||||||
|
|
||||||
**Automatisierter Test:**
|
**Checkliste:**
|
||||||
|
|
||||||
```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,6 +53,7 @@ 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, Subnet-Router | **Natives Unraid-Plugin** `tailscale.plg` (nicht repo-/Komodo-verwaltet) | Tailscale | Host-Netz (`tailscale1`) | `/boot/config/plugins/tailscale/state` (im Flash-Backup) | Tier 1, State relevant | nein | Subnet-Router `192.168.178.0/24`; redundanter Docker-Stack `host-services/tailscale/` am 2026-06-06 entfernt |
|
| `tailscale` | VPN/Remote-Zugang | `host-services/tailscale/docker-compose.yml` | Tailscale | Host-Netz | `/mnt/user/appdata/tailscale` | Tier 1, State relevant | nein | `network_mode: host`, `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` sind dokumentierte VPN-Ausnahmen |
|
||||||
| `gitea` | Git-Server / origin fuer GitOps | `core/gitea/docker-compose.yml` | `https://git.kaleschke.info`, SSH `222` | Traefik, `frontend_net`, externe DNS-Resolver fuer GitHub-Push-Mirror | `/mnt/user/services/gitea/data` | Tier 1, `gitea.sqlite.dump` + Share; privater GitHub-Push-Mirror fuer Repo-Bootstrap | ja | SSH-Port 222 direkte Host-Port-Ausnahme; Push-Mirror nach `michaelkaleschke-spec/homelab-infra` reduziert das DR-Bootstrap-Risiko |
|
| `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
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
# DR-Workstation Readiness - 2026-06-06
|
|
||||||
|
|
||||||
Automatisch erzeugter lokaler Readiness-Check fuer den Operator-PC. Es wurden keine Secret-Werte, Passphrases oder Private-Key-Inhalte ausgegeben.
|
|
||||||
|
|
||||||
## Zusammenfassung
|
|
||||||
|
|
||||||
| Check | Ergebnis |
|
|
||||||
|---|---|
|
|
||||||
| WSL2 Ubuntu | vorhanden (`Ubuntu 24.04`, WSL Version 2) |
|
|
||||||
| SSH/Git in WSL | vorhanden |
|
|
||||||
| GitHub-Read-Smoke mit DR-Key | ok |
|
|
||||||
| Borg Client | installiert |
|
|
||||||
| Hetzner Storage Box mit DR-Key | ok |
|
|
||||||
| `~/dr-smoke.sh` | vorhanden |
|
|
||||||
| Finaler Borg-Smoke | ok, Operator-Bestaetigung 2026-06-06 10:05:30 |
|
|
||||||
| WSL sudo ohne Passwortprompt | nein, Operator muss Passwort eingeben |
|
|
||||||
|
|
||||||
## Bewertung
|
|
||||||
|
|
||||||
- Der lokale WSL2-/Ubuntu-Unterbau ist vorhanden.
|
|
||||||
- Die DR-Key-Arbeitskopien liegen in WSL unter `~/.ssh/dr-readonly` und `~/.ssh/dr-hetzner`.
|
|
||||||
- GitHub-Read-Smoke und Hetzner-SSH-Smoke sind erfolgreich.
|
|
||||||
- `borgbackup` ist installiert.
|
|
||||||
- Der vollstaendige Bare-Metal-DR-Smoke ist erfolgreich abgeschlossen.
|
|
||||||
|
|
||||||
## Finaler Borg-Smoke
|
|
||||||
|
|
||||||
Operator-Bestaetigung vom 2026-06-06:
|
|
||||||
|
|
||||||
- Befehl: `bash ~/dr-smoke.sh`
|
|
||||||
- GitHub Deploy-Key: HEAD `3a263a4...`
|
|
||||||
- Hetzner SSH-Login: Repos `backup`, `backup2`, `hetzner_borg_appdata`, `hetzner_borg_appdata_critical` sichtbar
|
|
||||||
- Borg-Repo: `ssh://u565255@u565255.your-storagebox.de/./hetzner_borg_appdata_critical`
|
|
||||||
- Repository ID: `5dd9b949...`
|
|
||||||
- Encryption: `Yes (repokey)`
|
|
||||||
- Borg-Statistik: `Original size 1.16 TB`, `Compressed size 1.13 TB`, `Deduplicated size 35.92 GB`
|
|
||||||
- Ergebnis: `DR-Smoke OK (2026-06-06 10:05:30)`
|
|
||||||
|
|
||||||
Die Borg-Passphrase wurde nur interaktiv eingegeben und nicht dauerhaft auf `baerchen` gespeichert.
|
|
||||||
|
|
||||||
## Rohchecks
|
|
||||||
|
|
||||||
### wsl_status
|
|
||||||
|
|
||||||
- ExitCode: `0`
|
|
||||||
|
|
||||||
```text
|
|
||||||
Standarddistribution: Ubuntu
|
|
||||||
|
|
||||||
Standardversion: 2
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### wsl_list
|
|
||||||
|
|
||||||
- ExitCode: `0`
|
|
||||||
|
|
||||||
```text
|
|
||||||
NAME STATE VERSION
|
|
||||||
|
|
||||||
* Ubuntu Stopped 2
|
|
||||||
|
|
||||||
docker-desktop Stopped 2
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### ubuntu_os
|
|
||||||
|
|
||||||
- ExitCode: `0`
|
|
||||||
|
|
||||||
```text
|
|
||||||
Distributor ID: Ubuntu
|
|
||||||
Description: Ubuntu 24.04.4 LTS
|
|
||||||
Release: 24.04
|
|
||||||
Codename: noble
|
|
||||||
6.6.114.1-microsoft-standard-WSL2
|
|
||||||
```
|
|
||||||
|
|
||||||
### tools
|
|
||||||
|
|
||||||
- ExitCode: `0`
|
|
||||||
|
|
||||||
```text
|
|
||||||
/usr/bin/borg
|
|
||||||
borg 1.2.8
|
|
||||||
/usr/bin/ssh
|
|
||||||
OpenSSH_9.6p1 Ubuntu-3ubuntu13.16, OpenSSL 3.0.13 30 Jan 2024
|
|
||||||
/usr/bin/git
|
|
||||||
git version 2.43.0
|
|
||||||
```
|
|
||||||
|
|
||||||
### sudo
|
|
||||||
|
|
||||||
- ExitCode: `0`
|
|
||||||
|
|
||||||
```text
|
|
||||||
sudo-password-needed
|
|
||||||
```
|
|
||||||
|
|
||||||
### wsl_ssh_files
|
|
||||||
|
|
||||||
- ExitCode: `0`
|
|
||||||
|
|
||||||
```text
|
|
||||||
total 40
|
|
||||||
drwx------ 2 michi michi 4096 Jun 6 09:14 .
|
|
||||||
drwxr-x--- 5 michi michi 4096 Jun 6 08:37 ..
|
|
||||||
-rw------- 1 michi michi 411 Jun 6 09:14 dr-hetzner
|
|
||||||
-rw------- 1 michi michi 419 Jun 6 09:14 dr-readonly
|
|
||||||
-rw------- 1 michi michi 411 Apr 4 19:29 id_ed25519
|
|
||||||
-rw-r--r-- 1 michi michi 97 Apr 4 19:29 id_ed25519.pub
|
|
||||||
-rw------- 1 michi michi 6358 Jun 6 09:14 known_hosts
|
|
||||||
-rw------- 1 michi michi 3013 Apr 20 20:13 known_hosts.old
|
|
||||||
-rw------- 1 michi michi 3858 Apr 24 08:27 known_hosts.pre-port222-20260604-122031.bak
|
|
||||||
-rwxr-xr-x 1 michi michi 1311 Jun 6 08:37 /home/michi/dr-smoke.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### github_dr_key_smoke
|
|
||||||
|
|
||||||
- ExitCode: `0`
|
|
||||||
|
|
||||||
```text
|
|
||||||
68d3ace598ee4d1cdad3ed94b63ae5046ac187fb HEAD
|
|
||||||
```
|
|
||||||
|
|
||||||
### hetzner_dr_key_smoke
|
|
||||||
|
|
||||||
- ExitCode: `0`
|
|
||||||
|
|
||||||
```text
|
|
||||||
backup
|
|
||||||
backup2
|
|
||||||
hetzner_borg_appdata
|
|
||||||
hetzner_borg_appdata_critical
|
|
||||||
```
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
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.13@sha256:e79c381fdbf549a48adc6268c74b920b70cab53663995a2e8142964eedea10c7
|
image: filebrowser/filebrowser:v2.63.12@sha256:fc8c3a46c16bbdf97362b20c50164e97de9c1dd5f63230d28a4cb15248b53ec3
|
||||||
container_name: filebrowser
|
container_name: filebrowser
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
|
|||||||
@@ -497,6 +497,12 @@ 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
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#!/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,10 +42,6 @@ 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
|
||||||
|
|
||||||
@@ -95,8 +91,6 @@ 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
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,181 +0,0 @@
|
|||||||
#!/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"
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
#!/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,18 +40,6 @@ 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
|
||||||
@@ -95,7 +83,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|adguard|redis|nextcloud|komodo-bootstrap|komodo-mongo-restore|traefik|mailarchiver|mealie|shared-pg-cluster} [--what-if]" >&2
|
echo "Usage: $0 {freshness|vaultwarden|gitea|paperless|immich|authelia|nextcloud|komodo-bootstrap|komodo-mongo-restore|shared-pg-cluster} [--what-if]" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -28,8 +28,6 @@ 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
|
||||||
@@ -47,9 +45,7 @@ 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); AdGuard Home am
|
2026-06-03 (Config-Smoke ohne produktiven Dump-Restore).
|
||||||
2026-06-06 (Config + HTTP/DNS-Smoke); Redis 8 am 2026-06-06
|
|
||||||
(Pre-Cutover-Artefakt + PING/INFO/DBSIZE-Smoke).
|
|
||||||
|
|
||||||
## Konkreter Kalender
|
## Konkreter Kalender
|
||||||
|
|
||||||
|
|||||||
@@ -1,194 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
# baerchen App-/Lizenz-Readiness - 2026-06-06
|
|
||||||
|
|
||||||
Automatisch erzeugter lokaler Check. Keine Lizenzkeys, Passwoerter, Tokens oder Recovery-Code-Werte wurden ausgelesen oder ins Repo geschrieben.
|
|
||||||
|
|
||||||
## Ergebnis
|
|
||||||
|
|
||||||
- Technische Inventarisierung: erledigt
|
|
||||||
- Manuelle Konto-/Recovery-Bestaetigung: erledigt laut Operator-Bestaetigung 2026-06-06 ("alle Dienste laufen")
|
|
||||||
|
|
||||||
## Installierte Programme
|
|
||||||
|
|
||||||
### Passwortmanager / Browser
|
|
||||||
|
|
||||||
| DisplayName | DisplayVersion | Publisher | InstallDate |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Brave | 149.1.91.168 | Die Brave-Autoren | 20260604 |
|
|
||||||
| Google Chrome | 149.0.7827.54 | Google LLC | 20260604 |
|
|
||||||
| Microsoft Edge | 148.0.3967.96 | Microsoft Corporation | 20260604 |
|
|
||||||
| Microsoft Edge WebView2-Laufzeit | 148.0.3967.96 | Microsoft Corporation | 20260604 |
|
|
||||||
|
|
||||||
### Banking4 / Subsembly
|
|
||||||
|
|
||||||
| DisplayName | DisplayVersion | Publisher | InstallDate |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Banking4 Home | | Subsembly GmbH | |
|
|
||||||
|
|
||||||
### WISO / Buhl
|
|
||||||
|
|
||||||
| DisplayName | DisplayVersion | Publisher | InstallDate |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| WISO Steuer 2026 | 33.07.3410 | Buhl Data Service GmbH | 20260604 |
|
|
||||||
|
|
||||||
### Microsoft 365 / Office / OneDrive
|
|
||||||
|
|
||||||
| DisplayName | DisplayVersion | Publisher | InstallDate |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| Microsoft 365 - de-de | 16.0.20026.20140 | Microsoft Corporation | |
|
|
||||||
| Microsoft 365 - en-us | 16.0.20026.20140 | Microsoft Corporation | |
|
|
||||||
| Microsoft OneDrive | 23.038.0219.0001 | Microsoft Corporation | |
|
|
||||||
| Office 16 Click-to-Run Extensibility Component | 16.0.20026.20076 | Microsoft Corporation | 20260604 |
|
|
||||||
| Office 16 Click-to-Run Localization Component | 16.0.20026.20140 | Microsoft Corporation | 20260604 |
|
|
||||||
|
|
||||||
## Relevante Datenpfade
|
|
||||||
|
|
||||||
| Path | Exists | Type | LastWriteTime | Bytes |
|
|
||||||
| --- | --- | --- | --- | --- |
|
|
||||||
| C:\Users\michi\AppData\Local\Subsembly | True | Directory | 2026-06-04T12:23:43 | 43360359 |
|
|
||||||
| C:\Users\michi\AppData\Local\Buhl | True | Directory | 2026-06-04T12:55:57 | 680833 |
|
|
||||||
| C:\Users\michi\AppData\Local\Buhl Data Service GmbH | False | | | |
|
|
||||||
| C:\ProgramData\Buhl Data Service GmbH | True | Directory | 2026-06-04T12:57:08 | 6037194 |
|
|
||||||
| C:\Users\michi\Documents\steuer | True | Directory | 2026-01-26T11:21:44 | 13069132 |
|
|
||||||
| C:\Users\michi\Desktop\Banking | False | | | |
|
|
||||||
| C:\Users\michi\OneDrive | True | Directory | 2026-06-04T12:39:24 | 39370265 |
|
|
||||||
| D:\30_Finanzen | True | Directory | 2026-06-04T20:14:26 | 128994854 |
|
|
||||||
| D:\30_Finanzen\Recovery-Codes | False | | | |
|
|
||||||
| D:\30_Finanzen\BitLocker-RecoveryKey-baerchen-2026-06-06.txt | False | | | |
|
|
||||||
|
|
||||||
## OneDrive / Microsoft 365 Indikatoren
|
|
||||||
|
|
||||||
### OneDrive Prozess
|
|
||||||
|
|
||||||
_Keine Treffer._
|
|
||||||
|
|
||||||
### OneDrive Accounts Registry
|
|
||||||
|
|
||||||
| PSChildName |
|
|
||||||
| --- |
|
|
||||||
| Business1 |
|
|
||||||
| Personal |
|
|
||||||
|
|
||||||
### Office Aktivierungsindikatoren
|
|
||||||
|
|
||||||
_Keine Office-OSPP-Aktivierungsdaten gefunden oder Office nicht klassisch installiert._
|
|
||||||
|
|
||||||
## Manuell noch zu bestaetigen
|
|
||||||
|
|
||||||
- [x] Passwortmanager laesst sich oeffnen und enthaelt Homelab-/Banking-/Provider-Eintraege.
|
|
||||||
- [x] 2FA-Recovery-Codes fuer Microsoft, Hetzner, Cloudflare, Tailscale, Gitea/GitHub und Banken sind offline oder in Vaultwarden auffindbar.
|
|
||||||
- [x] Banking4 oeffnet den aktuellen Datentresor; ein frischer Backup-/Exportpfad ist bekannt.
|
|
||||||
- [x] WISO Steuer 2026 oeffnet, Buhl-Konto/Lizenz ist aktiv, Steuerdateien unter `C:\Users\michi\Documents\steuer` bzw. neuem Zielpfad sind sichtbar.
|
|
||||||
- [x] Microsoft-Konto zeigt aktives M365/Office-Installationsrecht.
|
|
||||||
- [x] OneDrive-Sync ist angemeldet und synchronisiert die erwarteten Ordner.
|
|
||||||
|
|
||||||
## Bewertung
|
|
||||||
|
|
||||||
Dieses Dokument belegt die technische Inventarisierung und die Operator-Bestaetigung vom 2026-06-06. Secret-Werte, Lizenzkeys und Recovery-Code-Werte wurden nicht dokumentiert.
|
|
||||||
@@ -46,16 +46,11 @@ 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. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
- Passwortmanager, 2FA-Recovery-Codes und Browser-Sync manuell pruefen.
|
||||||
- Banking4-Speicherort explizit pruefen. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
- Banking4-Speicherort explizit pruefen.
|
||||||
- Banking4 im Programm selbst oeffnen und aktuellen Datentresor/Backup-Export bestaetigen. Der Key und der Datentresor sind bereits lokal auf H: gesichert. **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.
|
||||||
- WISO Steuer 2026 oeffnen und Lizenz/Buhl-Konto sowie Speicherorte der Steuerdateien bestaetigen. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
- WISO Steuer 2026 oeffnen und Lizenz/Buhl-Konto sowie Speicherorte der Steuerdateien bestaetigen.
|
||||||
- Microsoft-Konto fuer M365 pruefen: Office-Webkonto/Abonnement, Installationsrecht, OneDrive-Sync. **Erledigt 2026-06-06 laut Operator-Bestaetigung.**
|
- Microsoft-Konto fuer M365 pruefen: Office-Webkonto/Abonnement, Installationsrecht, OneDrive-Sync.
|
||||||
- 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.
|
||||||
@@ -538,8 +533,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.
|
||||||
Status 2026-06-06: Passwortmanager/2FA, Banking4, WISO und Microsoft/M365
|
Als offene manuelle Pruefungen bleiben vor allem Passwortmanager/2FA,
|
||||||
wurden durch den Operator bestaetigt ("alle Dienste laufen").
|
Banking4, WISO und Microsoft/M365.
|
||||||
|
|
||||||
- [ ] Backup-Struktur auf H: erstellt
|
- [ ] Backup-Struktur auf H: erstellt
|
||||||
- [ ] Programmliste exportiert
|
- [ ] Programmliste exportiert
|
||||||
@@ -547,10 +542,10 @@ wurden durch den Operator bestaetigt ("alle Dienste laufen").
|
|||||||
- [ ] Windows-Aktivierung dokumentiert
|
- [ ] Windows-Aktivierung dokumentiert
|
||||||
- [ ] Benutzerordner gesichert
|
- [ ] Benutzerordner gesichert
|
||||||
- [ ] Browser-Lesezeichen exportiert oder Sync geprüft
|
- [ ] Browser-Lesezeichen exportiert oder Sync geprüft
|
||||||
- [x] Passwortmanager geprüft
|
- [ ] Passwortmanager geprüft
|
||||||
- [x] 2FA-Recovery-Codes gesichert
|
- [ ] 2FA-Recovery-Codes gesichert
|
||||||
- [ ] SSH/API/GPG/Zertifikate gesichert
|
- [ ] SSH/API/GPG/Zertifikate gesichert
|
||||||
- [x] Banking4-Speicherort geprüft und gesichert
|
- [ ] 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