feat(infra): migrate self-hosted backend to netralax.de

Move Supabase + LiveKit from the netralax.cloud VPS to a new netralax.de server. Adds the migration runbook (docs/), one-time move scripts (scripts/migrate/), and prod Caddy/LiveKit config templates (infra/). Repoints the desktop publish/changelog URLs and prod ops config to .de. JWT_SECRET + VAPID copied identically so already-installed clients keep working; the new server also serves the legacy .cloud hostnames.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
byGalax
2026-06-02 19:39:04 +02:00
parent 588b843904
commit 5bc30c950c
15 changed files with 1807 additions and 11 deletions
+132
View File
@@ -0,0 +1,132 @@
# Server-Umzug: netralax.cloud -> netralax.de
Einmalige Migration des selbst gehosteten Chat-Backends vom **alten VPS**
(`46.225.156.249`, `*.netralax.cloud`) auf einen **neuen, leeren VPS**
(`*.netralax.de`). Der neue Server bedient anschliessend **beide** Domains,
damit bereits installierte Desktop-/Mobile-Clients (die alte Hostnamen und den
alten anon-JWT fest eingebaut haben) weiterlaufen, bis sie sich selbst
aktualisieren.
> Diese Skripte sind bewusst getrennt von `scripts/prod/`. `scripts/prod/config.sh`
> kennt nur den jeweils **aktiven** Server; der Umzug braucht **beide** Hosts und
> hat deshalb seine eigene `scripts/migrate/config.sh`.
## Dateien
| Datei | Wo ausführen | Zweck |
|-------|--------------|-------|
| `config.sh` | | Gemeinsame Konfiguration (alter + neuer Host, SSH-Helfer). Wird von den anderen Skripten eingebunden. |
| `01-bootstrap-new-server.sh` | **auf dem neuen VPS** (als root / sudo) | Richtet den leeren Server ein: Docker, ufw, Supabase-Clone, LiveKit-Verzeichnis, Caddy, Update-Host, Deploy-User. |
| `02-migrate-data.sh` | **auf dem Entwickler-Laptop** | Überträgt Postgres-Daten (pg_dumpall) und die Storage-Objekte (rsync) von alt nach neu. |
## Voraussetzungen / Einrichtung (einmalig)
1. **Neue Server-IP — bereits eingetragen.** `scripts/migrate/config.sh` hat
`NEW_HOST="141.95.34.204"` und `NEW_USER="debian"`. (Der `require_new_host`-
Guard greift nur, falls der Platzhalter wieder drinsteht.)
2. **SSH-Zugriff.** Vom Laptop muss `ssh prox@46.225.156.249` (alt) **und**
`ssh debian@141.95.34.204` (neu) ohne Passwort funktionieren:
```
ssh-copy-id prox@46.225.156.249
ssh-copy-id debian@141.95.34.204
```
Für den direkten Storage-Transfer (Server-zu-Server) muss zusätzlich der
**alte** Server per SSH auf den **neuen** zugreifen können. Klappt das nicht,
fällt `02-migrate-data.sh` automatisch auf den Umweg über den Laptop zurück.
3. **Skripte ausführbar machen:**
```
chmod +x scripts/migrate/*.sh
```
## Ablauf (Reihenfolge unbedingt einhalten)
1. **Bootstrap auf dem neuen Server.** Skript hochladen und als root ausführen:
```
scp scripts/migrate/01-bootstrap-new-server.sh debian@141.95.34.204:/tmp/
ssh debian@141.95.34.204 'sudo bash /tmp/01-bootstrap-new-server.sh'
```
Das Skript ist idempotent (mehrfaches Ausführen schadet nicht) und gibt am
Ende einen **NEXT STEPS**-Block aus.
2. **Secrets eintragen.** `/opt/supabase/.env` auf dem neuen Server befüllen.
Diese Werte **1:1 vom alten Server kopieren** (sonst brechen eingebaute
Tokens, Sessions und Web-Push):
`POSTGRES_PASSWORD`, `JWT_SECRET`, `ANON_KEY`, `SERVICE_ROLE_KEY`,
`SECRET_KEY_BASE`, `VAULT_ENC_KEY`, `PG_META_CRYPTO_KEY`, alle `SMTP_*`,
`VAPID_PUBLIC_KEY`, `VAPID_PRIVATE_KEY`, `VAPID_SUBJECT`,
`PUSH_FANOUT_SHARED_SECRET`, `LIVEKIT_API_KEY`, `LIVEKIT_API_SECRET`.
Auf die **neue** Domain zeigen:
`SITE_URL`, `API_EXTERNAL_URL`, `SUPABASE_PUBLIC_URL`, `SUPABASE_URL`
= `https://supabase.netralax.de`, `LIVEKIT_URL` = `wss://livekit.netralax.de`.
`ADDITIONAL_REDIRECT_URLS` (komma-getrennt, **ohne Leerzeichen**) muss
enthalten: `chatapp://auth/callback`, `netralax://auth/callback` sowie
`https://supabase.netralax.de` und `https://supabase.netralax.cloud`.
3. **Server-Konfig platzieren.**
- `infra/livekit/docker-compose.prod.yml.example` -> `/opt/livekit/docker-compose.yml`
(Prod-Compose: host-networking, mountet `livekit.yaml` + `coturn.conf` +
`/etc/letsencrypt`; das Dev-Compose taugt **nicht** für Prod).
- `infra/livekit/livekit.prod.yaml.example` -> `/opt/livekit/livekit.yaml`
(`rtc.use_external_ip: true`, **kein** `node_ip: 127.0.0.1`, `keys:`-Block
identisch zu `LIVEKIT_API_KEY/SECRET` aus der `.env`).
- `infra/livekit/coturn.prod.conf.example` -> `/opt/livekit/coturn.conf`
(`external-ip` = öffentliche IP des neuen VPS, TLS-Cert für
`turn.netralax.de`).
- `infra/caddy/Caddyfile` -> `/etc/caddy/Caddyfile`, danach
`systemctl reload caddy`. Caddy bedient **beide** Domains (.de und .cloud).
4. **Stacks starten DB zuerst einmal hochfahren**, damit die Supabase-Init-
Skripte die Rollen anlegen (vor dem Restore):
```
ssh debian@141.95.34.204 'cd /opt/supabase && docker compose up -d db && sleep 20'
```
5. **Schreibzugriffe auf dem ALTEN System einfrieren** (Wartungsmodus). Sonst
landen während des Umzugs neue Uploads/Zeilen nur auf einer Seite und
DB + Storage werden inkonsistent.
6. **Daten migrieren** (vom Laptop). Erst der Trockenlauf, dann die Migration:
```
./scripts/migrate/02-migrate-data.sh --check # nur Pre-Flight, keine Änderung
./scripts/migrate/02-migrate-data.sh # fragt nach Bestätigung
```
Das Skript dumpt den **gesamten** Cluster per `pg_dumpall` und spielt ihn auf
dem neuen Server ein, danach rsync der Storage-Objekte. `push-migrations.sh`
**nicht** erneut ausführen die Migrationen sind bereits im Dump enthalten.
7. **DNS umstellen.** A-Records für **beide** Domains auf die neue IP zeigen
lassen: `supabase.netralax.de` / `.cloud`, `livekit.netralax.de` / `.cloud`,
`turn.netralax.de`, `update.netralax.de` / `.cloud`.
8. **Update-Artefakte spiegeln.** electron-updater-Dateien (`latest.yml`,
`*.exe`, `changelog.json`) unter `/var/www/updates/windows` ablegen, sodass
**sowohl** `update.netralax.de` **als auch** `update.netralax.cloud` sie
ausliefern. Nur so können alte (.cloud-)Clients die Umstiegs-Version ziehen.
## Sicherheitshinweise
- **`JWT_SECRET`, `ANON_KEY`, `SERVICE_ROLE_KEY`** müssen byteweise identisch
vom alten Server stammen, **bevor** der erste Client den neuen Server trifft
sonst werden alle eingebauten Tokens abgelehnt und alle Sessions fliegen raus.
- **`POSTGRES_PASSWORD`** muss vor dem Restore identisch gesetzt sein, weil der
Dump die Rollen-Passwort-Hashes mitbringt. Sonst können sich die internen
Dienste (auth/rest/storage) nach dem Restore nicht mehr an Postgres anmelden.
- **VAPID-Schlüsselpaar** identisch übernehmen, sonst sind alle bestehenden
Web-Push-Abos ungültig.
- **Medien-/TURN-Ports** müssen in ufw offen sein (7880/7881 tcp, 50000-50100
udp, coturn 3478 tcp+udp, 5349 tcp, 50200-50300 udp) sonst haben Anrufe kein
Audio/Video. Diese Ports laufen **nicht** über Caddy.
- **TURNS auf 5349** braucht ein eigenes TLS-Zertifikat für `turn.netralax.de`
auf der Platte (Pfade in `coturn.conf`) ein reines Caddy-Zertifikat reicht
nicht.
- **Alten VPS nicht abschalten**, bevor die `.cloud`-DNS-Einträge auf den neuen
Server zeigen und alte Clients Zeit zum Auto-Update hatten.
- Beim Restore werden harmlose `already exists`-Fehler für vorhandene Rollen
(`supabase_admin`, `postgres` …) ausgegeben das ist gewollt
(`ON_ERROR_STOP=0`). `02-migrate-data.sh` scannt die Restore-Ausgabe
**automatisch** auf echte `ERROR/FATAL/PANIC` und **bricht vor dem Storage-
rsync ab**, wenn welche übrig bleiben (Override: `FORCE_RESTORE_OK=1`).
Danach macht es eine Zeilen-Paritätsprüfung (alt vs. neu) über die tragenden
Tabellen.