Files
homelab/MIGRATION.md

8.7 KiB
Executable File
Raw Permalink Blame History

Homelab Migration Operativer Plan

Dateistruktur

homelab/
├── 00_setup-networks.sh
├── 01_stack-backend.yml
├── 01_paperless.sql          ← manuell per stdin einspielen, nicht gemountet
├── 02_stack-dns.yml
├── 03_stack-frontend.yml
├── 04_stack-traefik.yml      ← Phase 5, noch nicht aktiv
├── .env                      ← nicht in Git!
├── .gitignore
├── secrets/
│   └── postgres_password.txt ← nicht in Git!, muss vor Phase 3 existieren
└── traefik/                  ← Phase 5 vorbereiten
    ├── traefik.yml
    └── dynamic/
        └── middlewares.yml

Phase 0 Vorbereitung (nichts migrieren, nur prüfen)

0a Zugangsdaten rotieren

Die Mail-Archiver-Credentials waren in docker inspect im Klartext sichtbar.

# Neue Passwörter in .env setzen:
# MAILARCHIVER_DB_PASSWORD, MAILARCHIVER_USERNAME, MAILARCHIVER_PASSWORD

0b Secrets anlegen

mkdir -p secrets
echo "sicheres_postgres_passwort" > secrets/postgres_password.txt
chmod 600 secrets/postgres_password.txt
# Dieses Passwort ist das POSTGRES Superuser-Passwort, nicht das paperless-Passwort!

0c .env befüllen

Alle AENDERN_*-Werte in .env durch echte Passwörter ersetzen.

KRITISCH: REDIS_PASSWORD und PAPERLESS_DB_PASSWORD müssen konsistent sein:

  • REDIS_PASSWORD → steht in .env, wird von Redis Container UND paperless-ngx verwendet
  • PAPERLESS_DB_PASSWORD → steht in .env, muss in 01_paperless.sql gespiegelt sein

0d PostgreSQL-Zustand prüfen

# Läuft postgresql17 gerade?
docker exec -it postgresql17 psql -U postgres -c "\l"
docker exec -it postgresql17 psql -U postgres -c "\du"

# Fragen die beantwortet sein müssen:
# 1. Existiert ein User "paperless" bereits?
# 2. Existiert eine DB "paperless" bereits?
# 3. Liegt mailarchiver-DB ebenfalls auf dieser Instanz?
#    (docker exec -it postgresql17 psql -U postgres -c "\l" zeigt alle DBs)

0e 01_paperless.sql vorbereiten

Passwort-Platzhalter ersetzen:

# PAPERLESS_DB_PASSWORD aus .env nehmen und hier eintragen:
sed -i 's/HIER_PAPERLESS_DB_PASSWORD_EINTRAGEN/dein_passwort/g' 01_paperless.sql

Phase 1 Infrastruktur-Netze

Dauer: ~3 Min | Kein Ausfall | Sicher jederzeit

chmod +x 00_setup-networks.sh
./00_setup-networks.sh

# ntopng entfernen
docker stop ntopng && docker rm ntopng

# Prüfen
docker network ls | grep -E "frontend_net|backend_net|dns_net"

Immich, scanopy, host-Netz-Container → nicht anfassen


Phase 2 DNS

Dauer: ~10 Min | DNS-Ausfall: ~60 Sekunden

Vorbereitung

# Aktuellen Pi-hole-Stand dokumentieren (Screenshots, Blocklists etc.)
# Router-DNS auf 1.1.1.1 setzen falls pihole dein einziger DNS ist

Migration

# 1. Alte Container stoppen
docker stop binhex-official-pihole unbound
docker rm binhex-official-pihole unbound

# 2. Unbound zuerst starten
docker compose -f 02_stack-dns.yml up -d unbound

# 3. Warten bis unbound healthy
watch -n3 'docker inspect --format "{{.State.Health.Status}}" unbound'
# Erwartung: healthy

# 4. Erst dann pihole
docker compose -f 02_stack-dns.yml up -d binhex-official-pihole

Verifikation

# pihole → unbound Verbindung
docker exec binhex-official-pihole nslookup google.com unbound
# Erwartung: Antwort kommt zurück

# DNS von außen (Router-DNS zurückstellen auf deine IP)
nslookup google.com 192.168.178.58
# Erwartung: Auflösung klappt

Phase 3 Backend (Postgres + Redis + Paperless)

Dauer: ~20 Min | paperless-Ausfall: ~3 Minuten

⚠ Backup vorhanden ✓ — trotzdem: Phase 0d zuerst abschließen!

Phase 3a DB-Zustand prüfen (nichts umbauen)

docker exec -it postgresql17 psql -U postgres -c "\l"
docker exec -it postgresql17 psql -U postgres -c "\du"

Wenn paperless-User und -DB bereits existieren → weiter zu Phase 3b, SQL überspringen.

Wenn paperless-User/DB fehlen → erst 01_paperless.sql einspielen:

# Variante B (kein Volume-Mount nötig — stdin direkt pipen):
docker exec -i postgresql17 psql -U postgres < 01_paperless.sql

# Prüfen
docker exec -it postgresql17 psql -U postgres -c "\l"
docker exec -it postgresql17 psql -U postgres -c "\du"
# Erwartung: paperless-DB und paperless-User sichtbar

