5 KiB
Runbook — Relais TURN (visio sur les réseaux qui bloquent l'UDP)
Voir ADR 0006 pour le pourquoi complet.
Ce qui tourne
- coturn, paquet système (pas Docker), service
coturn: écoute en TLS (TURNS) sur127.0.0.1:5349uniquement.no-udp,no-tcp: aucun autre port, jamais directement sur l'IP publique. - Nginx, bloc
stream(/etc/nginx/nginx.conf, section balisée « ANSIBLE MANAGED BLOCK — bloc A, ADR 0006 ») : seul process qui écoute le port public 443. Lit le nom demandé dans la poignée de main TLS (SNI), sans la déchiffrer, et transmet les octets tels quels :turn.syllabuslab.fr→127.0.0.1:5349(coturn) ;- tout le reste →
127.0.0.1:8443(les vhosts HTTPS du portail, qui n'écoutent plus directement le port public depuis ce chantier).
- Prosody (rôle
visio) :TURNS_HOST/TURNS_PORT/TURN_TTLdans/etc/visio/visio.env,TURN_CREDENTIALS(secret partagé avec coturn) dans/etc/visio/secrets.env. Calcule lui-même, pour chaque participant, un couple nom d'utilisateur/mot de passe TURN valable 24 h — jamais le secret au navigateur. - Certificat :
turn.syllabuslab.frfait partie du même certificat Let's Encrypt que le reste (portail_noms_certificat). coturn en a une copie lisible (/etc/turnserver/cert/, groupeturnserver), régénérée automatiquement à chaque renouvellement par/etc/letsencrypt/renewal-hooks/deploy/90-turn-coturn.sh.
Aucun nouveau port ouvert dans nftables. Le relais coturn → JVB (pour la
vraie diffusion audio/vidéo) reste en boucle locale (relay-ip=127.0.0.1,
JVB en réseau hôte) : il ne traverse jamais l'IP publique.
Rôles et playbooks
| Rôle | Rôle Ansible | Playbook |
|---|---|---|
| coturn | ansible/roles/turn/ |
ansible/turn.yml |
| Routage 443 par nom | ansible/roles/portail/tasks/07-turn-stream.yml |
ansible/portail.yml (et tout playbook qui rejoue portail) |
| Annonce côté Jitsi | ansible/roles/visio/ (tâches TURN) |
ansible/visio.yml |
Ordre de déploiement important : turn.yml doit tourner avant
visio.yml (Prosody lit le secret de coturn, pas l'inverse). portail.yml
doit avoir déjà étendu le certificat au nom turn avant que turn.yml
tente de copier /etc/letsencrypt/live/.../.
Rotation du secret partagé
Le secret est dans /etc/turnserver-secret (600 root:root). Ne jamais
l'afficher (ni cat, ni dans une commande dont la sortie serait relue).
- Sur le serveur :
sudo bash -c 'openssl rand -hex 32 > /etc/turnserver-secret; chmod 600 /etc/turnserver-secret' - Depuis le Mac :
ansible-playbook turn.yml -i inventory.ini(redéploie coturn avec le nouveau secret, le redémarre). - Puis :
ansible-playbook visio.yml -i inventory.ini(Prosody relit le secret, les conteneurs Jitsi redémarrent). - Vérifier que les deux sont synchronisés sans afficher le secret :
comparer les empreintes (
sha256sum) du secret réellement chargé par chacun, jamais leur contenu. Exemple (coturn) :
et côté Prosody (dans le conteneur) :sudo grep '^static-auth-secret=' /etc/turnserver.conf | sed 's/^static-auth-secret=//' | tr -d '\n' | sha256sum
Les deux empreintes doivent être identiques.sudo docker exec visio-prosody-1 grep external_service_secret /run/prosody/config/prosody.cfg.lua | sed -E 's/.*"(.*)".*/\1/' | tr -d '\n' | sha256sum
Ne jamais lancer deux ansible-playbook en même temps sur ce serveur :
un incident le 2026-10-13 a montré qu'ils partagent la connexion SSH
(control socket) — tuer l'un peut faire planter un worker de l'autre en
plein milieu, laissant une configuration à moitié appliquée (sans la
casser : revérifier l'état avant de relancer).
Vérifier que le relais fonctionne (sans navigateur)
SECRET=$(sudo cat /etc/turnserver-secret) # sur le serveur seulement
timeout 10 turnutils_uclient -t -S -p 443 -W "$SECRET" -e 127.0.0.1 -r 10000 -n 1 turn.syllabuslab.fr
unset SECRET
Une ligne tls_connect: client session connected suivie d'une réponse
binaire (pas une erreur HTTP) prouve que le routage par nom atteint bien
coturn. (coturn ne journalise pas ces échanges par défaut — pas de ligne
dans journalctl -u coturn à attendre.)
Vérifier de bout en bout avec un vrai participant (à faire avant le pilote)
Forcer un navigateur à ignorer l'UDP (ex. Chrome : chrome://webrtc-internals
ou bloquer l'UDP sortant sur un réseau de test) et vérifier dans les
statistiques WebRTC qu'une candidate ICE de type relay est utilisée.
Rejoue aussi portail/tests/Reels/visio-e2e.mjs.
Tout vérifier après un changement de certificat ou de Nginx
sudo nginx -t
curl -s -o /dev/null -w '%{http_code}\n' https://syllabuslab.fr
echo | openssl s_client -connect syllabuslab.fr:443 -servername turn.syllabuslab.fr 2>/dev/null | openssl x509 -noout -subject -enddate
nmap -Pn -T4 --open 163.172.4.195 # doit toujours montrer seulement 22, 80, 443