Bedrud Dokumentation

Bedrud verwendet LiveKit für die Echtzeit-Video- und Audiokommunikation. LiveKit stellt den SFU-Medienserver (Selective Forwarding Unit) bereit, während Bedrud die Authentifizierung, Raumverwaltung und Admin-Kontrollen übernimmt.

Eingebettet vs. Extern

Bedrud unterstützt zwei LiveKit-Bereitstellungsmodi:

  1. Eingebetteter Modus (Standard): Das Backend startet und verwaltet einen LiveKit-Server-Prozess intern. Es ist keine zusätzliche Infrastruktur erforderlich – das Backend verwaltet den gesamten LiveKit-Prozess-Lebenszyklus.
  2. Externer Modus: Bedrud verbindet sich mit einem separaten LiveKit-Server oder -Cluster. Dies ist nützlich für horizontale Skalierung oder bei Verwendung einer verwalteten LiveKit Cloud-Instanz.

Konfiguration des externen Modus

Um einen externen LiveKit-Server zu verwenden, setzen Sie die folgenden Schlüssel in config.yaml:

livekit:
  host: "wss://livekit.example.com:7880"    # Client WebSocket URL (ws:// or wss://)
  internalHost: "https://livekit.example.com:7880"  # Server-to-server API URL
  apiKey: "your-api-key"
  apiSecret: "your-api-secret"
  external: true          # Skip embedded LiveKit startup
  skipTLSVerify: false    # Set true if LiveKit uses self-signed certs

Wenn embedded auf false gesetzt ist, überspringt Bedrud das Starten des eingebetteten LiveKit-Binaries. Der API-Schlüssel und das Secret müssen mit den Anmeldeinformationen des externen Servers übereinstimmen.

Für die Einrichtung und Konfiguration eines LiveKit-Clusters lesen Sie bitte die LiveKit-Dokumentation.

Webhook-Konfiguration (nur extern)

Bei Verwendung eines externen LiveKit-Servers müssen Sie Webhooks konfigurieren, damit LiveKit Bedrud über Teilnehmer-Trennungen und Raumschließungen informieren kann. Ohne Webhooks wird der Datenbankstatus veralten.

Endpunkt: https://<your-domain>/api/livekit/webhook

Authentifizierung: Verwendet die JWT-Signierung von LiveKit — denselben apiKey/apiSecret, den Sie oben konfiguriert haben. Kein separates Geheimnis erforderlich.

LiveKit Cloud: Einstellungen → Webhooks → Neuen Webhook erstellen. Geben Sie die Endpunkt-URL ein und wählen Sie Ihren API-Schlüssel aus.

Selbst gehostetes LiveKit: Fügen Sie zu Ihrer LiveKit-YAML-Konfiguration (z. B. livekit.yaml) hinzu:

webhook:
  urls: ["https://bedrud.example.com/api/livekit/webhook"]
  api_key: "your-api-key"

Ohne einen ordnungsgemäß konfigurierten Webhook werden participant_disconnected- und room_finished-Ereignisse nicht an Bedrud übermittelt. Das Admin-Dashboard zeigt möglicherweise veraltete Teilnehmerdaten an, und Räume werden nicht automatisch bereinigt.

LiveKit-Versionskompatibilität

Der eingebettete LiveKit-Modus von Bedrud generiert automatisch eine kompatible Konfiguration. Wenn Sie jedoch einen externen LiveKit-Server selbst hosten, beachten Sie die bahnbrechenden Änderungen in verschiedenen LiveKit-Versionen:

  • LiveKit v1.12+ hat das tls-Feld auf oberster Ebene aus seiner Konfiguration entfernt. Wenn Sie tls: in Ihrer LiveKit-YAML verwendet haben, entfernen Sie es. Konfigurieren Sie http:// für internalHost und ws:// für host in der Bedrud-Konfiguration. TURN TLS wird weiterhin unter dem Abschnitt turn: unterstützt.
  • LiveKit v1.11 und früher unterstützen tls: auf oberster Ebene. Verwenden Sie https:// für internalHost und wss:// für host.

Überprüfen Sie im Zweifelsfall Ihre LiveKit-Serverversion mit livekit-server --version und konsultieren Sie die LiveKit-Versionshinweise.

Eingebettete Konfigurationserzeugung (Embedded Config Generation)

