# 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` = coturn `static-auth-secret`.

## Provisioning (einmalig)

> ⚠️ Destruktive/Infra-Schritte — nur mit User-GO ausführen. Secrets NIE
> committen, nur in Infisical (staging).

1. **DNS**: A-Record `turn.rebreak.org` → Server-IP (Hetzner).
2. **Install**: `apt update && apt install -y coturn`
3. **TLS-Cert**: `certbot certonly --standalone -d turn.rebreak.org`
   (Port 80 muss kurz frei sein). Auto-Renew via certbot-Timer.
4. **Config**: `ops/calls/turnserver.conf` → `/etc/turnserver.conf`.
   `static-auth-secret` durch das echte Secret ersetzen (siehe Schritt 6).
5. **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)
6. **Secret generieren** + in Infisical (env=staging) setzen:
   - `TURN_SECRET` = `openssl rand -hex 32` (gleicher Wert in turnserver.conf)
   - `TURN_HOST`   = `turn.rebreak.org`
   - `TURN_REALM`  = `rebreak.org`
7. **Enable**: in `/etc/default/coturn` → `TURNSERVER_ENABLED=1`, dann
   `systemctl enable --now coturn`.
8. **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-servers` liefert `{ iceServers, iceTransportPolicy:"relay", ttl }`.
- Wirft `503 calls_not_configured`, solange `TURN_HOST`/`TURN_SECRET` fehlen →
  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.
