Jitsi self-hosted vs Zoom : ce qui change vraiment
Les services de visioconférence grand public (Zoom, Google Meet, Teams) imposent des limites de durée sur les plans gratuits, des quotas de participants, et conservent vos enregistrements sur leurs serveurs. Jitsi Meet, auto-hébergé, supprime ces contraintes : salles sans limite, durée sans limite, aucun compte requis pour rejoindre une réunion, flux vidéo qui restent sur votre infrastructure. C'est particulièrement pertinent pour une organisation soucieuse de la confidentialité de ses réunions, pour un cabinet qui traite des données sensibles, ou pour intégrer la visio dans une application tierce (Jitsi propose une API iframe stable). Le coût de fonctionnement se résume à la facture du VPS — aucun abonnement par siège, aucun surcoût logiciel.
Bénéfices concrets d'un Jitsi auto-hébergé
- Réunions sans limite de durée ni de nombre de salles — aucun minuteur qui coupe la réunion.
- Aucun compte requis pour les participants : un lien suffit pour rejoindre.
- API iframe pour intégrer la visio directement dans votre application ou votre site.
- Chiffrement du transport (DTLS-SRTP) et contrôle total sur les éventuels enregistrements.
- Personnalisation complète de l'interface : logo, couleurs, nom de domaine des salles.
- Aucune télémétrie envoyée à un tiers — les flux vidéo ne quittent pas votre VPS.
Prérequis chiffrés avant de commencer
Jitsi est dimensionné par la bande passante, pas par le CPU. La documentation Jitsi conseille 8 Go de RAM (4 Go suffisent pour de petites réunions), environ 4 cœurs dédiés pour un serveur de base, et surtout un lien réseau fiable : un flux 720p consomme environ 2,5 Mbit/s, et un lien de 100 Mbit/s ne tient pas une vingtaine de participants en haute définition. Surveillez la charge réseau du JVB. Trois ports doivent être joignables depuis internet : TCP 443 (HTTPS), TCP 80 (challenge Let's Encrypt et redirection vers HTTPS), UDP 10000 (média JVB). Le port TCP 4443 cité par d'anciens guides ne figure plus dans la liste officielle. Si coturn tourne sur le même VPS, ajoutez ses ports : 3478 en UDP et TCP, 5349 en TLS (le 443 est déjà pris par le conteneur web). Il faut Docker avec Compose V2 (commande docker compose), un nom de domaine meet.votredomaine.com avec un enregistrement A pointant vers l'IP publique du VPS, et une IP publique dédiée et stable — une IP partagée complique sérieusement la config coturn.
Déploiement pas à pas : Docker, .env, coturn et premier test
Récupérer docker-jitsi-meet
Téléchargez la dernière release depuis la page des releases de
github.com/jitsi/docker-jitsi-meetet décompressez-la : le guide officiel déconseille de cloner le dépôt, dont la branche principale tire les imagesunstable. Créez les dossiers de configuration listés par le guide (~/.jitsi-meet-cfg/…, dontstorageettmp, inscriptibles par l'uid 1000) : les conteneurs tournent sans root et refusent de démarrer sinon. Copiezenv.examplevers.env, puis exécutez./gen-passwords.sh— ce script génère tous les secrets internes (Prosody, Jicofo, JVB). Ne sautez pas cette étape : les valeurs par défaut ne sont pas des secrets. La releasestable-11248-3(novembre 2026) est la dernière stable ; évitezmasteret les imagesunstableen production, les composants internes changent sans préavis.Configurer PUBLIC_URL, les ports et JVB_ADVERTISE_IPS
Dans
.env, réglez d'abordHTTP_PORT=80etHTTPS_PORT=443(8000 et 8443 par défaut). Deux variables sont ensuite critiques :PUBLIC_URL=https://meet.votredomaine.com(utilisée par le client web pour construire les URL de salles) etJVB_ADVERTISE_IPS=<IP_PUBLIQUE_DU_VPS>(l'adresse que le JVB annonce aux clients pour établir la connexion média directe ; elle remplace l'ancienneDOCKER_HOST_ADDRESS). SansJVB_ADVERTISE_IPS, le JVB tente de découvrir son IP publique par STUN ; si l'adresse annoncée est fausse, les appels échouent dès que plus de deux participants rejoignent la réunion.Activer Let's Encrypt dans .env
Ajoutez dans
.env:ENABLE_LETSENCRYPT=1,LETSENCRYPT_DOMAIN=meet.votredomaine.com,[email protected]. Vérifiez que le port 80 est bien ouvert avant de démarrer — Let's Encrypt utilise un challenge HTTP-01 qui requiert une réponse sur ce port. Le conteneur web obtient et renouvelle le certificat avec acme.sh (service de renouvellement interne) et le conserve dans~/.jitsi-meet-cfg/storage/web: gardez ce dossier entre les redémarrages. Ajoutez aussiLETSENCRYPT_ACME_SERVER=letsencrypt: sans elle, acme.sh s'adresse à ZeroSSL par défaut.Configurer coturn (TURN server)
C'est l'étape que la plupart des guides survolent et qui fait échouer l'installation. docker-jitsi-meet ne fournit pas coturn : installez-le à part (paquet ou conteneur), puis déclarez-le dans
.envpour que Prosody remette aux clients des identifiants temporaires :TURNS_HOST=turn.votredomaine.cometTURNS_PORTpour le TLS,TURN_HOST=turn.votredomaine.com,TURN_PORT=3478etTURN_TRANSPORT=udp,tcpen complément. Le port 443 en TLS permet de traverser les pare-feux les plus restrictifs, qui bloquent les ports non standard mais laissent passer ce qui ressemble à du HTTPS ; il exige une IP que le conteneur web n'occupe pas déjà, sinon gardez 5349.Générez ensuite un secret partagé (
openssl rand -hex 32) et placez-le dansTURN_CREDENTIALScôté.envet dans coturn (use-auth-secretetstatic-auth-secret=<le même secret>) ; jamaisno-auth, qui ferait de votre serveur un relais ouvert à tous. Le certificat TLS se déclare dans la configuration de coturn (cert=etpkey=), pas dans.env. Si coturn tourne dans un conteneur séparé, montez ces fichiers en volume.Dernier point souvent oublié : coturn ne bloque pas par défaut les plages RFC1918 (192.168.x.x, 10.x.x.x, 172.16.x.x) : seul le loopback est refusé. Un client authentifié peut donc relayer du trafic vers votre réseau interne. Ajoutez
no-multicast-peerset des lignesdenied-peer-ippour ces plages, puis, si le JVB a une adresse interne, autorisez-la seule avecallowed-peer-ip.Lancer la stack et vérifier le JVB
Exécutez
docker compose up -d. Attendez 30 secondes, puis :docker compose logs jvb 2>&1 | grep -E 'register|connected|error'. Vous devez voir une ligne indiquant que le JVB s'est enregistré auprès de Jicofo. Si vous voyezFailed to registerouConnection refused, le Prosody n'est pas encore prêt — relancez après une minute. Vérifiez ensuite que les ports répondent :nc -zv meet.votredomaine.com 443(web, TCP),nc -zv turn.votredomaine.com 3478(coturn, TCP) etnc -zvu meet.votredomaine.com 10000(JVB, UDP ; un succès en UDP n'est qu'indicatif).Premier test vidéo depuis deux réseaux différents
Ouvrez
https://meet.votredomaine.comdepuis votre poste habituel et depuis un second appareil sur un réseau différent (téléphone en 4G par exemple). Si les deux participants se voient et s'entendent, le TURN fonctionne. Un test depuis deux postes sur le même réseau local ne valide pas coturn — il réussit en pair-à-pair sans jamais solliciter le relais.
Configuration avancée : enregistrement, authentification et limites
Enregistrement des réunions. Jitsi intègre Jibri pour l'enregistrement local ou le streaming RTMP. Jibri capture le rendu d'un navigateur en temps réel : une instance n'enregistre qu'une réunion à la fois, et la documentation Jitsi demande au moins 8 Go de RAM par instance en 720p, de préférence sur un serveur séparé. Activez ENABLE_RECORDING=1 dans .env et lancez le conteneur Jibri fourni : docker compose -f docker-compose.yml -f jibri.yml up -d. Authentification des organisateurs. Par défaut, n'importe qui peut créer une salle : une instance publique laissée ainsi devient une visio gratuite pour des inconnus, sur votre bande passante. Activez ENABLE_AUTH=1, AUTH_TYPE=internal et ENABLE_GUESTS=1 pour exiger un compte côté organisateur tout en laissant les invités rejoindre librement. Créez les comptes hôtes avec docker compose exec prosody prosodyctl --config /run/prosody/config/prosody.cfg.lua register admin meet.jitsi <mot_de_passe> : meet.jitsi est le domaine XMPP interne, pas votre nom public, et le mot de passe se génère (openssl rand -base64 18) plutôt que de se réutiliser. Limiter les participants anonymes. ENABLE_LOBBY=1 rend disponible la salle d'attente : une fois activée par le modérateur, chaque entrée doit être validée avant d'accéder à la salle. Combiné à ENABLE_AUTH=1, cela donne un contrôle complet sur qui accède à quoi.
Durcissement : fail2ban sur le service TURN
coturn expose un service accessible depuis internet. Installez fail2ban et créez un filtre sur les tentatives d'authentification TURN échouées : les échecs apparaissent dans le journal de coturn avec un code 401 ; vérifiez le format exact de votre version avant d'écrire la regex du filtre. Une jail fail2ban avec maxretry=10 et bantime=600 suffit à décourager les scans automatiques sans impacter vos utilisateurs légitimes. Fixez le journal avec log-file=/var/log/turnserver.log dans la configuration de coturn (sans cette option, coturn choisit lui-même un fichier dans /var/log, /var/tmp ou /tmp), faites surveiller ce chemin par fail2ban, ou montez ce fichier depuis le conteneur.
Dépannage : les quatre erreurs les plus fréquentes
Son absent ou vidéo bloquée sur « connecting » — coturn + UDP 10000. C'est la panne la plus fréquente. Vérifiez dans cet ordre : (1) ufw status — les ports TCP 443 et UDP 10000 sont-ils ouverts ? (2) les journaux de coturn (journalctl -u coturn en natif, docker logs <conteneur-coturn> sinon) — coturn démarre-t-il sans erreur de certificat ? (3) Depuis une machine externe : curl -v telnet://meet.votredomaine.com:3478 — coturn répond-il ? (4) Dans les logs du navigateur (F12 → Console) : voyez-vous ICE failed ou failed to gather candidates ? Si oui, coturn n'est pas joignable depuis l'extérieur. Vérifiez que TURN_HOST et TURNS_HOST dans .env résolvent bien vers l'IP réelle du serveur coturn. Connexion refusée sur TCP 443. Si le certificat Let's Encrypt n'a pas pu être émis (port 80 fermé lors du premier démarrage), le conteneur web s'arrête après le message Failed to obtain a certificate from the Let's Encrypt CA et plus rien ne répond sur le 443. Solution : ouvrez le port 80, vérifiez HTTP_PORT=80 et relancez docker compose up -d ; inutile de supprimer la configuration, et chaque nouvel essai compte dans les limites de Let's Encrypt. Partage d'écran refusé par le navigateur. Le partage d'écran exige un contexte sécurisé (HTTPS valide). Si vous voyez getUserMedia is not supported, le certificat est invalide ou le domaine n'est pas en HTTPS. Vérifiez PUBLIC_URL — elle doit commencer par https:// avec un domaine dont le certificat est valide, pas une IP brute. Erreur « ICE failed » persistante malgré coturn opérationnel. Vérifiez la variable JVB_ADVERTISE_IPS (anciennement DOCKER_HOST_ADDRESS) : elle doit contenir l'IP publique du VPS, pas l'IP interne du conteneur Docker (172.17.x.x). Si votre VPS est derrière un NAT cloud (rare mais existant), vous avez besoin de l'IP NAT externe, pas de l'IP de l'interface réseau.
Monitoring : surveiller la bande passante et les participants
Le pont vidéo JVB expose une API de statistiques en temps réel sur http://localhost:8080/colibri/stats. Cette endpoint JSON rapporte le nombre de conférences actives, de participants, la bande passante entrante et sortante en kbit/s, et le RTT moyen (rtt_aggregate). Ce port 8080 n'est publié que sur 127.0.0.1 : gardez-le ainsi. Pour une surveillance continue, le JVB expose déjà ses métriques au format Prometheus sur /metrics (même port privé) ; côté Prosody, activez PROSODY_ENABLE_METRICS=1 dans .env. Connectez ensuite un Prometheus + Grafana : le dépôt fournit prometheus.yml et grafana.yml, qui publient les ports 9090 et 3000 sur toutes les interfaces. Limitez-les à 127.0.0.1 ou à un VPN, car les ports publiés par Docker contournent les règles ufw.
En l'absence de Prometheus, une surveillance minimale s'obtient avec un cron qui interroge /colibri/stats et alerte si le débit dépasse un seuil : curl -s http://127.0.0.1:8080/colibri/stats | python3 -c "import json,sys; s=json.load(sys.stdin); print(s.get('bit_rate_download',0), s.get('bit_rate_upload',0))".
Pour estimer la capacité avant d'atteindre la saturation : la capacité d'un JVB dépend d'abord du lien réseau et des résolutions envoyées ; mesurez-la sur votre propre charge plutôt que de vous fier à un chiffre générique. Quand la limite approche, rtt_aggregate grimpe et la qualité perçue chute avant que le CPU sature — c'est le signal pour ajouter une instance JVB.
Votre Jitsi est en place — gérez la bande passante
Jitsi fonctionne en mode SFU : le pont vidéo (JVB) relaie chaque flux vers chaque participant, donc la bande passante sortante grimpe proportionnellement au nombre de participants multiplié par le nombre de flux. Un flux 720p pèse environ 2,5 Mbit/s selon la documentation Jitsi : multipliez par le nombre de flux réellement envoyés à chaque participant pour estimer le débit sortant. Réglez channelLastN: 5 dans custom-config.js (dossier web de la configuration) pour ne recevoir que les N dernières vidéos actives pour limiter les flux côté client sur les grosses réunions, et surveillez docker stats jvb pour anticiper la saturation. Au-delà d'une vingtaine de participants simultanés réguliers, déployez plusieurs instances JVB sur des VPS distincts derrière un seul Jicofo : c'est l'architecture de passage à l'échelle horizontale native de Jitsi. Pour les déploiements multi-organisations ou multi-domaines, retenez qu'une installation docker-jitsi-meet n'a qu'une PUBLIC_URL : si chaque organisation doit disposer de ses propres comptes et d'un espace de salles isolé, prévoyez une instance par organisation, sur son propre sous-domaine.