Wenn TLS im eingebetteten Modus aktiviert ist, generiert Bedrud eine temporäre LiveKit-YAML-Konfiguration (/tmp/bedrud-livekit-*.yaml) mit:

  • TURN aktiviert, domain automatisch aus server.host gesetzt, udp_port: 3478, tls_port: 5349, und das Server-TLS-Zertifikat wird für TURN/TLS wiederverwendet
  • node_ip wird aufgelöst via livekit.nodeIPserver.host → automatische Ausgangs-IP-Erkennung
  • bind_addresses ausgelassen (LiveKit bindet standardmäßig alle Schnittstellen)

Die temporäre Datei wird beim Beenden des LiveKit-Prozesses gelöscht. Zur Umgehung der automatischen Generierung mit einer statischen Konfiguration setzen Sie livekit.configPath oder LIVEKIT_CONFIG_PATH.

Funktionsweise

1. Raumerstellung

Wenn ein Benutzer einen Raum in Bedrud erstellt, erstellt der Server nicht sofort einen LiveKit-Raum. LiveKit-Räume werden bei Bedarf erstellt, wenn der erste Teilnehmer beitritt.

2. Join Tokens

Wenn ein Benutzer einem Meeting beitritt:

  1. Das Frontend sendet eine Anfrage an /api/room/join.

  2. Das Backend verifiziert, dass der Benutzer die Berechtigung hat, diesem Raum beizutreten.

  3. Das Backend verwendet seinen API Key und Secret, um ein signiertes JWT (Join Token) zu generieren.

  4. Das Token enthält:

    • Den Raumnamen.
    • Die Identität des Benutzers (Anzeigename).
    • Berechtigungen – beispielsweise, ob der Benutzer Audio veröffentlichen oder seinen Bildschirm freigeben darf.
  5. Das Frontend erhält dieses Token und verbindet sich direkt mit dem LiveKit-Medienport (Standard 7880).

3. Raumsteuerung (Admin)

Das Backend verwendet das LiveKit Go SDK, um administrative Aktionen durchzuführen:

  • Kick: Trennt einen Teilnehmer.
  • Mute: Schaltet das Mikrofon eines Teilnehmers stumm.
  • Berechtigungen: Ändert in Echtzeit, was ein Teilnehmer tun kann.

Netzwerkarchitektur

  • API-Port (8090/443): Verwaltet HTTP-Anfragen und WebSocket-Signalisierung für den Verbindungsaufbau.
  • Medienport (7880): Verwaltet Video- und Audiodaten über WebRTC-Protokolle. ICE/TCP-Fallback verwendet Port 7881, wenn UDP blockiert ist.
  • TURN-Port (3478 UDP / 5349 TLS): Leitet Medien für Clients hinter restriktiven NATs oder Firewalls weiter. Siehe TURN-Server-Leitfaden.

Für Firewall- und Port-Anforderungen siehe WebRTC-Konnektivität.

Troubleshooting

Startup & Config Crashes

SymptomCauseFix
Container crash-loops, logs could not resolve external IPuse_external_ip: true without explicit node_ip in DockerSet node_ip: <lan-ip> under rtc: and use_external_ip: false
LiveKit exits with TURN domain required on v1.12+turn.tls_port is set but no domain or TLS cert/keyAdd domain: under turn:, provide cert_file/key_file, or remove tls_port for UDP-only TURN
field tls not found on startupLiveKit v1.12+ removed top-level tls: config fieldRemove tls: block from LiveKit YAML; use http:// / ws:// in Bedrud config
LIVEKIT_CONFIG env var not picked upEntrypoint doesn’t parse env var (pre-v1.7 or custom entrypoint)LiveKit reads LIVEKIT_CONFIG natively since v1.7 — verify version; pass via --config-body only if needed
Docker: --config-body via sh -c fails with flag provided but not defined: -cImage entrypoint is /livekit-server directly — command gets appended, not wrapped by shellDon’t use a shell wrapper, LIVEKIT_CONFIG env var is supported natively by the binary
Docker Compose: $LIVEKIT_CONFIG expands to empty stringCompose substitutes $VAR from host environment, not containerUse $$LIVEKIT_CONFIG to escape docker-compose variable substitution
YAML parsing error from LIVEKIT_CONFIGIncorrect YAML indentation or syntaxValidate: docker run --rm -e LIVEKIT_CONFIG livekit-server --config-body "$LIVEKIT_CONFIG"

