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:
@@ -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.
|
||||
Reference in New Issue
Block a user