Phase 3b paperless stoppen

docker stop paperless-ngx Paperless-AI
docker rm paperless-ngx Paperless-AI

Phase 3c Redis + Postgres in backend_net ziehen

# Alte Container stoppen
docker stop Redis postgresql17
docker rm Redis postgresql17

# Backend-Stack starten
docker compose -f 01_stack-backend.yml up -d

# Health abwarten — NICHT weitermachen bevor beide healthy sind!
watch -n3 'docker ps --filter "name=postgresql17" --filter "name=Redis" --format "table {{.Names}}\t{{.Status}}"'
# Erwartung: beide "(healthy)"

Phase 3d Verbindungen testen

# PostgreSQL von backend_net erreichbar?
docker run --rm --network backend_net postgres:17 \
  psql "host=postgresql17 user=postgres password=$(cat secrets/postgres_password.txt) dbname=postgres" \
  -c "SELECT version();"
# Erwartung: PostgreSQL-Version

# PostgreSQL vom Host NICHT mehr erreichbar?
nc -zv 127.0.0.1 5432
# Erwartung: Connection refused ✓

# Redis PONG?
docker run --rm --network backend_net redis:7-alpine \
  redis-cli -h Redis -a "${REDIS_PASSWORD}" ping
# Erwartung: PONG

Phase 3e Paperless starten

docker compose -f 03_stack-frontend.yml up -d paperless-ngx Paperless-AI

# Logs die ersten 60 Sekunden beobachten
docker logs -f paperless-ngx

# Worauf achten:
#   ✓ Keine "AUTH failed"-Fehler (Redis-Passwort stimmt)
#   ✓ Keine "password authentication failed for user paperless" (DB-Passwort stimmt)
#   ✓ "Migrating..." läuft durch
#   ✓ Webinterface auf http://HOST:8000 erreichbar

Phase 4 Frontend in Wellen

Pro Welle: ~5 Min | pro Container: ~15 Sek Ausfall

Welle A unkritisch

for c in homarr homepage Dozzle dashdot theme-park; do
  docker stop $c && docker rm $c && echo "✓ $c entfernt"
done
docker compose -f 03_stack-frontend.yml up -d homarr homepage Dozzle dashdot theme-park
docker ps --filter "name=homarr" --filter "name=homepage" --filter "name=Dozzle"

Welle B mittelkritisch

for c in UptimeKuma scrutiny code-server; do
  docker stop $c && docker rm $c && echo "✓ $c entfernt"
done
docker compose -f 03_stack-frontend.yml up -d UptimeKuma scrutiny code-server

Welle C sensibel (einzeln)

# PortainerCE
docker stop PortainerCE && docker rm PortainerCE
docker compose -f 03_stack-frontend.yml up -d PortainerCE

# vaultwarden — danach Tailscale-Zugang sofort testen!
docker stop vaultwarden && docker rm vaultwarden
docker compose -f 03_stack-frontend.yml up -d vaultwarden
# Test: https://kallilabcore.taild9fcf2.ts.net:4743/admin erreichbar?

# mail-archiver — danach Login und Sync prüfen
docker stop mail-archiver && docker rm mail-archiver
docker compose -f 03_stack-frontend.yml up -d mail-archiver
docker logs -f mail-archiver   # auf DB-Verbindungsfehler achten

# Stash — separat je nach Nutzung
docker stop Stash && docker rm Stash
docker compose -f 03_stack-frontend.yml up -d Stash

# luckyBackup
docker stop luckyBackup && docker rm luckyBackup
docker compose -f 03_stack-frontend.yml up -d luckyBackup

Abschlusskontrolle

# Alle Container laufen?
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Networks}}"

# Port 5432 nicht mehr öffentlich?
nc -zv 127.0.0.1 5432      # → Connection refused ✓
nc -zv 127.0.0.1 6379      # → Connection refused ✓ (alter Redis-Port)
nc -zv 127.0.0.1 6382      # → Connection refused ✓ (alter Redis-Port)

# Netzwerk-Isolation: Portainer kann postgresql17 NICHT sehen
docker exec PortainerCE ping postgresql17 2>&1 | head -2
# → Name or service not known ✓

# paperless-ngx kann postgresql17 sehen
docker exec paperless-ngx nc -zv postgresql17 5432 2>&1
# → Connection succeeded ✓

Phase 5 Traefik (separat, wenn bereit)

Erst wenn Phase 14 stabil laufen:

  1. traefik/traefik.yml anlegen (Vorlage in 04_stack-traefik.yml)
  2. Domain + DNS-Eintrag einrichten
  3. Port 80 + 443 auf Router weiterleiten
  4. docker compose -f 04_stack-traefik.yml up -d
  5. Dashboard testen: https://traefik.yourdomain.tld
  6. Pro Container: traefik.enable: "false""true", Port auskommentieren

Was unberührt bleibt

Stack Grund
immich (immich_default) bereits korrekt isoliert
scanopy (scanopy_scanopy) bereits korrekt isoliert
Plex, Tailscale, ntopng* host-Netz technisch bedingt
Netdata, Glances, netalertx host-Netz technisch bedingt

*ntopng wird entfernt und später sauber neu aufgesetzt.