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 :
- 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.
- 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 certsLorsque 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
tlsde premier niveau de sa configuration. Si vous utilisieztls:dans votre YAML LiveKit, supprimez-le. Configurezhttp://pourinternalHostetws://pourhostdans la configuration de Bedrud. TURN TLS est toujours pris en charge dans la sectionturn:. - LiveKit v1.11 et versions antérieures prennent en charge
tls:au niveau supérieur. Utilisezhttps://pourinternalHostetwss://pourhost.
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é,
domaindéfini automatiquement depuisserver.host,udp_port: 3478,tls_port: 5349, et le certificat TLS du serveur réutilisé pour TURN/TLS node_iprésolu vialivekit.nodeIP→server.host→ détection automatique de l’IP sortantebind_addressesomis (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 :
-
Le frontend envoie une requête à
/api/room/join. -
Le backend vérifie que l’utilisateur a la permission de rejoindre cette salle.
-
Le backend utilise sa Clé API et Secret pour générer un JWT signé (Jeton de Rejoindre).
-
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.
-
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
| Symptom | Cause | Fix |
|---|---|---|
Container crash-loops, logs could not resolve external IP | use_external_ip: true without explicit node_ip in Docker | Set 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/key | Add domain: under turn:, provide cert_file/key_file, or remove tls_port for UDP-only TURN |
field tls not found on startup | LiveKit v1.12+ removed top-level tls: config field | Remove tls: block from LiveKit YAML; use http:// / ws:// in Bedrud config |
LIVEKIT_CONFIG env var not picked up | Entrypoint 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: -c | Image entrypoint is /livekit-server directly — command gets appended, not wrapped by shell | Don’t use a shell wrapper, LIVEKIT_CONFIG env var is supported natively by the binary |
Docker Compose: $LIVEKIT_CONFIG expands to empty string | Compose substitutes $VAR from host environment, not container | Use $$LIVEKIT_CONFIG to escape docker-compose variable substitution |
YAML parsing error from LIVEKIT_CONFIG | Incorrect YAML indentation or syntax | Validate: docker run --rm -e LIVEKIT_CONFIG livekit-server --config-body "$LIVEKIT_CONFIG" |
Connectivity
| Symptom | Cause | Fix |
|---|---|---|
| Admin dashboard shows “LiveKit disconnected” | Bedrud can’t reach LiveKit HTTP API | Verify internalHost in config; run curl http://<internalHost>/ from Bedrud host; check firewall |
| Token generated but client connection times out | LiveKit WebSocket unreachable from browser | Check host in livekit: config (must be reachable by clients); verify DNS/firewall; test with wscat |
| Embedded LiveKit not starting | Missing binary or permission | Ensure internal/livekit/bin/livekit-server exists (even empty file for build); check Bedrud server logs |
| Port 7880 already in use | Another process on same port | Change livekit.port or use different Docker port mapping |
| Redis connection fails in LiveKit logs | Redis unreachable or wrong address | Verify redis.address: in LiveKit YAML; check container network connectivity |
curl http://127.0.0.1:7880 returns connection refused | LiveKit crashed during startup | Check docker logs / journalctl; look for RTC/TURN validation errors near the bottom of the log |
| Token expired before client connected | Short JWT validity window | Request a fresh token via POST /api/room/join before each connection attempt |
Media & TURN
| Symptom | Cause | Fix |
|---|---|---|
| Participants join but no audio/video | UDP port range blocked or wrong node_ip | Open UDP 50000-60000; verify node_ip is the externally reachable address |
| Clients behind NAT can’t connect | TURN not configured or ports blocked | Enable 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 failure | Set explicit node_ip and use_external_ip: false |
| Self-signed cert errors with external LiveKit | Bedrud’s skipTLSVerify is false | Set skipTLSVerify: true in Bedrud’s livekit: config |
| Clients connect via relay unnecessarily | node_ip is a private IP behind NAT | Set node_ip to the public IP or use use_external_ip: true with STUN access |
| TURN relay not used by clients | Direct WebRTC path is working (expected) | Check chrome://webrtc-internals — srflx candidates = direct path, no TURN needed |
Webhook & State
| Symptom | Cause | Fix |
|---|---|---|
| Database shows stale active participants after disconnect | Webhook not configured for external LiveKit | Add webhook: block to LiveKit YAML with URL https://<domain>/api/livekit/webhook |
| Participants never marked inactive | Firewall blocking webhook delivery from LiveKit to Bedrud | Check LiveKit logs for webhook delivery errors; ensure port 443/8090 is reachable from LiveKit |
| Room not cleaned up after all leave | empty_timeout / departure_timeout too high | Reduce 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,
StartRoomCompositeEgressreturns 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 theFileURLis 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
| Symptom | Cause | Fix |
|---|---|---|
twirp error unauthenticated: permissions denied when starting recording | Egress JWT missing Room field in grant | Update egressAuthContext to include Room: roomName in the VideoGrant |
twirp error unauthenticated: permissions denied even with valid API key | Redis not configured for LiveKit, or egress workers unavailable | Add 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 dir | Add egress.s3: block to LiveKit YAML pointing to S3-compatible storage |
process_recording job fails to download | External LK’s file URL points to inaccessible local path | Configure 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
- Guide Serveur TURN - Architecture TURN, configuration, TLS et dépannage
- Connectivité WebRTC - pile complète de connectivité STUN/ICE/TURN/SFU
- Vue d’Ensemble de l’Architecture - architecture complète du système