Files
byGalax 5bc30c950c 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>
2026-06-02 19:39:04 +02:00

133 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.