Backend: - GET /api/calls/ice-servers: ephemeral HMAC TURN credentials (10-min TTL), iceTransportPolicy:"relay" (no IP leak), 503 until coturn configured - nitro runtimeConfig: turnHost/turnSecret/turnRealm (Infisical staging set) Ops: - ops/calls/ runbook + turnserver.conf (self-hosted coturn, force-relay, use-auth-secret, hardening). coturn provisioned + verified on rebreak-server. Frontend (DM header redesign): - removed standalone "i" button; header center (avatar+name+chevron) opens info sheet - call icon top-right, only when canCall (mutual-follow + callsEnabled); shows "coming soon" until the WebRTC client lands Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2.6 KiB
2.6 KiB
Voice-Calls — coturn TURN-Server Runbook
Self-hosted TURN (coturn) auf Hetzner für die DM-Voice-Calls. Force-Relay → kein direkter IP-Austausch zwischen Usern (Anonymität, kein neuer Sub-Auftragsverarbeiter).
Architektur
App A ──┐ ┌── App B
│ WebRTC (DTLS-SRTP, E2E) │
├──────────────► coturn ◄──────┤ ← relay-only, sieht nur verschlüsselten Audio-Stream
│ │
Signaling (SDP/ICE) über Supabase Realtime (ephemerer Channel pro Call)
ICE-Credentials über GET /api/calls/ice-servers (HMAC, 10-min-TTL)
- coturn validiert ephemere Credentials per
use-auth-secret(kein DB-Lookup). - Das Backend mintet sie aus
TURN_SECRET= coturnstatic-auth-secret.
Provisioning (einmalig)
⚠️ Destruktive/Infra-Schritte — nur mit User-GO ausführen. Secrets NIE committen, nur in Infisical (staging).
- DNS: A-Record
turn.rebreak.org→ Server-IP (Hetzner). - Install:
apt update && apt install -y coturn - TLS-Cert:
certbot certonly --standalone -d turn.rebreak.org(Port 80 muss kurz frei sein). Auto-Renew via certbot-Timer. - Config:
ops/calls/turnserver.conf→/etc/turnserver.conf.static-auth-secretdurch das echte Secret ersetzen (siehe Schritt 6). - Firewall (Hetzner Cloud Firewall + ufw): öffnen
3478/udp,3478/tcp(STUN/TURN)5349/tcp(TURN over TLS)49160-49200/udp(Relay-Range, = min/max-port in der Config)
- Secret generieren + in Infisical (env=staging) setzen:
TURN_SECRET=openssl rand -hex 32(gleicher Wert in turnserver.conf)TURN_HOST=turn.rebreak.orgTURN_REALM=rebreak.org
- Enable: in
/etc/default/coturn→TURNSERVER_ENABLED=1, dannsystemctl enable --now coturn. - Verify:
ss -lunp | grep 3478(lauscht UDP)turnutils_uclient -v -t -u <user> -w <pw> turn.rebreak.org(oder Trickle-ICE-Test im Browser gegen turns:turn.rebreak.org:5349).
Backend
GET /api/calls/ice-serversliefert{ iceServers, iceTransportPolicy:"relay", ttl }.- Wirft
503 calls_not_configured, solangeTURN_HOST/TURN_SECRETfehlen → kein IP-leakender Fallback. - runtimeConfig-Keys in
backend/nitro.config.ts:turnHost,turnSecret,turnRealm.
Betrieb / Kosten
- Audio ≈ 50 kbps/Call → Bandbreite vernachlässigbar.
- coturn kann auf der bestehenden Hetzner-Box mitlaufen (eigene Ports).
- Log-Minimierung: coturn
no-cli, kein verbose-Logging in Prod.