Bedrud Documentation

Bedrud utilise LiveKit pour gérer la communication vidéo et audio en temps réel. LiveKit fournit le serveur média SFU (Selective Forwarding Unit), et Bedrud gère l’authentification, la gestion des salles et les contrôles d’administration.

Intégré vs Externe

Bedrud supporte deux modes de déploiement LiveKit :

  1. Mode Intégré (Par Défaut) : Le backend démarre et gère un processus serveur LiveKit en interne. Aucune infrastructure supplémentaire n’est requise - le backend gère le cycle de vie du processus LiveKit.
  2. Mode Externe : Bedrud se connecte à un serveur LiveKit séparé ou un cluster. C’est utile pour la mise à l’échelle horizontale ou lors de l’utilisation d’une instance gérée LiveKit Cloud.

Configuration du Mode Externe

Pour utiliser un serveur LiveKit externe, définissez les clés suivantes dans 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

Lorsque embedded est false, Bedrud saute le démarrage du binaire LiveKit intégré. La clé API et le secret doivent correspondre aux identifiants du serveur externe.

Pour la configuration et la mise en place du cluster LiveKit, référez-vous à la documentation LiveKit.

Configuration Webhook (externe uniquement)

Lorsque vous utilisez un serveur LiveKit externe, vous devez configurer des webhooks pour que LiveKit puisse notifier Bedrud des déconnexions de participants et des fermetures de salle. Sans webhooks, l’état de la base de données deviendra obsolète.

Point de terminaison : https://<your-domain>/api/livekit/webhook

Authentification : Utilise la signature JWT de LiveKit — les mêmes apiKey/apiSecret que ceux configurés ci-dessus. Aucun secret séparé nécessaire.

LiveKit Cloud : Paramètres → Webhooks → Créer un nouveau webhook. Saisissez l’URL du point de terminaison et sélectionnez votre clé API.

LiveKit auto-hébergé : Ajoutez à votre configuration YAML LiveKit (ex. livekit.yaml) :

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

Sans un webhook correctement configuré, les événements participant_disconnected et room_finished ne sont pas transmis à Bedrud. Le tableau de bord d’administration peut afficher des données de participants obsolètes et les salles ne seront pas nettoyées automatiquement.

Compatibilité des versions LiveKit

Le mode LiveKit intégré de Bedrud génère automatiquement une configuration compatible. Cependant, si vous auto-hébergez un serveur LiveKit externe, soyez conscient des changements de rupture entre les versions de LiveKit :

  • LiveKit v1.12+ a supprimé le champ tls de premier niveau de sa configuration. Si vous utilisiez tls: dans votre YAML LiveKit, supprimez-le. Configurez http:// pour internalHost et ws:// pour host dans la configuration de Bedrud. TURN TLS est toujours pris en charge dans la section turn:.
  • LiveKit v1.11 et versions antérieures prennent en charge tls: au niveau supérieur. Utilisez https:// pour internalHost et wss:// pour host.

En cas de doute, vérifiez la version de votre serveur LiveKit avec livekit-server --version et consultez les notes de version LiveKit.

Génération de configuration intégrée (Embedded Config Generation)

Lorsque TLS est activé en mode intégré, Bedrud génère une configuration YAML temporaire pour LiveKit (/tmp/bedrud-livekit-*.yaml) avec :

  • TURN activé, domain défini automatiquement depuis server.host, udp_port: 3478, tls_port: 5349, et le certificat TLS du serveur réutilisé pour TURN/TLS
  • node_ip résolu via livekit.nodeIPserver.host → détection automatique de l’IP sortante
  • bind_addresses omis (LiveKit écoute sur toutes les interfaces par défaut)

Le fichier temporaire est supprimé à la sortie du processus LiveKit. Pour contourner la génération automatique avec une configuration statique, définissez livekit.configPath ou LIVEKIT_CONFIG_PATH.

Comment Cela Fonctionne

1. Création de Salle

Lorsqu’un utilisateur crée une salle dans Bedrud, le serveur ne crée pas immédiatement une salle LiveKit. Les salles LiveKit sont créées à la demande lorsque le premier participant rejoint.

2. Jetons de Rejoindre (Join Tokens)

Lorsqu’un utilisateur rejoint une réunion :

  1. Le frontend envoie une requête à /api/room/join.

  2. Le backend vérifie que l’utilisateur a la permission de rejoindre cette salle.

  3. Le backend utilise sa Clé API et Secret pour générer un JWT signé (Jeton de Rejoindre).

  4. Le jeton contient :

    • Le nom de la salle.
    • L’identité de l’utilisateur (nom d’affichage).
    • Permissions - par exemple, si l’utilisateur peut publier de l’audio ou partager son écran.
  5. Le frontend reçoit ce jeton et se connecte directement au port média LiveKit (défaut 7880).

3. Contrôles de Salle (Admin)

Le backend utilise le SDK Go LiveKit pour effectuer des actions administratives :

  • Expulser : Déconnecte un participant.
  • Couper le Micro : Force le microphone d’un participant en sourdine.
  • Permissions : Change ce qu’un participant peut faire en temps réel.

Architecture Réseau

  • Port API (8090/443) : Gère les requêtes HTTP et la signalisation WebSocket pour la configuration des appels.
  • Port Média (7880) : Gère les données vidéo et audio en utilisant les protocoles WebRTC. Le repli ICE/TCP utilise le port 7881 lorsque l’UDP est bloqué.
  • Port TURN (3478 UDP / 5349 TLS) : Relaie le média pour les clients derrière des NAT ou pare-feux restrictifs. Voir Guide Serveur TURN.

Pour les exigences de pare-feu et de port, voir Connectivité WebRTC.

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.

Voir aussi