Connectivity

SymptomCauseFix
Admin dashboard shows “LiveKit disconnected”Bedrud can’t reach LiveKit HTTP APIVerify internalHost in config; run curl http://<internalHost>/ from Bedrud host; check firewall
Token generated but client connection times outLiveKit WebSocket unreachable from browserCheck host in livekit: config (must be reachable by clients); verify DNS/firewall; test with wscat
Embedded LiveKit not startingMissing binary or permissionEnsure internal/livekit/bin/livekit-server exists (even empty file for build); check Bedrud server logs
Port 7880 already in useAnother process on same portChange livekit.port or use different Docker port mapping
Redis connection fails in LiveKit logsRedis unreachable or wrong addressVerify redis.address: in LiveKit YAML; check container network connectivity
curl http://127.0.0.1:7880 returns connection refusedLiveKit crashed during startupCheck docker logs / journalctl; look for RTC/TURN validation errors near the bottom of the log
Token expired before client connectedShort JWT validity windowRequest a fresh token via POST /api/room/join before each connection attempt

Media & TURN

SymptomCauseFix
Participants join but no audio/videoUDP port range blocked or wrong node_ipOpen UDP 50000-60000; verify node_ip is the externally reachable address
Clients behind NAT can’t connectTURN not configured or ports blockedEnable TURN; open UDP 3478 (and TCP 5349 for TLS); verify TURN domain resolves
Could not resolve external IP on startup (non-Docker)No STUN internet access or DNS failureSet explicit node_ip and use_external_ip: false
Self-signed cert errors with external LiveKitBedrud’s skipTLSVerify is falseSet skipTLSVerify: true in Bedrud’s livekit: config
Clients connect via relay unnecessarilynode_ip is a private IP behind NATSet node_ip to the public IP or use use_external_ip: true with STUN access
TURN relay not used by clientsDirect WebRTC path is working (expected)Check chrome://webrtc-internalssrflx candidates = direct path, no TURN needed

Webhook & State

SymptomCauseFix
Database shows stale active participants after disconnectWebhook not configured for external LiveKitAdd webhook: block to LiveKit YAML with URL https://<domain>/api/livekit/webhook
Participants never marked inactiveFirewall blocking webhook delivery from LiveKit to BedrudCheck LiveKit logs for webhook delivery errors; ensure port 443/8090 is reachable from LiveKit
Room not cleaned up after all leaveempty_timeout / departure_timeout too highReduce values in LiveKit YAML room: section

Recording (Egress)

Bedrud uses LiveKit’s RoomCompositeEgress API to record rooms as MP4 files.

Prerequisites

  • Redis — LiveKit egress requires Redis for coordinating egress workers. Without Redis, StartRoomCompositeEgress returns permission errors.

  • Egress S3 storage (external mode only) — For external LiveKit, you must configure an egress: section in your LiveKit YAML so recordings are stored to durable S3-compatible storage. Otherwise the FileURL is a local path unreachable from Bedrud.

    egress:
      s3:
        access_key: "your-s3-access-key"
        secret_key: "your-s3-secret-key"
        endpoint: "http://minio:9000"
        bucket: "bedrud-recordings"
        region: "us-east-1"
        force_path_style: true

Troubleshooting: Recording

SymptomCauseFix
twirp error unauthenticated: permissions denied when starting recordingEgress JWT missing Room field in grantUpdate egressAuthContext to include Room: roomName in the VideoGrant
twirp error unauthenticated: permissions denied even with valid API keyRedis not configured for LiveKit, or egress workers unavailableAdd redis: section to LiveKit YAML; ensure Redis is healthy
Recording starts but FileURL is a local path (e.g., /tmp/...)No egress: S3 config — LiveKit writes to worker temp dirAdd egress.s3: block to LiveKit YAML pointing to S3-compatible storage
process_recording job fails to downloadExternal LK’s file URL points to inaccessible local pathConfigure egress S3 so LiveKit produces S3 URLs

See also the TURN Server Guide for TURN-specific troubleshooting, WebRTC Connectivity for STUN/ICE/firewall debugging, and Installation Troubleshooting for port/perm/setup issues.

Siehe auch