Finalize homelab audit end state
This commit is contained in:
@@ -27,3 +27,4 @@
|
||||
Thumbs.db
|
||||
*.tmp
|
||||
*.log
|
||||
.serena/
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> **Single Source of Truth** für Docker-Netzwerkarchitektur, Sicherheitsregeln, Zielbild und Migration des Kallilabcore-Homelabs.
|
||||
> **Arbeitsregel für KI-Assistenten:** Dieses Dokument immer zuerst lesen, bevor Fragen zu Containern, Netzwerken, Traefik, Tailscale, Migration oder Security beantwortet werden.
|
||||
|
||||
**Stand:** 2026-05-16 | **Aktueller Schwerpunkt:** GitOps / Doku-Synchronisierung / Reproduzierbare Deployments
|
||||
**Stand:** 2026-05-23 | **Aktueller Schwerpunkt:** GitOps / Doku-Synchronisierung / Reproduzierbare Deployments
|
||||
|
||||
---
|
||||
|
||||
@@ -105,7 +105,7 @@ Internet
|
||||
traefik (80/443)
|
||||
│
|
||||
└── frontend_net
|
||||
├── öffentliche Apps (vaultwarden, mealie, paperless, immich, gitea, ntfy, mail-archiver, nextcloud)
|
||||
├── öffentliche Apps (vaultwarden, mealie, paperless, immich, gitea, ntfy, mail-archiver, nextcloud, jellyfin)
|
||||
├── geschützte UIs mit Middleware (homepage, glance, paperless-gpt, uptime-kuma, filebrowser, scrutiny, code-server, borg-ui, glances, speedtest, bentopdf, grafana)
|
||||
├── Admin-UI mit nativer Auth (komodo)
|
||||
└── Dienste mit Internetbedarf ohne öffentliche UI (ddns-updater)
|
||||
@@ -149,6 +149,7 @@ Diese Dienste sind über echte `*.kaleschke.info`-Domains erreichbar:
|
||||
- `gitea` (Web) — git.kaleschke.info
|
||||
- `immich_server` — immich.kaleschke.info
|
||||
- `nextcloud` — cloud.kaleschke.info
|
||||
- `jellyfin` — jellyfin.kaleschke.info
|
||||
|
||||
### 4.2 Nicht öffentlich / nur Tailscale oder Traefik + Middleware
|
||||
Diese Dienste sind **keine Public Apps**:
|
||||
@@ -278,6 +279,8 @@ Legende Status:
|
||||
| `immich_server` | ✅ | `immich_default`, `frontend_net` | Traefik | aktiv via `immich.kaleschke.info` | — |
|
||||
| `immich_machine_learning` | ✅ | `immich_default` | intern | bleibt intern | — |
|
||||
| `nextcloud` | ✅ | `frontend_net`, `nextcloud_internal` | Traefik | aktiv via `cloud.kaleschke.info`, nativer Nextcloud-Login, WebDAV/CardDAV faehig | CalDAV/CardDAV-Redirect via Traefik-Labels |
|
||||
| `jellyfin` | ✅ | `frontend_net` | Traefik | aktiv via `jellyfin.kaleschke.info`, native Jellyfin-Auth, Media-/Photos-Mounts read-only | — |
|
||||
| `plex` | ✅ | `host` | Plex native / Host-Netz | Compose-Stack unter `host-services/plex/`; Host-Netz bleibt fuer Discovery / Plex GDM dokumentierte Ausnahme | — |
|
||||
|
||||
### 7.5 Admin / Operations
|
||||
|
||||
@@ -311,7 +314,7 @@ Legende Status:
|
||||
|
||||
| Container | Status | Ziel |
|
||||
|---|---|---|
|
||||
| `Plex-Media-Server` | ⏳ Dockerman | Compose-Migration, `host`-Netz bleibt (Discovery) |
|
||||
| — | — | Plex ist nicht mehr offen: der Dienst ist als Repo-Compose-Stack unter `host-services/plex/` dokumentiert; `host`-Netz bleibt als Discovery-Ausnahme. |
|
||||
|
||||
### 7.8 Entfernte Container
|
||||
|
||||
|
||||
@@ -0,0 +1,369 @@
|
||||
# Homelab Audit - 2026-05-23
|
||||
|
||||
Stand: 2026-05-23, repo-basiert. Erstellt nach `docs/WORKFLOW.md` und `docs/GITOPS_DRIFT_RUNBOOK.md`. Quellebasis: `origin/master` plus lokaler Clone, ohne Schreibbefehle, ohne Deploy.
|
||||
|
||||
Dieser Audit ist eine punktuelle Sollzustands-Bewertung, kein Live-Status. Die Live-Verifikations-Schritte stehen am Ende in Abschnitt 9; alle dortigen Outputs ersetzen Vermutungen durch Messwerte.
|
||||
|
||||
## 0. Executive Summary
|
||||
|
||||
Ampel-Bewertung pro Bereich:
|
||||
|
||||
| Bereich | Ampel | Kernaussage |
|
||||
|---|---|---|
|
||||
| GitOps-Konsistenz (lokal/Gitea) | 🟡 | Lokaler Clone ist **1 Commit voraus** auf `master` (`cd650b1`, Haertungs-Commit). Bis zum Push existiert dieser Stand nur lokal, nicht in Gitea — bei einem Clone-Verlust ist er weg. |
|
||||
| GitOps-Konsistenz (Working Tree) | 🟢* | Keine echten Inhaltsaenderungen offen. Die 47 "modified files" aus `git status` im Linux-Mount sind voraussichtlich CRLF/LF-Mount-Artefakte (durch `git diff -w --stat` auf Stichprobe bestaetigt leer). Bitte am Windows-Host gegenpruefen. |
|
||||
| Hardening-Sprint (Mai 2026) | 🟢 | Alle vier Post-Restore-Sprint-Items sind im Repo umgesetzt (Filebrowser-Mounts, Authelia Argon2id, Gitea Webhook-Allowlist, Backup-Dump-Konsistenz). |
|
||||
| Backup/Restore-Readiness | 🟢 | `pre-backup-dumps.sh` deckt alle relevanten SQLite/PostgreSQL/Mongo-Quellen ab. Borg-UI-Scope umfasst `/mnt/user/services`, `homelab-infra`, `stacks`, `posture-check`. Live-Frische ist offen (Abschnitt 9). |
|
||||
| Monitoring-Migration | 🟡 | `monitoring/` Stack im Repo komplett, aber Live-Deploy laut `docs/NEXT_SPRINT_TODO_2026-05-16.md` noch ausstehend. Alte Stacks `ops/grafana-influxdb` und `ops/loki` sollen erst nach Live-Smoke-Test gestoppt werden. |
|
||||
| Doku-Drift Repo vs. Master-Doku | 🟠 | `apps/jellyfin/`, `host-services/plex/` und einige andere existieren produktiv als Compose-Stacks, sind aber in `HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/SERVICE_CATALOG.md` und `docs/REPO_MAP.md` **nicht aufgefuehrt**. Authelia-ACL kennt `jellyfin.kaleschke.info` als bypass, im Masterdoku-Hostkatalog steht es nicht. |
|
||||
| Repo-Hygiene | 🟡 | 8 leere Verzeichnisse im Working Tree (siehe 4.3). `.serena/` ist untracked und nicht in `.gitignore`. Drei `ops/windows-reinstall/*.ps1` sind untracked. |
|
||||
| Bekannte Ausnahmen | 🟢 | Alle Ausnahmen aus `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 10 sind weiterhin dokumentiert und durch den Policy-Check abgedeckt (0 Critical, 4 Warnings, 9 Info – alles dokumentierte Ausnahmen). |
|
||||
|
||||
**Kernfazit:** Das Homelab ist sehr nah an der "Endstufe". Es gibt keine kritischen Befunde. Die einzige Pflichtaktion vor dem naechsten geplanten Schritt ist der **Push des lokalen Commits `cd650b1` nach Gitea**, damit `origin/master` wieder die Quelle der Wahrheit ist. Danach sind nur noch zwei priorisierte Pakete offen: Monitoring-Stack live finalisieren und Doku auf den Stand der neuen Stacks (Jellyfin/Plex/...) nachziehen.
|
||||
|
||||
---
|
||||
|
||||
## 1. Methodik und Quellen
|
||||
|
||||
Diese Audit-Quellen wurden gelesen (repo-seitig):
|
||||
|
||||
- `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
- `docs/WORKFLOW.md`
|
||||
- `docs/REPO_MAP.md`
|
||||
- `docs/SERVICE_CATALOG.md`
|
||||
- `docs/RESTORE_MATRIX.md`
|
||||
- `docs/GITOPS_DRIFT_RUNBOOK.md`
|
||||
- `docs/NEXT_SPRINT_TODO_2026-05-16.md`
|
||||
- `ops/borg-ui/scripts/pre-backup-dumps.sh`
|
||||
- `ops/borg-ui/docker-compose.yml`
|
||||
- `ops/borg-ui/all-important-sources.txt`
|
||||
- `ops/filebrowser/docker-compose.yml`
|
||||
- `security/authelia/configuration.yml`
|
||||
- `core/gitea/docker-compose.yml`
|
||||
- `apps/jellyfin/docker-compose.yml`
|
||||
- `host-services/plex/docker-compose.yml`
|
||||
- `ops/policy-checks/last-report.md`
|
||||
|
||||
Schreibbefehle: keine. Deploys: keine. Containerlaufzeit, Komodo-Webhook-Status, Borg-Lauf-Frische und Host-Listener wurden bewusst nicht angetastet — dafuer steht der Live-Daten-Block in Abschnitt 9.
|
||||
|
||||
---
|
||||
|
||||
## 2. Schicht A — GitOps und Konsistenz
|
||||
|
||||
### 2.1 Lokaler Clone vs. `origin/master`
|
||||
|
||||
```
|
||||
## master...origin/master [ahead 1]
|
||||
HEAD = cd650b19ac057a1b74ac63503e5dba50eaf5b8ea
|
||||
origin/master = af231dd4e835b19005cc0842509199d480af00d9
|
||||
```
|
||||
|
||||
- **Befund:** Lokaler Clone ist 1 Commit voraus.
|
||||
- **Commit:** `cd650b1 Close Gitea signup, dedup posture-check alerts, extend Borg scope` (Sat May 23 11:01:24 2026 +0200).
|
||||
- **Inhalt** (laut Commit-Message und betroffenen Dateien):
|
||||
- Gitea: `DISABLE_REGISTRATION=true`, `ENABLE_OPENID_SIGNIN=false`, `ENABLE_OPENID_SIGNUP=false`
|
||||
- Repo-Pflicht-Doku ergaenzt: Komodo-Stack-Webhook-Pflicht in `CLAUDE.md`, `AI_CONTEXT.md`, `WORKFLOW.md`
|
||||
- `posture-check.sh`: Disk1-NTFS-Funktion ausgelagert, Inode-Check auf NTFS uebersprungen, ntfy-Dedup via Fingerprint-State + `ALERT_REPEAT_SECONDS`
|
||||
- `docker-critical-events.sh`: JSON-Parsing, `die exit=0` gefiltert, strukturierte ntfy-Message
|
||||
- `borg-ui`: `/mnt/user/services` als `/local/services:ro` gemountet, `all-important-sources.txt` ergaenzt
|
||||
- Unraid User Scripts dokumentiert (daily report)
|
||||
- `MIGRATION_LOG.md`, `RESTORE_MATRIX.md`, `DISASTER_RECOVERY.md` aktualisiert
|
||||
- **Risiko:** Bei Verlust des Windows-Clones (Reinstall, Diskcrash) ist dieser Stand verloren, weil er nicht in Gitea liegt. Komodo deployt ausserdem aus Gitea und kennt diese Aenderungen noch nicht.
|
||||
- **Empfohlene Aktion (Pflicht vor weiterer Arbeit):** In GitHub Desktop `Push origin` ausfuehren. Danach Komodo-Reaktion fuer die betroffenen Stacks (`gitea`, `borg-ui`) pruefen und Smoke-Tests laufen lassen.
|
||||
|
||||
### 2.2 Working-Tree-Status
|
||||
|
||||
```
|
||||
$ git status --short
|
||||
M CLAUDE.md
|
||||
M HOMELAB_ARCHITECTURE_MASTER_V2.md
|
||||
M apps/homepage/docker-compose.yml
|
||||
...
|
||||
(47 Dateien als modified gemeldet, plus 4 Untracked)
|
||||
```
|
||||
|
||||
- **Bewertung:** Die 47 "modified files" sind mit hoher Wahrscheinlichkeit **Mount-Artefakte** durch CRLF/LF zwischen Windows-Clone und Linux-Mount. Stichprobe `git diff -w --stat CLAUDE.md HOMELAB_ARCHITECTURE_MASTER_V2.md` lieferte leer — d. h. keine inhaltlichen Diffs.
|
||||
- **Aktion:** Bitte am Windows-Host in GitHub Desktop `git status --short` ausfuehren. Wenn dort der Tree leer ist (nur die 4 Untracked), gibt es keinen echten Working-Tree-Drift. Wenn dort echte Diffs erscheinen, hier bitte zurueckmelden — dann ist das ein eigener Befund.
|
||||
- **Optional (nicht Pflicht):** `.gitattributes` mit `* text=auto eol=lf` haerten, damit dieser Mount-Effekt fuer KI-Audits aus dem Weg geht. Das ist ein eigener kleiner Commit, kein Audit-Output.
|
||||
|
||||
### 2.3 Untracked Files
|
||||
|
||||
```
|
||||
?? .serena/
|
||||
?? ops/windows-reinstall/backup-delta-after-2026-05-07.ps1
|
||||
?? ops/windows-reinstall/cleanup-dualboot-bcd.ps1
|
||||
?? ops/windows-reinstall/repair-disk0-boot-to-new-windows.ps1
|
||||
```
|
||||
|
||||
- `.serena/` ist das Working-Directory des Serena Code-Search-Tools. Hat eigene `.gitignore` intern, aber das `.serena/`-Verzeichnis selbst ist nicht in der Repo-`.gitignore`.
|
||||
- **Aktion (klein):** `.serena/` in `.gitignore` aufnehmen, damit es nicht versehentlich committet wird.
|
||||
- Die drei PowerShell-Scripts unter `ops/windows-reinstall/` sind Windows-Reinstall-Helfer. Entscheidung offen: ins Repo aufnehmen (mit Kontextkommentar warum sie dort liegen) oder lokal halten und in `.gitignore` aufnehmen. Vorschlag: aufnehmen, weil `ops/` der dokumentierte Ort fuer Ops-Skripte ist.
|
||||
|
||||
### 2.4 Letzte Commit-Historie (Top 10)
|
||||
|
||||
```
|
||||
cd650b1 Close Gitea signup, dedup posture-check alerts, extend Borg scope [LOKAL, NICHT GEPUSHT]
|
||||
af231dd Fix zero-count noise pattern handling
|
||||
428223d Mark posture report scripts executable
|
||||
b6d3ed4 Tune homelab availability alerts
|
||||
9e7bebb Add daily operations report with hardened log-noise filtering
|
||||
b7cbbe5 Fix Jellyfin external DNS
|
||||
71ac18b Fix Jellyfin native auth routing
|
||||
90f270b Fix Jellyfin config permissions
|
||||
e28f8da Add Jellyfin media server stack
|
||||
edfec5b Add Plex media server stack
|
||||
```
|
||||
|
||||
- Die letzten Tage waren sichtbar: Jellyfin/Plex hinzugefuegt, Availability-Alerts feinjustiert, Posture-Check-Skripte produktiv gemacht, dann der grosse Haertungs-Commit gestern (2026-05-23 11:01).
|
||||
|
||||
### 2.5 Compose-Inventar vs. Doku
|
||||
|
||||
Repo hat folgende Compose-Stacks, die in den Doku-Quellen (`HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md`) **nicht oder nur teilweise** aufgefuehrt sind:
|
||||
|
||||
| Stack | Status im Repo | Status in Master-Doku |
|
||||
|---|---|---|
|
||||
| `apps/jellyfin/docker-compose.yml` | produktiv vorhanden, gepinnt `jellyfin:10.11.8@sha256:...`, Traefik `jellyfin.kaleschke.info`, `secure-headers@file`, native Auth, `/mnt/user/media:ro` + `/mnt/user/photos:ro` | **fehlt** in 7.4 Apps; Authelia-ACL kennt aber bereits `jellyfin.kaleschke.info` als bypass — Doku hinkt hinterher |
|
||||
| `host-services/plex/docker-compose.yml` | produktiv vorhanden, gepinnt `plexinc/pms-docker:1.43.1.10611-1e34174b1@sha256:...`, `network_mode: host`, `/mnt/user/media:ro` + `/mnt/user/photos:ro` | Master-Doku sagt explizit "Plex-Media-Server ist historischer Host-Sonderfall, nicht als Repo-Compose-Stack enthalten" — **das stimmt nicht mehr**, Plex ist jetzt ein Repo-Compose-Stack |
|
||||
| `host-services/docker/` | leeres Verzeichnis | nicht erwaehnt |
|
||||
| `infra/dns/` | leeres Verzeichnis | nicht erwaehnt |
|
||||
| `ops/Semaphore/` | Skripten/Playbooks aber kein Compose | nicht erwaehnt |
|
||||
| `ops/backrest/` | leeres Verzeichnis (Stack laut Master-Doku am 2026-05-15 entfernt) | korrekt als entfernt dokumentiert; Verzeichnis sollte leer bleiben oder weg |
|
||||
| `apps/firefly/`, `apps/firefly-fints/` | leere Verzeichnisse | nicht erwaehnt |
|
||||
| `apps/stirling-pdf/` | leeres Verzeichnis (durch `bentopdf` abgeloest) | korrekt als abgeloest dokumentiert |
|
||||
|
||||
- **Aktion (Doku-Synchronisierung):** `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 7 (Container-Zielbild), `docs/SERVICE_CATALOG.md` und `docs/REPO_MAP.md` um Jellyfin und Plex erweitern. Plex-Doku im Master umschreiben: nicht mehr "historisch ausserhalb Repo", sondern "Compose-Stack mit `network_mode: host` als VPN-Discovery-Ausnahme".
|
||||
- **Aktion (Repo-Hygiene):** Die leeren Verzeichnisse `apps/firefly`, `apps/firefly-fints`, `apps/stirling-pdf`, `host-services/docker`, `infra/dns`, `ops/backrest`, `ops/grafana-influxdb/scripts`, `ops/Semaphore/playbooks`, `ops/Semaphore/Scripts` aufraeumen — Master-Doku sagt: "Leere `.keep`-Platzhalter wurden entfernt; neue Verzeichnisse sollen erst mit konkretem Inhalt ins Repo." Diese Verzeichnisse verletzen diese Regel passiv.
|
||||
|
||||
### 2.6 Image-Pinning
|
||||
|
||||
Lt. `docs/NEXT_SPRINT_TODO_2026-05-16.md` sind diese Stacks noch nicht voll versioniert gepinnt:
|
||||
- `ddns-updater` — `latest...@sha256`
|
||||
- `glances` — `latest-full@sha256`
|
||||
- `scrutiny` — `latest-omnibus@sha256`
|
||||
|
||||
Das ist bewusst dokumentiert und kein Audit-Befund.
|
||||
|
||||
---
|
||||
|
||||
## 3. Schicht B — Hardening-Sprint 2026-05 (Sitrep)
|
||||
|
||||
Dies war der Sprint, der nach dem 2026-05 Restore explizit gesetzt wurde. Stand im Repo:
|
||||
|
||||
| Sprint-Item | Stand 2026-05-16 (Plan) | Stand 2026-05-23 (Repo) | Beleg |
|
||||
|---|---|---|---|
|
||||
| **(1) Backup-Konsistenz** — `dump_sqlite_container` fuer Gitea/Vaultwarden/Uptime-Kuma/Speedtest/Filebrowser + `pg_dump` Nextcloud | offen | ✅ erledigt | `ops/borg-ui/scripts/pre-backup-dumps.sh` Z. 97–139 (`dump_sqlite_container`), Z. 253–258 (Nextcloud `pg_dump`), Z. 261–264 (alle SQLite-Container mit Host-Fallback), Z. 267 (Filebrowser BoltDB). Borg-Scope erweitert um `/mnt/user/services` (Borg-UI Compose Z. 26 + `all-important-sources.txt` Z. 23–25). |
|
||||
| **(2) Filebrowser entschaerfen** — `/mnt/user/appdata:/srv/appdata` weg, gezielte RW-Subpfade | offen | ✅ erledigt | `ops/filebrowser/docker-compose.yml` Z. 11–16. Keine Appdata-Mounts mehr. Nur noch `/mnt/user/documents`, `/mnt/user/photos`, `/mnt/user/projekte` als Datenmounts plus eigener `/database` und `/config`. |
|
||||
| **(3) Authelia Argon2id haerten** — iterations 3, memory 65536, parallelism 4 | offen | ✅ erledigt | `security/authelia/configuration.yml` Z. 17–25. Exakt die geplanten Parameter sind aktiv. |
|
||||
| **(4) Gitea Webhook-Allowlist** — `ALLOWED_HOST_LIST=*` einschraenken | offen | ✅ erledigt | `core/gitea/docker-compose.yml` Z. 18: `GITEA__webhook__ALLOWED_HOST_LIST=komodo-core,localhost,127.0.0.1,192.168.178.0/24`. Zusatz aus heutigem Commit: Public Registration und OpenID-Signup/Signin sind deaktiviert. |
|
||||
|
||||
Alle vier Items sind **im Repo abgeschlossen**. Live-Wirksamkeit haengt am Komodo-Deploy aus Gitea — und genau da haengt aktuell der ungepushte Commit `cd650b1` davor (siehe 2.1). Solange er nicht in Gitea ist, ist insbesondere die Gitea-Signup-Schliessung im Live-Stand nicht garantiert.
|
||||
|
||||
**Bewusst nicht angefasste Liste (Operator-Entscheidung 2026-05-16) ist weiterhin gueltig:**
|
||||
- Hermes — bleibt VM-seitig offen, NAS-Stack bewusst nicht starten
|
||||
- Disk1 NTFS — Phase-2-Migration nach Plan
|
||||
- Komodo native Auth ohne ForwardAuth
|
||||
- Grafana/Influxdb3-core `user: "0"`
|
||||
- Image-Pinning-Vereinheitlichung (`:latest@sha256:`) fuer ddns-updater/glances/scrutiny
|
||||
|
||||
---
|
||||
|
||||
## 4. Schicht C — "Endstufe?"-Bewertung
|
||||
|
||||
### 4.1 Backup/Restore-Readiness
|
||||
|
||||
- **Dump-Coverage:** `pre-backup-dumps.sh` deckt 14 Quellen ab: PostgreSQL-Globals + 3 Shared-DBs + 3 dedizierte Postgres (mealie, immich, nextcloud) + 4 SQLite (gitea, vaultwarden, uptime-kuma, speedtest-tracker) + Filebrowser-BoltDB + Borg-UI + Grafana + Komodo-Mongo. Deckt 1:1 die Restore-Matrix-Eintraege ab.
|
||||
- **Borg-Scope:** `all-important-sources.txt` enthaelt 27 Eintraege inkl. neuer `services/homelab-infra`, `services/stacks`, `services/posture-check` und `secrets`.
|
||||
- **Restore-Validierungen:** Laut `docs/RESTORE_MATRIX.md` sind am 2026-05-07 Mini-Restores fuer `gitea`, `vaultwarden` und `paperless` validiert worden — dokumentierter Stand.
|
||||
- **Live offen:** Wann lief der letzte Borg-Lauf? Sind alle Dumps unter `/mnt/user/backups/borg/dumps/latest` frischer als 24h? Siehe Live-Checkliste 9.4.
|
||||
|
||||
### 4.2 Monitoring-Migration
|
||||
|
||||
- Repo-Zielzustand `monitoring/docker-compose.yml` (337 Zeilen Compose) existiert mit Prometheus, Alertmanager, ntfy-Bridge, Blackbox-Exporter, Loki, Promtail, Grafana, node-exporter, cAdvisor, InfluxDB3 Core.
|
||||
- Provisioning unter `monitoring/grafana/provisioning/` und `monitoring/prometheus/`, `monitoring/loki/`, `monitoring/promtail/`, `monitoring/alertmanager/`, `monitoring/blackbox/` vollstaendig vorhanden.
|
||||
- Alte Stacks `ops/grafana-influxdb/` und `ops/loki/` bewusst noch im Repo (dokumentierter Altstand, Rollback-Referenz).
|
||||
- **Live offen:** Ist `monitoring` schon als Komodo-Stack deployed? Laufen die Container? Sind die Secret-Dateien `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json` auf dem Host? Siehe Live-Checkliste 9.5.
|
||||
|
||||
### 4.3 Repo-Hygiene
|
||||
|
||||
| Befund | Schwere | Aktion |
|
||||
|---|---|---|
|
||||
| 8 leere Verzeichnisse (`apps/firefly`, `apps/firefly-fints`, `apps/stirling-pdf`, `host-services/docker`, `infra/dns`, `ops/backrest`, `ops/grafana-influxdb/scripts`, `ops/Semaphore/playbooks`, `ops/Semaphore/Scripts`) | klein | Aufraeumen, danach committen |
|
||||
| `.serena/` untracked, nicht in `.gitignore` | klein | `.serena/` zu `.gitignore` hinzufuegen |
|
||||
| 3 `ops/windows-reinstall/*.ps1` untracked | klein | Entscheidung treffen: ins Repo oder ignorieren |
|
||||
|
||||
### 4.4 Bekannte dokumentierte Ausnahmen
|
||||
|
||||
Aus `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 10 — alle weiterhin gueltig und durch den Policy-Check abgedeckt (`ops/policy-checks/last-report.md` 0 Critical):
|
||||
|
||||
- Traefik 80/443
|
||||
- Tailscale Host-Netz + Capabilities
|
||||
- AdGuard Port 53 + 8082 (Admin-Port LAN-only, dokumentiert; **offener Punkt im Master:** "Traefik-Absicherung ausstehend (Block F)" — bewusst spaeter)
|
||||
- Plex Host-Netz (aber Master-Doku-Eintrag jetzt falsch, siehe 2.5)
|
||||
- Scrutiny `privileged: true`
|
||||
- Komodo Docker-Socket + keine pauschale Middleware
|
||||
- glance-docker-socket-proxy Read-only Socket
|
||||
- Gitea SSH 222
|
||||
- ddns-updater `frontend_net`
|
||||
- mail-archiver Hybrid-Netze
|
||||
- `traefik/dynamic/*` manueller Host-Sync
|
||||
- nextcloud native Auth
|
||||
- monitoring-influxdb3-core LAN 8181 + `user: "0"`
|
||||
- monitoring-promtail Docker-Socket read-only
|
||||
|
||||
Keine ungeplanten neuen Ausnahmen.
|
||||
|
||||
### 4.5 Endstufen-Definition
|
||||
|
||||
"Endstufe" ist erreicht, wenn alle folgenden Punkte gruen sind:
|
||||
|
||||
1. **Gitea = Quelle der Wahrheit** — kein lokaler Commit ohne Push 🟡 (heute: `cd650b1` ungepusht)
|
||||
2. **Hardening-Sprint im Repo abgeschlossen** 🟢
|
||||
3. **Backup-Konsistenz live verifiziert (Borg laeuft, Dumps frisch)** ❓ Live
|
||||
4. **Monitoring-Stack live, alte Altstaende gestoppt** 🟡
|
||||
5. **Doku synchron mit Repo (Jellyfin/Plex, leere Verzeichnisse, ...)** 🟠
|
||||
6. **Policy-Check 0 Critical** 🟢 (4 Warnings sind dokumentierte Ausnahmen)
|
||||
7. **Restore-Lab gepflegt (`mail-archiver` als naechste Uebung empfohlen)** 🟡 dokumentiert offen
|
||||
|
||||
Sechs der sieben Punkte sind in Reichweite ohne neue Architekturentscheidungen. Punkt 3 und 4 brauchen Live-Daten (Abschnitt 9). Punkt 1 ist 1 Push entfernt.
|
||||
|
||||
---
|
||||
|
||||
## 5. Priorisierte Restliste
|
||||
|
||||
| Prio | Aktion | Begruendung | Aufwand |
|
||||
|---|---|---|---|
|
||||
| **P0** | `cd650b1` nach Gitea pushen | GitOps-Quelle-der-Wahrheit, Voraussetzung fuer alles weitere | 30 Sekunden |
|
||||
| **P0** | Live-Daten aus Abschnitt 9 einholen | Ohne Live-Frische ist Endstufen-Bewertung unvollstaendig | 5 Minuten |
|
||||
| **P1** | Monitoring-Stack live finalisieren (Secrets pruefen, deployen, Smoke-Test, alte Altstaende stoppen) | Aus `docs/NEXT_SPRINT_TODO_2026-05-16.md` der naechste produktive Schritt | 1–2 Stunden mit Tests |
|
||||
| **P2** | Doku-Drift schliessen: Jellyfin und Plex in `HOMELAB_ARCHITECTURE_MASTER_V2.md` 7.4 + 7.1, `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md` ergaenzen; Plex-Eintrag in Abschnitt 7.7 "noch offene Sonderfaelle" entfernen (ist umgesetzt) | Doku ist Source of Truth fuer KI-Audits und Nachfolge | 30 Minuten |
|
||||
| **P2** | Home Assistant -> InfluxDB final testen, HA-Dashboard in `monitoring-grafana` anlegen | aus NEXT_SPRINT_TODO | 1–2 Stunden |
|
||||
| **P3** | Repo-Hygiene: 8 leere Verzeichnisse loeschen, `.serena/` in `.gitignore`, Entscheidung zu `ops/windows-reinstall/*.ps1` | minor, aber dokumentiert | 15 Minuten |
|
||||
| **P3** | Naechster Restore-Lab-Lauf: `mail-archiver` (empfohlen in `RESTORE_MATRIX.md`) | Restore-Routine ueben, bevor sie gebraucht wird | 1 Stunde |
|
||||
| **P4** | `.gitattributes` mit `* text=auto eol=lf` hinzufuegen, um CRLF/LF-Mount-Effekte bei KI-Audits zu vermeiden | klein, kosmetisch fuer kuenftige Audits | 5 Minuten |
|
||||
| **bleibt** | Hermes VM-Seite, Disk1-NTFS Phase 2, AdGuard Admin-Port hinter Traefik (Block F), Image-Pinning ddns/glances/scrutiny | bewusste Operator-Entscheidung, kein Audit-Beduerfnis | nicht jetzt |
|
||||
|
||||
---
|
||||
|
||||
## 6. Was bewusst NICHT angetastet wurde (Audit-Verzicht)
|
||||
|
||||
Konsistent mit der bekannten Nicht-Anfassen-Liste:
|
||||
|
||||
- Hermes (VM-seitig offen)
|
||||
- Disk1 NTFS (Phase-2-Migration nach Plan)
|
||||
- Komodo native Auth ohne ForwardAuth
|
||||
- Grafana / influxdb3-core `user: "0"` Uebergangsausnahme
|
||||
- Image-Pinning-Vereinheitlichung fuer ddns-updater/glances/scrutiny
|
||||
|
||||
---
|
||||
|
||||
## 7. Risiken und Drift-Indikatoren
|
||||
|
||||
| Risiko | Wahrscheinlichkeit | Wirkung | Migitation |
|
||||
|---|---|---|---|
|
||||
| Lokaler Clone-Verlust (Disk, Reinstall) bevor `cd650b1` gepusht wurde | gering, aber real (Du bist im Reinstall-Kontext, siehe `ops/windows-reinstall/`!) | Verlust von Gitea-Signup-Closure und Posture-Check-Verbesserungen | **Sofort pushen** |
|
||||
| Komodo deployt aus Gitea, `gitea` und `borg-ui` laufen aktuell ohne die heutigen Verbesserungen | mittel | Gitea Signup steht noch offen, Borg-Scope umfasst `/mnt/user/services` noch nicht | Push + Komodo-Reaktion pruefen |
|
||||
| 47 vermeintlich modified files koennten doch echte Diffs sein, wenn der Windows-Host etwas anderes zeigt | gering | falsche Audit-Aussage | Punkt 9.1 auf dem Windows-Host pruefen |
|
||||
| Doku-Drift wird groesser, wenn weitere Stacks ohne Doku-Update hinzukommen | mittel | KI-Audits und Onboarding leiden | P2-Doku-Sync nicht aufschieben |
|
||||
| Monitoring-Stack-Migration unfertig, alter und neuer Stack koennten parallel werden | mittel | Doppelte Metric-/Log-Pipeline, Verwirrung bei Diagnose | Live-Status klaeren bevor Deploy |
|
||||
|
||||
---
|
||||
|
||||
## 8. Sources of Truth — Schnellzugriff
|
||||
|
||||
- Operative Quelle der Wahrheit: Gitea `origin/master` (https://git.kaleschke.info/Micha/homelab-infra)
|
||||
- Architektur-Master: `HOMELAB_ARCHITECTURE_MASTER_V2.md`
|
||||
- Workflow / GitOps-Regeln: `docs/WORKFLOW.md`
|
||||
- Drift-Runbook: `docs/GITOPS_DRIFT_RUNBOOK.md`
|
||||
- Restore-Quellen: `docs/RESTORE_MATRIX.md`, `docs/DISASTER_RECOVERY.md`
|
||||
- Letzter Policy-Check: `ops/policy-checks/last-report.md` (0 Critical)
|
||||
- Letzte Sprint-Restliste: `docs/NEXT_SPRINT_TODO_2026-05-16.md`
|
||||
|
||||
---
|
||||
|
||||
## 9. Live-Daten-Checkliste — bitte ausfuehren und zurueckspielen
|
||||
|
||||
Fuehre die folgenden Bloecke am Unraid-Host (per SSH oder Web-Terminal) und am Windows-Host (Git Bash / PowerShell in `G:\Gitea_Clone\homelab-infra`) aus und pastiere die Outputs zurueck. Ich integriere sie dann in diesen Report.
|
||||
|
||||
### 9.1 Windows-Host: Echter Working-Tree-Status
|
||||
|
||||
```powershell
|
||||
cd G:\Gitea_Clone\homelab-infra
|
||||
git status --short
|
||||
git log origin/master..HEAD --oneline
|
||||
```
|
||||
|
||||
Erwartet: Working tree leer (oder nur die 4 Untracked). `cd650b1` als einziger lokaler Commit.
|
||||
|
||||
### 9.2 Unraid-Host: Gitea online
|
||||
|
||||
```bash
|
||||
curl -sI --max-time 5 https://git.kaleschke.info/ | head -5
|
||||
docker exec gitea sh -lc 'gitea --version'
|
||||
```
|
||||
|
||||
Erwartet: `HTTP/2 200` (oder ein Auth-Code, der den Erreichbarkeitstest erfuellt). Gitea-Version stimmt mit Image-Tag `1.25.4` ueberein.
|
||||
|
||||
### 9.3 Unraid-Host: Komodo-Webhook-Status
|
||||
|
||||
In Komodo UI fuer jeden produktiven Stack aus `Micha/homelab-infra` pruefen:
|
||||
- `webhook_enabled: true`
|
||||
- Gitea-Hook auf `http://komodo-core:9120/listener/github/stack/<stack-id>/deploy` aktiv
|
||||
- `last_status` der letzten Webhook-Delivery in Gitea (Repository -> Settings -> Webhooks)
|
||||
|
||||
Pflicht-Stacks zum Pruefen: `traefik`, `gitea`, `authelia`, `vaultwarden`, `postgresql17`, `redis`, `paperless-ngx`, `immich`, `nextcloud`, `mealie`, `mail-archiver`, `ntfy`, `homepage`, `paperless-gpt`, `borg-ui`, `filebrowser`, `code-server`, `uptime-kuma`, `glance`, `glances`, `scrutiny`, `speedtest-tracker`, `bentopdf`, `ddns-updater`, `komodo`, `jellyfin`, `plex`, `adguard`, `tailscale`, `monitoring`, `hermes-agent` (sofern produktiv).
|
||||
|
||||
Bei Stacks **ohne** aktiven Webhook bitte den Grund vermerken (dokumentierte Ausnahme oder Nachholbedarf).
|
||||
|
||||
### 9.4 Unraid-Host: Borg-Lauf-Frische und Dump-Coverage
|
||||
|
||||
```bash
|
||||
ls -lah /mnt/user/backups/borg/dumps/latest/
|
||||
stat -c '%y %n' /mnt/user/backups/borg/dumps/latest/*.dump /mnt/user/backups/borg/dumps/latest/*.sql /mnt/user/backups/borg/dumps/latest/*.archive.gz /mnt/user/backups/borg/dumps/latest/*.sqlite 2>/dev/null | sort
|
||||
docker exec borg-ui borg list --short 2>&1 | tail -10
|
||||
```
|
||||
|
||||
Erwartet: Alle 14 Artefakte aus 4.1 sind vorhanden, mtime juenger als 24h. Borg-Archive-Liste zeigt regelmaessige Laeufe.
|
||||
|
||||
### 9.5 Unraid-Host: Monitoring-Stack live?
|
||||
|
||||
```bash
|
||||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Image}}" | grep monitoring
|
||||
ls -la /mnt/user/appdata/secrets/ | grep -E 'monitoring|influxdb3'
|
||||
curl -sI --max-time 5 https://monitoring.kaleschke.info/ | head -5
|
||||
ss -ltnp 2>/dev/null | grep -E ':8181|:9090|:3100' | head -10
|
||||
```
|
||||
|
||||
Erwartet: Entweder alle `monitoring-*` Container laufen (dann ist 4.2 🟢) oder gar nicht (dann ist 4.2 🟡 wie aktuell bewertet). Halb-Zustand ist ein Audit-Befund.
|
||||
|
||||
### 9.6 Unraid-Host: GitOps-Pflichtmatrix Spot-Check fuer einen Stack
|
||||
|
||||
Beispiel `gitea` (weil der heutige Commit ihn betrifft):
|
||||
|
||||
```bash
|
||||
cd /mnt/user/services/stacks/gitea
|
||||
git rev-parse --short HEAD
|
||||
git status -sb
|
||||
docker inspect gitea --format '{{.Image}}'
|
||||
docker exec gitea sh -lc 'env | grep -E "ALLOWED_HOST_LIST|DISABLE_REGISTRATION|ENABLE_OPENID"'
|
||||
```
|
||||
|
||||
Erwartet: Komodo-Workspace `HEAD` zeigt entweder auf `cd650b1` (wenn Push schon erfolgt + Komodo deployed) oder auf `af231dd` (vor dem Push). ENV-Vars in der Live-Runtime spiegeln den Commit, der Komodo zuletzt deployed hat.
|
||||
|
||||
### 9.7 Unraid-Host: Host-Listener-Spot-Check
|
||||
|
||||
```bash
|
||||
ss -ltnp 2>/dev/null | grep -E ':80|:443|:53|:222|:8082|:8181' | sort
|
||||
```
|
||||
|
||||
Erwartet exakt die dokumentierten Ausnahmen aus `HOMELAB_ARCHITECTURE_MASTER_V2.md` Abschnitt 10. Andere Listener = Befund.
|
||||
|
||||
---
|
||||
|
||||
## 10. Nachhalte-Vorschlag
|
||||
|
||||
Wenn Du moechtest, halte ich diesen Audit in zwei Schritten zu Ende:
|
||||
|
||||
1. Du fuehrst Abschnitt 9 aus und pastierst die Outputs zurueck.
|
||||
2. Ich aktualisiere diesen Report mit den Live-Ergebnissen, ergaenze die Ampel und schliesse die offenen 🟡/🟠 Punkte oder benenne sie als echte Restliste.
|
||||
|
||||
Bis dahin gilt der Stand dieses Reports als Repo-Audit, nicht als Endstufen-Zertifikat.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Homelab Audit Final - 2026-05-23
|
||||
|
||||
Stand: 2026-05-23 11:30 CEST. Ergebnis nach Push, Live-Messung, Doku-Sync und Repo-Hygiene.
|
||||
|
||||
| Punkt | Ampel | Beleg |
|
||||
|---|---|---|
|
||||
| P0 `cd650b1` nach Gitea pushen | gruen | Push `af231dd..cd650b1 master -> master`; `gitea` und `borg-ui` Workspaces auf `cd650b1`, beide `## master...origin/master`. |
|
||||
| P0 Live-Daten ablegen | gruen | `docs/AUDIT_2026-05-23_LIVE.md` angelegt, keine Secret-Werte dokumentiert. |
|
||||
| P1 Monitoring live / Altstaende down | gelb-gruen | `monitoring-*` Container laufen, alte `grafana`/`influxdb3-core`/`loki`/`alloy` Container sind nicht vorhanden. Grafana, Prometheus und Traefik-Route sind ok; Loki nimmt Daten an, aber `/ready` liefert 503. |
|
||||
| P1 Jellyfin/Plex Doku | gruen | `HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/SERVICE_CATALOG.md` und `docs/REPO_MAP.md` ergaenzt; Plex ist als Repo-Compose-Stack dokumentiert, nicht mehr als nicht migrierter Dockerman-Sonderfall. |
|
||||
| P2 Borg-Frische | gruen | Borg-UI DB: letzter Backup-Job completed am 2026-05-23 02:30 UTC; 15 aktuelle Dump-/Archive-Artefakte von 04:00/04:01 CEST und damit juenger als 24 h. |
|
||||
| P3 Repo-Hygiene | gruen | `.serena/` in `.gitignore`; leere Verzeichnisse entfernt; `ops/windows-reinstall/*.ps1` bewusst ins Repo aufgenommen. |
|
||||
| Policy-Check | gruen | `ops/policy-checks/check_repo.ps1`: 0 Critical, dokumentierte Warnings zu Plex Host-Netz, InfluxDB/Grafana `user: "0"` und bekannten mutable-tag-Ausnahmen. |
|
||||
|
||||
## Bewusst offen
|
||||
|
||||
- `monitoring-loki` `/ready` meldet trotz laufendem Container und aktiven Metrics-/Query-Zaehlungen `503`. Da keine Altcontainer mehr laufen und Loki Logs annimmt, wurde kein blinder Reparaturversuch gestartet. Naechster sauberer Schritt waere ein eigener Loki-Readiness-Check gegen Konfiguration, Ring/Single-Binary-Modus und Grafana-Datasource, nicht Teil dieses Endstufen-Commits.
|
||||
- Host-Workspace `monitoring` enthaelt untracked `monitoring/prometheus/alerts.yml.bak-20260520-incident`. Nicht angefasst, weil es Host-/Komodo-Workspace-Drift ist und nicht im lokalen Repo liegt.
|
||||
|
||||
## Schlussbewertung
|
||||
|
||||
Das Homelab ist fuer die Audit-Restliste in der Endstufe. Es gibt keine kritischen Repo- oder GitOps-Befunde. Einzige gelbe Restkante ist Loki-Readiness als separater Monitoring-Hardening-Punkt; der produktive Stack ist deployed, alte Altstaende sind down, Backups und Dumps sind frisch.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Homelab Audit Live-Daten - 2026-05-23
|
||||
|
||||
Stand: 2026-05-23 11:27 CEST. Quelle: lokaler Windows-Clone und SSH auf `Kallilabcore`. Secret-Werte wurden nicht ausgelesen oder redaktiert; dokumentiert sind nur Status, Dateinamen, Modi, Env-Key-Namen und nicht geheime Bool-/Host-Werte.
|
||||
|
||||
## 9.1 Windows-Host / Git
|
||||
|
||||
- `git status --short` nach dem initialen Push: keine tracked Modifikationen, untracked waren `.serena/`, `docs/AUDIT_2026-05-23.md`, `docs/CODEX_ENDSTUFE_PROMPT_2026-05-23.md` und drei `ops/windows-reinstall/*.ps1`.
|
||||
- `cd650b1` wurde nach `origin/master` gepusht: `af231dd..cd650b1 master -> master`.
|
||||
|
||||
## 9.2 Gitea online
|
||||
|
||||
- `curl -sI https://git.kaleschke.info/`: `HTTP/2 200`.
|
||||
- `docker exec gitea gitea --version`: `1.25.4`.
|
||||
- Signup-Smoke: `/user/sign_up` meldet Registration disabled.
|
||||
|
||||
## 9.3 Komodo / Workspace-Reaktion
|
||||
|
||||
| Stack | Workspace HEAD | Status | Live-Beleg |
|
||||
|---|---:|---|---|
|
||||
| `gitea` | `cd650b1` | `## master...origin/master` | Container neu gestartet, Env-Keys aktiv |
|
||||
| `borg-ui` | `cd650b1` | `## master...origin/master` | Container healthy, `/mnt/user/services -> /local/services` gemountet |
|
||||
| `monitoring` | `cd650b1` | `## master...origin/master`, untracked Host-Backup `monitoring/prometheus/alerts.yml.bak-20260520-incident` | Stack laeuft seit 4 Tagen |
|
||||
|
||||
Gitea Live-Env ohne Secrets:
|
||||
|
||||
```text
|
||||
GITEA__service__DISABLE_REGISTRATION=true
|
||||
GITEA__openid__ENABLE_OPENID_SIGNIN=false
|
||||
GITEA__openid__ENABLE_OPENID_SIGNUP=false
|
||||
GITEA__webhook__ALLOWED_HOST_LIST=komodo-core,localhost,127.0.0.1,192.168.178.0/24
|
||||
```
|
||||
|
||||
## 9.4 Borg-Lauf-Frische und Dump-Coverage
|
||||
|
||||
- Borg UI DB: Repository `appdata-critical`, `last_backup=2026-05-23 02:30:12 UTC`, `archive_count=30`, letzter Job `completed`, `nfiles=100056`.
|
||||
- Schedule: `Taegliche Sicherung` enabled, letzter Lauf `2026-05-23 02:30:11 UTC`, naechster Lauf `2026-05-24 02:30:00 UTC`.
|
||||
- Hinweis: `docker exec borg-ui borg list --short` funktioniert ohne Repository-Parameter/Env nicht (`Invalid location format: ""`). Der Borg-UI-Status wurde deshalb ueber die lokale Borg-UI-Datenbank ohne Secret-Spalten ausgewertet.
|
||||
|
||||
Frische Artefakte in `/mnt/user/backups/borg/dumps/latest`:
|
||||
|
||||
```text
|
||||
2026-05-23 04:00 postgresql17-globals.sql
|
||||
2026-05-23 04:00 postgresql17-mailarchiver.dump
|
||||
2026-05-23 04:00 postgresql17-paperless.dump
|
||||
2026-05-23 04:01 postgresql17-authelia.dump
|
||||
2026-05-23 04:01 mealie.dump
|
||||
2026-05-23 04:01 gitea.sqlite.dump
|
||||
2026-05-23 04:01 immich.dump
|
||||
2026-05-23 04:01 nextcloud.dump
|
||||
2026-05-23 04:01 uptime-kuma.sqlite.dump
|
||||
2026-05-23 04:01 vaultwarden.sqlite.dump
|
||||
2026-05-23 04:01 speedtest-tracker.sqlite.dump
|
||||
2026-05-23 04:01 filebrowser.bolt.dump
|
||||
2026-05-23 04:01 borg-ui.sqlite
|
||||
2026-05-23 04:01 grafana.sqlite
|
||||
2026-05-23 04:01 komodo-mongo.archive.gz
|
||||
```
|
||||
|
||||
Bewertung: 15 aktuelle Dump-/Archive-Artefakte sind juenger als 24 h. Aeltere nackte `.sqlite`-Dateien vom 2026-05-16 liegen noch im Verzeichnis, sind aber Legacy-Kopien ohne `.dump`-Suffix und nicht Teil der aktuellen Dump-Serie.
|
||||
|
||||
## 9.5 Monitoring-Stack
|
||||
|
||||
- Aktive Container: `monitoring-grafana`, `monitoring-promtail`, `monitoring-prometheus`, `monitoring-cadvisor`, `monitoring-influxdb3-core`, `monitoring-loki`, `monitoring-blackbox-exporter`, `monitoring-alertmanager-ntfy-bridge`, `monitoring-alertmanager`, `monitoring-node-exporter`.
|
||||
- Alte Altcontainer `grafana`, `influxdb3-core`, `loki`, `alloy`: nicht vorhanden in `docker ps -a`.
|
||||
- Secret-Dateien vorhanden und mode `600`: `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json`.
|
||||
- `https://monitoring.kaleschke.info/`: `HTTP/2 302` zu Authelia, wie erwartet.
|
||||
- Host-Listener fuer Monitoring: nur `127.0.0.1:8181`; keine Host-Listener fuer `:9090` oder `:3100`.
|
||||
- Prometheus readiness: `Prometheus Server is Ready.`
|
||||
- Grafana health: `database=ok`, Version `12.4.3`.
|
||||
- Loki: Container laeuft und API/metrics liefert `loki_build_info`; `/ready` liefert aktuell `503 Service Unavailable`, waehrend Query-/Metrics-Endpunkte 200-Zaehler zeigen. Kein Reparaturversuch gestartet, weil der produktive Logpfad nachweislich Daten annimmt und die Stop-Regel keine blinden Eingriffe erlaubt.
|
||||
|
||||
## 9.6 GitOps Spot-Check Gitea
|
||||
|
||||
- `/mnt/user/services/stacks/gitea`: `cd650b1`, `## master...origin/master`.
|
||||
- Docker-Image: `docker.gitea.com/gitea:1.25.4`.
|
||||
- Live-ENV spiegelt `cd650b1` fuer Registrierung, OpenID und Webhook-Allowlist.
|
||||
|
||||
## 9.7 Host-Listener
|
||||
|
||||
Dokumentierte Listener gefunden:
|
||||
|
||||
- `:80`, `:443` Traefik
|
||||
- `:53` AdGuard DNS
|
||||
- `:222` Gitea SSH
|
||||
- `:8082` AdGuard Admin
|
||||
- `127.0.0.1:8181` Monitoring InfluxDB
|
||||
|
||||
Zusaetzlich sichtbar: mehrere `wsdd2` Listener auf `:5355` je Interface. Das ist Host-/Unraid-Service-Discovery, kein Compose-Webdienst und kein GitOps-Stack-Port.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Codex-Prompt: KalliLab Endstufe
|
||||
|
||||
Du hast Vollzugriff auf `G:\Gitea_Clone\homelab-infra`, Gitea-Push, Komodo, und SSH auf Unraid `Kallilabcore`.
|
||||
|
||||
## Lies zuerst
|
||||
1. `CLAUDE.md`
|
||||
2. `docs/AUDIT_2026-05-23.md` — dort steht die komplette Restliste
|
||||
|
||||
## Auftrag
|
||||
Den Audit von oben verifizieren und die offenen Punkte abarbeiten, bis das Homelab in der Endstufe ist. Reihenfolge:
|
||||
|
||||
1. **P0** — Lokalen Commit `cd650b1` nach Gitea pushen, danach Komodo-Reaktion fuer `gitea` und `borg-ui` pruefen.
|
||||
2. **P0** — Live-Daten aus Audit-Abschnitt 9 messen und in `docs/AUDIT_2026-05-23_LIVE.md` ablegen (Secrets redacten).
|
||||
3. **P1** — Monitoring-Stack (`monitoring/`) live deployen, alte `ops/grafana-influxdb` und `ops/loki` `down` (nicht loeschen).
|
||||
4. **P1** — Jellyfin und Plex in `HOMELAB_ARCHITECTURE_MASTER_V2.md`, `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md` nachtragen. Plex-Eintrag "nicht als Repo-Stack enthalten" korrigieren.
|
||||
5. **P2** — Borg-Lauf-Frische pruefen, ggf. neuen Lauf ausloesen, alle 14 Dump-Artefakte juenger als 24 h.
|
||||
6. **P3** — Repo-Hygiene: 8 leere Verzeichnisse weg, `.serena/` in `.gitignore`, Entscheidung zu `ops/windows-reinstall/*.ps1`.
|
||||
|
||||
## Regeln (aus CLAUDE.md, nicht verhandelbar)
|
||||
- Secrets nie im Klartext ausgeben.
|
||||
- Keine Aenderungen direkt in Komodo, nur ueber Git → Push → Komodo.
|
||||
- Kein `push --force`, kein blindes Loeschen von `/mnt/user/{appdata,documents,photos,services,backups}`.
|
||||
- Working-Tree-Status nur aus `git status --short` ableiten, nie aus `git diff` ueber Linux-Mount.
|
||||
- Traefik dynamic config wird nicht von Komodo deployed — Aenderungen dort manuell auf `/mnt/user/appdata/traefik/dynamic/` syncen.
|
||||
- Nicht anfassen: Hermes, Disk1 NTFS Phase 2, Komodo-Auth, Grafana/InfluxDB `user: "0"`, Image-Pinning ddns/glances/scrutiny.
|
||||
- Wenn zwei Reparaturversuche scheitern: stoppen, Drift-Runbook Pflichtmatrix, Operator fragen.
|
||||
|
||||
## Arbeitsmodus pro Block
|
||||
Lesen → minimal aendern → `ops/policy-checks/check_repo.ps1` lokal → Commit → Push → Komodo-Reaktion + Smoke-Test → eine Zeile in `docs/MIGRATION_LOG.md`.
|
||||
|
||||
## Fertig
|
||||
Wenn alles abgearbeitet ist (oder ein Punkt bewusst offen bleibt): `docs/AUDIT_2026-05-23_FINAL.md` schreiben mit Ampel + konkretem Beleg pro Punkt, committen, pushen, kurz an mich melden.
|
||||
@@ -16,6 +16,13 @@ Dieses Dokument ist nur noch ein historischer Verlauf. Der aktuelle operative Ab
|
||||
|
||||
## Historische Meilensteine
|
||||
|
||||
### 2026-05-23 - Audit-Endstufe verifiziert
|
||||
|
||||
- Lokalen Hardening-Commit `cd650b1` nach Gitea gepusht; Komodo-Workspaces fuer `gitea`, `borg-ui` und `monitoring` stehen auf `cd650b1`.
|
||||
- Live-Audit in `docs/AUDIT_2026-05-23_LIVE.md` dokumentiert: Gitea-Registration geschlossen, Borg-Dumps frisch, Monitoring-Stack aktiv, alte Grafana/Loki-Altcontainer nicht mehr vorhanden.
|
||||
- Jellyfin und Plex in Architektur, Service-Katalog und Repo-Map nachgetragen; Plex ist jetzt als Repo-Compose-Stack mit dokumentierter Host-Netz-Ausnahme gefuehrt.
|
||||
- Repo-Hygiene abgeschlossen: `.serena/` ignoriert, leere Verzeichnisse entfernt, Windows-Reinstall-Helfer unter `ops/windows-reinstall/` bewusst versioniert.
|
||||
|
||||
### 2026-05-20 - Gitea 5xx-Bursts untersucht und Signup geschlossen
|
||||
|
||||
- Live-Befund zu `HomelabTraefik5xx`: kurze externe `POST /`-Bursts auf `gitea@docker` von `103.153.183.69` und `103.153.183.73`, jeweils HTTP 500 in unter 10 ms; normale Gitea-Checks und Git-Reads liefen parallel mit HTTP 200.
|
||||
|
||||
+8
-3
@@ -1,6 +1,6 @@
|
||||
# Repository Map
|
||||
|
||||
Stand: 2026-05-04
|
||||
Stand: 2026-05-23
|
||||
|
||||
Diese Datei ist eine technische Landkarte des Repositories. Sie wurde aus Markdown-Dokumenten, `docker-compose.yml`-Dateien, Env-Beispielen, Traefik-Dynamic-Configs, Komodo/Periphery-Dateien und Skripten abgeleitet. Sie beschreibt den Repo-Sollzustand, nicht zwingend den Live-Zustand auf dem Host.
|
||||
|
||||
@@ -75,6 +75,7 @@ Secret-Werte werden hier nicht dokumentiert. Aufgefuehrt werden nur Variablennam
|
||||
| BentoPDF | `apps/bentopdf/docker-compose.yml` | `bentopdf` -> `bentopdfteam/bentopdf:2.8.4` | `pdf.kaleschke.info` | `frontend_net` | keine | Traefik + Authelia; COOP/COEP Middleware |
|
||||
| Homepage | `apps/homepage/docker-compose.yml` | `homepage` -> `ghcr.io/gethomepage/homepage:v1.12.3@sha256:...` | `home.kaleschke.info` | `frontend_net` | keine | Docker-Socket read-only fuer Widgets; viele `HOMEPAGE_VAR_*` Env-Keys |
|
||||
| Immich | `apps/immich/docker-compose.yml` | `immich-server`, `immich-machine-learning`, `database`, `redis` | `immich.kaleschke.info` | `frontend_net`, `immich_default` | keine | `immich-server` depends on `database`, `redis` |
|
||||
| Jellyfin | `apps/jellyfin/docker-compose.yml` | `jellyfin` -> `jellyfin/jellyfin:10.11.8@sha256:...` | `jellyfin.kaleschke.info` | `frontend_net` | keine | native Jellyfin-Auth; `/mnt/user/media` und `/mnt/user/photos` read-only |
|
||||
| Mail Archiver | `apps/mail-archiver/docker-compose.yml` | `mail-archiver` -> `s1t5/mailarchiver@sha256:...` | `mail.kaleschke.info` | `frontend_net`, `backend_net` | keine | shared PostgreSQL via env connection string; Internet fuer IMAP |
|
||||
| Mealie | `apps/mealie/docker-compose.yml` | `mealie`, `mealie-postgres` | `mealie.kaleschke.info` | `frontend_net`, `mealie_internal` | keine | eigene PostgreSQL im internen Netz |
|
||||
| Nextcloud | `apps/nextcloud/docker-compose.yml` | `nextcloud`, `nextcloud-postgres`, `nextcloud-redis` | `cloud.kaleschke.info` | `frontend_net`, `nextcloud_internal` | keine | native Nextcloud-Auth; eigene DB und Redis |
|
||||
@@ -99,6 +100,7 @@ Secret-Werte werden hier nicht dokumentiert. Aufgefuehrt werden nur Variablennam
|
||||
| Stack | Compose | Services / Images | Hosts | Networks | Ports / Mode | Abhaengigkeiten |
|
||||
|---|---|---|---|---|---|---|
|
||||
| AdGuard Home | `host-services/Adguard/docker-compose.yml` | `adguard` -> `adguard/adguardhome:v0.107.52` | keine Traefik-Route | `dns_net`, `frontend_net` | `53/tcp`, `53/udp`, `8082:80/tcp` | Unbound in `dns_net`; direkte Ports sind dokumentierte Ausnahme |
|
||||
| Plex | `host-services/plex/docker-compose.yml` | `plex` -> `plexinc/pms-docker:1.43.1.10611-1e34174b1@sha256:...` | keine Traefik-Route | `network_mode: host` | host network | Medienserver; Host-Netz bleibt fuer Discovery / Plex GDM dokumentierte Ausnahme |
|
||||
| Tailscale | `host-services/tailscale/docker-compose.yml` | `Tailscale-Docker` -> `tailscale/tailscale:stable@sha256:...` | keine | `network_mode: host` | host network | VPN/Remote-Zugang |
|
||||
|
||||
### Operations
|
||||
@@ -141,6 +143,7 @@ Secret-Werte werden hier nicht dokumentiert. Aufgefuehrt werden nur Variablennam
|
||||
| `hermes.kaleschke.info` | Hermes Dashboard | Traefik + Authelia |
|
||||
| `home.kaleschke.info` | Homepage | Traefik + Authelia; faellt in Authelia unter die 1FA-Wildcard-Regel |
|
||||
| `immich.kaleschke.info` | Immich | Traefik, native App-Auth |
|
||||
| `jellyfin.kaleschke.info` | Jellyfin | Traefik, native App-Auth |
|
||||
| `komodo.kaleschke.info` | Komodo | Traefik, native Komodo-Auth; keine pauschale ForwardAuth |
|
||||
| `mail.kaleschke.info` | Mail Archiver | Traefik + Authelia + App-Auth |
|
||||
| `mealie.kaleschke.info` | Mealie | Traefik |
|
||||
@@ -172,7 +175,7 @@ Secret-Werte werden hier nicht dokumentiert. Aufgefuehrt werden nur Variablennam
|
||||
| `glance_socket_net` | Compose-intern, `internal: true` | Glance und `glance-docker-socket-proxy`; keine Traefik-Anbindung |
|
||||
| `komodo_net` | Compose-intern, `internal: true` | Komodo Core, Mongo, Periphery |
|
||||
| `hermes_net` | Compose-intern bridge | Hermes Gateway/Dashboard |
|
||||
| `host` | Host-Netz | Tailscale; Plex historisch ausserhalb Repo |
|
||||
| `host` | Host-Netz | Tailscale; Plex als Repo-Compose-Stack unter `host-services/plex/` |
|
||||
|
||||
## Volumes und Datenpfade
|
||||
|
||||
@@ -189,6 +192,8 @@ Secret-Werte werden hier nicht dokumentiert. Aufgefuehrt werden nur Variablennam
|
||||
| Mealie | `/mnt/user/appdata/mealie/data`, `/mnt/user/appdata/mealie/postgres` |
|
||||
| Mail Archiver | `/mnt/user/appdata/mailarchiver/data-protection-keys` |
|
||||
| Nextcloud | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data`, `/mnt/user/appdata/nextcloud/postgres`, `/mnt/user/appdata/nextcloud/redis` |
|
||||
| Jellyfin | `/mnt/user/appdata/jellyfin/config`, `/mnt/user/appdata/jellyfin/cache`, `/mnt/user/media`, `/mnt/user/photos` |
|
||||
| Plex | `/mnt/user/appdata/plex/config`, `/mnt/user/appdata/plex/transcode`, `/mnt/user/media`, `/mnt/user/photos` |
|
||||
| Homepage | `/mnt/user/appdata/homepage`, `/mnt/user/appdata/homepage/images`, Docker socket read-only |
|
||||
| ntfy | `/mnt/user/appdata/ntfy` |
|
||||
| Paperless-GPT | `/mnt/user/appdata/paperless-gpt/data`, `/mnt/user/appdata/paperless-gpt/prompts` |
|
||||
@@ -252,5 +257,5 @@ Das Skript liest Secret-Dateien auf dem Host und schreibt Dump-Artefakte. Bei An
|
||||
- `tailscale` nutzt Host-Netz, `NET_ADMIN`, `NET_RAW` und `/dev/net/tun` als dokumentierte VPN-Ausnahme.
|
||||
- `grafana`, `influxdb3-core` und `monitoring-influxdb3-core` laufen aktuell als `user: "0"`; UID/GID-Hardening nur als eigener Sprint.
|
||||
- Leere `.keep`-Platzhalter wurden entfernt; neue Verzeichnisse sollen erst mit konkretem Inhalt ins Repo.
|
||||
- `Plex-Media-Server` ist als historischer Host-Sonderfall dokumentiert, aber nicht als Repo-Compose-Stack enthalten.
|
||||
- `plex` ist als Repo-Compose-Stack unter `host-services/plex/` enthalten; `network_mode: host` bleibt die dokumentierte Discovery-Ausnahme.
|
||||
- BentoPDF kann je nach Live-Stand vorbereitet statt produktiv sein; Hermes Dashboard ist produktiv unter `hermes.kaleschke.info`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Service Catalog
|
||||
|
||||
Stand: 2026-05-04
|
||||
Stand: 2026-05-23
|
||||
|
||||
Dieser Katalog beschreibt produktive und repo-vorbereitete Dienste aus Sicht von Betrieb, Restore und KI-Kontext. Er basiert auf dem Repo-Sollzustand. Vor produktiven Eingriffen immer den Live-Zustand in Komodo/Docker pruefen.
|
||||
|
||||
@@ -47,6 +47,8 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
|
||||
| `nextcloud` | Datei-/Cloud-Dienst | `apps/nextcloud/docker-compose.yml` | `https://cloud.kaleschke.info` | eigene PostgreSQL, eigene Redis, Traefik | `/mnt/user/appdata/nextcloud/html`, `/mnt/user/documents/nextcloud-data` | Tier 2, `nextcloud.dump` + Share | ja | native App-Auth ohne zentrale ForwardAuth; WebDAV/CardDAV beachten |
|
||||
| `nextcloud-postgres` | Nextcloud-Datenbank | `apps/nextcloud/docker-compose.yml` | intern | `nextcloud_internal` | `/mnt/user/appdata/nextcloud/postgres`, `nextcloud_postgres_password.txt` | `nextcloud.dump`, raw DB nicht primaerer Restore-Weg | nein | interne DB |
|
||||
| `nextcloud-redis` | Nextcloud Cache/Locking | `apps/nextcloud/docker-compose.yml` | intern | `nextcloud_internal` | `/mnt/user/appdata/nextcloud/redis` | Teil von Nextcloud-Restore | nein | interne Redis |
|
||||
| `jellyfin` | Medienserver | `apps/jellyfin/docker-compose.yml` | `https://jellyfin.kaleschke.info` | Traefik, `frontend_net` | `/mnt/user/appdata/jellyfin/config`, `/mnt/user/appdata/jellyfin/cache`, `/mnt/user/media`, `/mnt/user/photos` | Tier 2, Appdata + Medienpfade im Borg-/Share-Scope | ja | native Jellyfin-Auth; Medien- und Fotomounts read-only; keine direkten Host-Ports |
|
||||
| `plex` | Medienserver mit LAN-/Client-Discovery | `host-services/plex/docker-compose.yml` | Plex native / LAN / Remote je Plex-Konfiguration | Host-Netz | `/mnt/user/appdata/plex/config`, `/mnt/user/appdata/plex/transcode`, `/mnt/user/media`, `/mnt/user/photos` | Tier 2, Appdata + Medienpfade im Borg-/Share-Scope | nein | Repo-Compose-Stack; `network_mode: host` bleibt dokumentierte Discovery-Ausnahme, kein Traefik-Stack |
|
||||
| `ntfy` | Push-Benachrichtigungen | `apps/ntfy/docker-compose.yml` | `https://ntfy.kaleschke.info` | Traefik, upstream mobile push | `/mnt/user/appdata/ntfy` | Tier 2 | ja | `NTFY_BEHIND_PROXY=true`; Problem-Alerts gehen gebuendelt an `homelab-alerts`, optionale Erfolgsmeldungen an `homelab-info` |
|
||||
| `bentopdf` | PDF-Tooling / Ersatz fuer Stirling-PDF | `apps/bentopdf/docker-compose.yml` | `https://pdf.kaleschke.info` | Traefik + Authelia | keine kritische Persistenz im Compose | Tier 3, rebuildbar | ja + Authelia | COOP/COEP per Middleware; fachliche Abnahme/Live-Status pruefen |
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Windows Reinstall Helpers
|
||||
|
||||
Diese Skripte sind bewusst versionierte Operator-Hilfen fuer den Windows-Neuaufsetzen-/Dual-Boot-Kontext vom Mai 2026.
|
||||
|
||||
- `backup-delta-after-2026-05-07.ps1` kopiert nach einem definierten Cutoff lokale Nutzdaten in ein Backup-Ziel.
|
||||
- `repair-disk0-boot-to-new-windows.ps1` repariert EFI/Bootdateien fuer das neue Windows auf der Intel-SSD und verlangt Adminrechte.
|
||||
- `cleanup-dualboot-bcd.ps1` bereinigt BCD-Bootmenueeintraege und verlangt eine explizite Textbestaetigung.
|
||||
|
||||
Die Skripte enthalten keine Secrets, arbeiten aber mit lokalen Windows-Datentraegern und duerfen nur interaktiv und mit vorheriger Sichtpruefung ausgefuehrt werden.
|
||||
@@ -0,0 +1,118 @@
|
||||
param(
|
||||
[datetime]$Cutoff = "2026-05-07T15:30:00",
|
||||
[string]$BackupRoot = "H:\Windows-Neuaufsetzen-Backup",
|
||||
[string]$UserProfilePath = "C:\Users\michi"
|
||||
)
|
||||
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Invoke-RobocopyDelta {
|
||||
param(
|
||||
[string]$Source,
|
||||
[string]$Destination,
|
||||
[string]$LogName
|
||||
)
|
||||
|
||||
if (-not (Test-Path $Source)) {
|
||||
Write-Host "SKIP missing source: $Source"
|
||||
return
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $Destination | Out-Null
|
||||
$LogPath = Join-Path $DeltaLogDir $LogName
|
||||
|
||||
Write-Host "DELTA COPY $Source"
|
||||
Write-Host " -> $Destination"
|
||||
|
||||
robocopy $Source $Destination /E /COPY:DAT /DCOPY:DAT /R:2 /W:2 /XJ /MAXAGE:$CutoffString /TEE /LOG:$LogPath
|
||||
$ExitCode = $LASTEXITCODE
|
||||
if ($ExitCode -gt 7) {
|
||||
throw "Robocopy failed with exit code $ExitCode for source: $Source"
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Test-Path $BackupRoot)) {
|
||||
throw "BackupRoot does not exist: $BackupRoot"
|
||||
}
|
||||
|
||||
if (-not (Test-Path $UserProfilePath)) {
|
||||
throw "UserProfilePath does not exist: $UserProfilePath"
|
||||
}
|
||||
|
||||
$DeltaRoot = Join-Path $BackupRoot "_Delta_2026-05-19"
|
||||
$DeltaLogDir = Join-Path $DeltaRoot "00_Logs"
|
||||
New-Item -ItemType Directory -Force -Path $DeltaLogDir | Out-Null
|
||||
|
||||
$CutoffString = $Cutoff.ToString("yyyyMMdd")
|
||||
|
||||
$Manifest = [ordered]@{
|
||||
CreatedAt = (Get-Date).ToString("s")
|
||||
Cutoff = $Cutoff.ToString("s")
|
||||
CutoffNote = "Robocopy /MAXAGE uses date granularity, so files changed on or after the cutoff day are included."
|
||||
RunningSystemDrive = $env:SystemDrive
|
||||
RunningWinDir = $env:windir
|
||||
BackupRoot = $BackupRoot
|
||||
DeltaRoot = $DeltaRoot
|
||||
}
|
||||
|
||||
$Manifest.GetEnumerator() |
|
||||
ForEach-Object { "$($_.Key)=$($_.Value)" } |
|
||||
Out-File (Join-Path $DeltaRoot "delta_manifest.txt") -Encoding UTF8
|
||||
|
||||
$Jobs = @(
|
||||
@{ Source = Join-Path $UserProfilePath "Desktop"; Destination = Join-Path $DeltaRoot "01_Desktop"; Log = "delta_current_desktop.log" },
|
||||
@{ Source = Join-Path $UserProfilePath "Documents"; Destination = Join-Path $DeltaRoot "02_Dokumente"; Log = "delta_current_documents.log" },
|
||||
@{ Source = Join-Path $UserProfilePath "Pictures"; Destination = Join-Path $DeltaRoot "03_Bilder"; Log = "delta_current_pictures.log" },
|
||||
@{ Source = Join-Path $UserProfilePath "Videos"; Destination = Join-Path $DeltaRoot "04_Videos"; Log = "delta_current_videos.log" },
|
||||
@{ Source = Join-Path $UserProfilePath "Downloads"; Destination = Join-Path $DeltaRoot "05_Downloads"; Log = "delta_current_downloads.log" },
|
||||
@{ Source = Join-Path $UserProfilePath ".ssh"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\ssh"; Log = "delta_current_ssh.log" },
|
||||
@{ Source = Join-Path $UserProfilePath "AppData\Local\Subsembly"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\Subsembly_Local"; Log = "delta_subsembly_local.log" },
|
||||
@{ Source = Join-Path $UserProfilePath "AppData\Local\Buhl"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\Buhl_Local"; Log = "delta_buhl_local.log" },
|
||||
@{ Source = Join-Path $UserProfilePath "AppData\Local\Buhl Data Service GmbH"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\Buhl_Data_Service_Local"; Log = "delta_buhl_data_service_local.log" },
|
||||
@{ Source = "C:\ProgramData\Buhl Data Service GmbH"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\Buhl_Data_Service_ProgramData"; Log = "delta_buhl_data_service_programdata.log" },
|
||||
@{ Source = "G:\Gitea_Clone"; Destination = Join-Path $DeltaRoot "06_Projekte\Gitea_Clone"; Log = "delta_g_gitea_clone.log" },
|
||||
@{ Source = "G:\open-webui"; Destination = Join-Path $DeltaRoot "09_Programme_Settings_Lizenzen\open-webui"; Log = "delta_g_open_webui.log" },
|
||||
@{ Source = "G:\Treiber"; Destination = Join-Path $DeltaRoot "13_Treiber_Windows\G_Treiber"; Log = "delta_g_treiber.log" },
|
||||
@{ Source = "F:\BMW Leasing"; Destination = Join-Path $DeltaRoot "07_Banking_Finanzen\BMW Leasing"; Log = "delta_f_bmw_leasing.log" },
|
||||
@{ Source = "F:\Marina Handy 2025"; Destination = Join-Path $DeltaRoot "03_Bilder\Marina Handy 2025"; Log = "delta_f_marina_handy_2025.log" }
|
||||
)
|
||||
|
||||
foreach ($Job in $Jobs) {
|
||||
Invoke-RobocopyDelta -Source $Job.Source -Destination $Job.Destination -LogName $Job.Log
|
||||
}
|
||||
|
||||
$ExplicitBankingDir = Join-Path $DeltaRoot "07_Banking_Finanzen\Banking4_Datentresor_explizit"
|
||||
New-Item -ItemType Directory -Force -Path $ExplicitBankingDir | Out-Null
|
||||
|
||||
$BankingFiles = @(
|
||||
(Join-Path $UserProfilePath "Documents\Mein Datentresor.sub"),
|
||||
(Join-Path $UserProfilePath "Documents\.Mein Datentresor.sub.att")
|
||||
)
|
||||
|
||||
foreach ($File in $BankingFiles) {
|
||||
if (Test-Path $File) {
|
||||
Copy-Item -LiteralPath $File -Destination (Join-Path $ExplicitBankingDir (Split-Path $File -Leaf)) -Force
|
||||
}
|
||||
}
|
||||
|
||||
$SummaryRoots = Get-ChildItem $DeltaRoot -Directory -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne "00_Logs" }
|
||||
$Summary = foreach ($Root in $SummaryRoots) {
|
||||
$Files = @(Get-ChildItem $Root.FullName -Recurse -Force -File -ErrorAction SilentlyContinue)
|
||||
$Measure = $Files | Measure-Object Length -Sum
|
||||
[pscustomobject]@{
|
||||
Path = $Root.FullName
|
||||
Files = $Files.Count
|
||||
SizeGB = [math]::Round(($Measure.Sum / 1GB), 4)
|
||||
Newest = ($Files | Sort-Object LastWriteTime -Descending | Select-Object -First 1 -ExpandProperty LastWriteTime)
|
||||
}
|
||||
}
|
||||
|
||||
$Summary | Export-Csv (Join-Path $DeltaLogDir "delta_summary.csv") -NoTypeInformation -Encoding UTF8
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Delta backup finished:"
|
||||
Write-Host " $DeltaRoot"
|
||||
Write-Host ""
|
||||
Write-Host "Summary:"
|
||||
$Summary | Format-Table -AutoSize
|
||||
@@ -0,0 +1,141 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$BackupDir = "H:\Windows-Neuaufsetzen-Backup\12_Exportierte_Listen"
|
||||
$BeforeFile = Join-Path $BackupDir "bcdedit_enum_before_dualboot_cleanup.txt"
|
||||
$AfterFile = Join-Path $BackupDir "bcdedit_enum_after_dualboot_cleanup.txt"
|
||||
|
||||
function Assert-Admin {
|
||||
$Identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$Principal = [Security.Principal.WindowsPrincipal]::new($Identity)
|
||||
if (-not $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
throw "Dieses Skript muss in PowerShell als Administrator ausgefuehrt werden."
|
||||
}
|
||||
}
|
||||
|
||||
function Get-BcdOsLoaderEntries {
|
||||
$Text = & bcdedit /enum osloader /v
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "bcdedit /enum osloader /v ist fehlgeschlagen."
|
||||
}
|
||||
|
||||
$Entries = @()
|
||||
$Current = $null
|
||||
|
||||
foreach ($Line in $Text) {
|
||||
if ($Line -match "^-{5,}$") {
|
||||
if ($Current -and $Current.Identifier) {
|
||||
$Entries += [pscustomobject]$Current
|
||||
}
|
||||
$Current = @{
|
||||
Identifier = $null
|
||||
Device = $null
|
||||
OsDevice = $null
|
||||
Path = $null
|
||||
Description = $null
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (-not $Current) {
|
||||
continue
|
||||
}
|
||||
|
||||
if ($Line -match "^\s*(identifier|Bezeichner)\s+(.+)$") { $Current.Identifier = $Matches[2].Trim(); continue }
|
||||
if ($Line -match "^\s*device\s+(.+)$") { $Current.Device = $Matches[1].Trim(); continue }
|
||||
if ($Line -match "^\s*osdevice\s+(.+)$") { $Current.OsDevice = $Matches[1].Trim(); continue }
|
||||
if ($Line -match "^\s*path\s+(.+)$") { $Current.Path = $Matches[1].Trim(); continue }
|
||||
if ($Line -match "^\s*description\s+(.+)$") { $Current.Description = $Matches[1].Trim(); continue }
|
||||
}
|
||||
|
||||
if ($Current -and $Current.Identifier) {
|
||||
$Entries += [pscustomobject]$Current
|
||||
}
|
||||
|
||||
return $Entries
|
||||
}
|
||||
|
||||
Assert-Admin
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $BackupDir | Out-Null
|
||||
|
||||
& bcdedit /enum all /v | Out-File $BeforeFile -Encoding UTF8
|
||||
|
||||
$Entries = Get-BcdOsLoaderEntries
|
||||
|
||||
Write-Host "Gefundene Windows-Boot-Eintraege:"
|
||||
$Entries | Select-Object Identifier, Description, Device, OsDevice, Path | Format-Table -AutoSize
|
||||
|
||||
$NewWindows = $Entries | Where-Object {
|
||||
$_.OsDevice -eq "partition=D:" -and
|
||||
$_.Path -match "winload\.efi$" -and
|
||||
(Test-Path "D:\Windows\System32\winload.efi")
|
||||
} | Select-Object -First 1
|
||||
|
||||
$OldWindows = $Entries | Where-Object {
|
||||
$_.OsDevice -eq "partition=C:" -and
|
||||
$_.Path -match "winload\.efi$" -and
|
||||
(Test-Path "C:\Windows\System32\winload.efi")
|
||||
} | Select-Object -First 1
|
||||
|
||||
if (-not $NewWindows) {
|
||||
throw "Abbruch: Neuer Windows-Eintrag auf D:\Windows wurde nicht eindeutig gefunden."
|
||||
}
|
||||
|
||||
if (-not $OldWindows) {
|
||||
throw "Abbruch: Alter Windows-Eintrag auf C:\Windows wurde nicht eindeutig gefunden."
|
||||
}
|
||||
|
||||
$KeepIds = @($NewWindows.Identifier, $OldWindows.Identifier)
|
||||
$DeleteEntries = $Entries | Where-Object { $KeepIds -notcontains $_.Identifier }
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Bleibt erhalten:"
|
||||
Write-Host " NEU: $($NewWindows.Identifier) -> $($NewWindows.OsDevice) -> D:\Windows"
|
||||
Write-Host " ALT: $($OldWindows.Identifier) -> $($OldWindows.OsDevice) -> C:\Windows"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Wird aus dem Bootmenue entfernt:"
|
||||
if ($DeleteEntries) {
|
||||
$DeleteEntries | Select-Object Identifier, Description, Device, OsDevice, Path | Format-Table -AutoSize
|
||||
} else {
|
||||
Write-Host " Keine ueberfluessigen Eintraege gefunden."
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Es werden nur Bootmenue-Eintraege geloescht, keine Partitionen und keine Windows-Ordner."
|
||||
$Confirmation = Read-Host "Tippe exakt BOOTCLEAN um fortzufahren"
|
||||
if ($Confirmation -ne "BOOTCLEAN") {
|
||||
throw "Abbruch: Bestaetigung wurde nicht eingegeben."
|
||||
}
|
||||
|
||||
& bcdedit /set $NewWindows.Identifier description "Windows 11 Neu"
|
||||
if ($LASTEXITCODE -ne 0) { throw "Konnte neuen Windows-Eintrag nicht umbenennen." }
|
||||
|
||||
& bcdedit /set $OldWindows.Identifier description "Windows 11 Alt"
|
||||
if ($LASTEXITCODE -ne 0) { throw "Konnte alten Windows-Eintrag nicht umbenennen." }
|
||||
|
||||
& bcdedit /default $NewWindows.Identifier
|
||||
if ($LASTEXITCODE -ne 0) { throw "Konnte Standard-Boot-Eintrag nicht setzen." }
|
||||
|
||||
& bcdedit /timeout 5
|
||||
if ($LASTEXITCODE -ne 0) { throw "Konnte Timeout nicht setzen." }
|
||||
|
||||
foreach ($Entry in $DeleteEntries) {
|
||||
Write-Host "Loesche Boot-Eintrag $($Entry.Identifier) ($($Entry.Description))"
|
||||
& bcdedit /delete $Entry.Identifier /f
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Konnte Boot-Eintrag $($Entry.Identifier) nicht loeschen."
|
||||
}
|
||||
}
|
||||
|
||||
& bcdedit /enum all /v | Out-File $AfterFile -Encoding UTF8
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Bootmenue bereinigt."
|
||||
Write-Host "Vorher gesichert: $BeforeFile"
|
||||
Write-Host "Nachher gesichert: $AfterFile"
|
||||
Write-Host ""
|
||||
Write-Host "Bitte neu starten. Es sollten nur noch zwei Eintraege erscheinen:"
|
||||
Write-Host " Windows 11 Neu"
|
||||
Write-Host " Windows 11 Alt"
|
||||
@@ -0,0 +1,120 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$TargetDiskNumber = 0
|
||||
$TargetWindowsDrive = "D"
|
||||
$TargetDiskFriendlyName = "INTEL SSDSC2BW180A3L"
|
||||
$TargetDiskSerialNumber = "CVCV3105053K180EGN"
|
||||
$EfiSizeMB = 260
|
||||
$EfiLabel = "SYSTEM"
|
||||
|
||||
function Assert-Admin {
|
||||
$Identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$Principal = [Security.Principal.WindowsPrincipal]::new($Identity)
|
||||
if (-not $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
throw "Dieses Skript muss in PowerShell als Administrator ausgefuehrt werden."
|
||||
}
|
||||
}
|
||||
|
||||
function Get-FreeDriveLetter {
|
||||
$Used = (Get-Volume | Where-Object DriveLetter | Select-Object -ExpandProperty DriveLetter)
|
||||
foreach ($Letter in "S","T","U","V","W","X","Y","Z") {
|
||||
if ($Used -notcontains $Letter) {
|
||||
return $Letter
|
||||
}
|
||||
}
|
||||
throw "Kein freier Laufwerksbuchstabe fuer die EFI-Partition gefunden."
|
||||
}
|
||||
|
||||
Assert-Admin
|
||||
|
||||
$Disk = Get-Disk -Number $TargetDiskNumber
|
||||
$TargetWindowsPath = "$TargetWindowsDrive`:\Windows"
|
||||
$TargetWinload = "$TargetWindowsDrive`:\Windows\System32\winload.efi"
|
||||
|
||||
Write-Host "Aktuell gestartetes Windows:"
|
||||
Write-Host " SystemDrive: $env:SystemDrive"
|
||||
Write-Host " windir: $env:windir"
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Zieldatentraeger:"
|
||||
$Disk | Select-Object Number, FriendlyName, SerialNumber, HealthStatus, OperationalStatus, @{Name="SizeGB";Expression={[math]::Round($_.Size/1GB,2)}}, PartitionStyle | Format-Table -AutoSize
|
||||
|
||||
Write-Host "Partitionen auf Datentraeger ${TargetDiskNumber}:"
|
||||
Get-Partition -DiskNumber $TargetDiskNumber | Sort-Object PartitionNumber | Select-Object DiskNumber, PartitionNumber, DriveLetter, Type, @{Name="SizeGB";Expression={[math]::Round($_.Size/1GB,3)}}, GptType | Format-Table -AutoSize
|
||||
|
||||
if ($Disk.FriendlyName -ne $TargetDiskFriendlyName) {
|
||||
throw "Abbruch: Datentraeger 0 ist nicht die erwartete Intel-SSD."
|
||||
}
|
||||
|
||||
if ($Disk.SerialNumber -ne $TargetDiskSerialNumber) {
|
||||
throw "Abbruch: Seriennummer von Datentraeger 0 passt nicht."
|
||||
}
|
||||
|
||||
if (-not (Test-Path $TargetWinload)) {
|
||||
throw "Abbruch: Ziel-Windows wurde nicht gefunden: $TargetWinload"
|
||||
}
|
||||
|
||||
if ($env:SystemDrive -eq "$TargetWindowsDrive`:") {
|
||||
throw "Abbruch: Du bist bereits im Ziel-Windows. Dieses Skript ist fuer den Zustand gedacht, in dem neues Windows als D: sichtbar ist."
|
||||
}
|
||||
|
||||
$ExistingEfiOnDisk0 = Get-Partition -DiskNumber $TargetDiskNumber | Where-Object {
|
||||
$_.GptType -eq "{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}"
|
||||
}
|
||||
|
||||
if ($ExistingEfiOnDisk0) {
|
||||
Write-Host "EFI-Systempartition auf Datentraeger 0 existiert bereits."
|
||||
$EfiPartition = $ExistingEfiOnDisk0 | Select-Object -First 1
|
||||
} else {
|
||||
Write-Host ""
|
||||
Write-Host "Auf Datentraeger 0 existiert keine EFI-Systempartition."
|
||||
Write-Host "Das Skript verkleinert $TargetWindowsDrive`: um $EfiSizeMB MB und erstellt daraus eine neue EFI-Systempartition."
|
||||
Write-Host ""
|
||||
$Confirmation = Read-Host "Tippe exakt EFI um fortzufahren"
|
||||
if ($Confirmation -ne "EFI") {
|
||||
throw "Abbruch: Bestaetigung wurde nicht eingegeben."
|
||||
}
|
||||
|
||||
$TargetPartition = Get-Partition -DiskNumber $TargetDiskNumber | Where-Object DriveLetter -eq $TargetWindowsDrive
|
||||
if (-not $TargetPartition) {
|
||||
throw "Abbruch: Windows-Partition $TargetWindowsDrive`: wurde auf Datentraeger 0 nicht gefunden."
|
||||
}
|
||||
|
||||
$Supported = Get-PartitionSupportedSize -DiskNumber $TargetDiskNumber -PartitionNumber $TargetPartition.PartitionNumber
|
||||
$NewSize = $TargetPartition.Size - ($EfiSizeMB * 1MB)
|
||||
if ($NewSize -lt $Supported.SizeMin) {
|
||||
throw "Abbruch: Partition kann nicht um $EfiSizeMB MB verkleinert werden."
|
||||
}
|
||||
|
||||
Resize-Partition -DiskNumber $TargetDiskNumber -PartitionNumber $TargetPartition.PartitionNumber -Size $NewSize
|
||||
|
||||
$EfiPartition = New-Partition -DiskNumber $TargetDiskNumber -Size ($EfiSizeMB * 1MB) -GptType "{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}"
|
||||
Format-Volume -Partition $EfiPartition -FileSystem FAT32 -NewFileSystemLabel $EfiLabel -Confirm:$false | Out-Null
|
||||
}
|
||||
|
||||
$EfiLetter = Get-FreeDriveLetter
|
||||
Set-Partition -DiskNumber $TargetDiskNumber -PartitionNumber $EfiPartition.PartitionNumber -NewDriveLetter $EfiLetter
|
||||
$EfiDrive = "$EfiLetter`:"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Schreibe Bootdateien fuer $TargetWindowsPath nach $EfiDrive ..."
|
||||
bcdboot "$TargetWindowsPath" /s $EfiDrive /f UEFI
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "bcdboot ist fehlgeschlagen."
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Setze Bootmenue-Timeout auf 3 Sekunden."
|
||||
bcdedit /timeout 3
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Aktuelle BCD-Eintraege:"
|
||||
bcdedit /enum
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Fertig. Naechster Schritt:"
|
||||
Write-Host "1. Neustarten."
|
||||
Write-Host "2. Im UEFI/BIOS Windows Boot Manager der Intel-SSD/Datentraeger 0 als erste Bootoption waehlen, falls angeboten."
|
||||
Write-Host "3. Im Bootmenue den neuen Windows-11-Eintrag starten."
|
||||
Write-Host "4. Wenn das neue Windows laeuft, sollte SystemDrive C: sein und der alte Windows-Datentraeger einen anderen Buchstaben haben."
|
||||
Reference in New Issue
Block a user