Symposium sur la sécurité des technologies de l'information et des communications

Journal du comité d'organisation

Live streaming SSTIC - Serveurs frontaux

· par le comité d'organisation
Dernière étape du livestreaming : les serveurs frontaux délivrant les flux aux clients. Nous détaillerons la mise en place d’un de ces serveurs frontaux ainsi que les évolutions possibles et différents problèmes à considérer.

Ce billet est le dernier d’une série de 5 :

  1. introduction et considérations pour le SSTIC ;
  2. l’architecture de streaming ;
  3. la chaîne de capture audio/vidéo sur place ;
  4. le transcodage des flux en différentes qualités ;
  5. les serveurs frontaux accédés par les internautes.

Prérequis

Bande passante

Pour un serveur frontal, contrairement au serveur de transcodage, la seule caractéristique importante est le débit disponible. Comptez une moyenne de 2 Mbits/s par client pour avoir de la marge.

Matériel

Un serveur dédié avec un CPU Intel Atom, ARM ou équivalent et une liaison gigabit non garantie seront largement suffisant. Avec des chunks de 5 secondes et 500 ou 1000 clients, il subira 100 à 200 hits/s environ, ce qui reste gérable par des configurations très modestes (et c’est paramétrable).

Il est ainsi possible de louer des serveurs «jetables» pour avoir un pool de frontaux conséquent, ou de bénéficier d’un peering plus favorable vers certains FAI en variant les hébergeurs pour ces frontaux.

Mise en place

La mise en place d’un frontal est très simple et peut même se faire en 5 minutes. Pour les habitués, la procédure est quasiment identique à la mise en place d’un relai, à la différence près que le frontal n’ira pas chercher le flux, mais que le serveur de transcodage lui poussera le flux spontanément.

Routage RTMP et HLS

Reprenons le routage vidéo mis en place sur le serveur de transcodage :

Représentation graphique de la configuration nginx-rtmp-module en 2018

Représentation graphique de la configuration nginx-rtmp-module en 2018 (pleine taille)

Pour le frontal, il s’agit uniquement de créer l’application hls en bas à droite. Elle servira les flux RTMP directement aux clients finaux, en plus de découper le flux en chunks placés sur le disque dur pour être servis en HTTP. Le flux source, lui, sera poussé en RTMP par le serveur de transcodage, comme indiqué sur la droite du schéma.

Compilation de nginx avec son module RTMP

La procédure sera la même que pour le serveur de transcodage :

apt-get install build-essential libpcre3 libpcre3-dev libssl-dev unzip
wget https://nginx.org/download/nginx-1.16.0.tar.gz
wget https://github.com/arut/nginx-rtmp-module/archive/master.zip
tar zxvf nginx-1.16.0.tar.gz
unzip master.zip
cd nginx-1.16.0
./configure --add-module=../nginx-rtmp-module-master --with-http_ssl_module
make && make install

Vous devez toujours créer les dossiers nécessaires :

mkdir -p /var/www/stat /var/www/hls /var/www/player 
chown -R nobody /var/www/stat /var/www/hls /var/www/player

Copiez aussi stat.xsl depuis le dossier du module rtmp dans /var/www/stat/ :

cp ../nginx-rtmp-module-master/stat.xsl /var/www/stat/

nginx est désormais installé dans /usr/local/nginx/. Sa configuration est située dans /usr/local/nginx/conf/nginx.conf.

Pour démarrer le serveur en tâche de fond, lancez la commande :

/usr/local/nginx/sbin/nginx

Pour le stopper complètement, par exemple en cas de modification de la configuration RTMP, lancez :

/usr/local/nginx/sbin/nginx -s stop

Il faut également mettre le lecteur vidéo HTML5 :

wget https://static.sstic.org/streaming2019/player.tar.gz
tar zxvf player.tar.gz -C /var/www/player

Il ne reste plus qu’à configurer nginx pour qu’il serve les fichiers HTML et les chunks vidéo.

Configuration de nginx

Techniquement, il est possible de copier-coller le fichier de configuration du serveur de transcodage. ffmpeg n’étant pas installé, aucun flux ne sera alimenté et seule l’application RTMP hls est utile.

Voici une configuration dédiée à l’usage en tant que serveur frontal. Elle est téléchargeable ici et la documentation des directives est accessible par là.

Il existe une différence notable par rapport à notre serveur de transcodage : la partie HTTP est accessible à tous les clients, alors que sur le serveur de transcodage elle est restreinte aux IP autorisées à des fins de debug. Sur ce dernier, il est aussi fait usage de règles iptables pour filtrer les clients autorisés à la volée, sans redémarrer nginx. Utiliser iptables pour gérer les autorisations d’accès permet de créer un fichier de configuration unique partagé entre serveurs de transcodage et frontaux.

worker_processes  1;
events {
    worker_connections  1024;
}

Comme pour le transcoder, nous n’utilisons qu’un seul worker. Si vous n’utilisez pas d’options incompatibles (exec*), vous pouvez en avoir plusieurs.

rtmp {

    server {

        listen 1935;
        chunk_size 4096;

        application hls {
            # Application gérant l'écriture des _chunks_ HLS dans un path 
            # accessible en HTTP
            live on;
            hls on;
            hls_path /var/www/hls;
            hls_nested on;
            hls_playlist_length 10m;
            hls_type live;

            hls_variant _low BANDWIDTH=512000;
            hls_variant _mid BANDWIDTH=1024000;
            hls_variant _hi  BANDWIDTH=2048000;
            
            # nombre maximum de connexions RTMP à accepter
            # max_connections 512;
            # attention, la vraie limite se fait au niveau de l'alias HTTP
            
            # publication en local seulement
            allow publish 127.0.0.1;
            allow publish 178.33.71.43; # on autorise le serveur de transcodage (ancien)
            allow publish 62.210.203.206; # on autorise le serveur de transcodage (new)
            deny publish all;
            
            # lecture pour tous 
            allow play all;
        }
    }
}

Les hls_variant permettent de décrire les paramètres renseignés dans les playlists m3u8 générées, afin d’aider les lecteurs clients à gérer diverses choses comme la qualité du flux.

L’option la plus utile avec le lecteur HTML5 clappr est hls_playlist_length, qui permet d’activer le «time shifting», en gros les chunks resteront disponibles plusieurs minutes sur le serveur avant d’être effacés. Les clients peuvent donc mettre le flux en pause. Le délai affiché n’est pas très précis, dans la pratique une valeur de 10 minutes nous donne 15 minutes de tampon réel.

Nous avons choisi de ne pas mettre plus de 15 minutes afin d’éviter que les clients utilisent le streaming comme un moyen d’accéder aux vidéos des présentations passées, ce qui consommerait de la bande passante au détriment des clients en direct.

# HTTP can be used for accessing RTMP stats
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;

    server {
        listen      80;
        server_name  localhost;

        # This URL provides RTMP statistics in XML
        location /stat {
            rtmp_stat all;

            # Use this stylesheet to view XML as web page
            # in browser
            rtmp_stat_stylesheet stat.xsl;
            allow 127.0.0.1;
            deny all;
        }
        
        location /stat.xsl {
            # XML stylesheet to view RTMP stats.
            # Copy stat.xsl wherever you want
            # and put the full directory path here
            root /var/www/stat/;
            allow 127.0.0.1;
            deny all;
        }
        
        location /hls {
            # Serve HLS fragments
            types {
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
            }
            root /var/www;
            add_header Cache-Control no-cache;
            add_header 'Access-Control-Allow-Origin' "$http_origin";
        }
        
        location /player {
            root /var/www;
            add_header Cache-Control no-cache;
        }

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

Il ne reste plus qu’à configurer la partie HTTP, qui sert les stats RTMP, le lecteur HTML5 et les chunks HLS.

Après redémarrage, le serveur frontal est prêt à recevoir des flux poussés par le serveur transcodage autorisé dans la configuration. Après quelques secondes, ils seront visibles sur la page d’accueil en HTTP.

Statistiques

La génération de statistiques d’audience en temps réel précises est compliqué, d’autant plus que l’association n’utilise aucun tracker de visiteurs.

Il est possible d’analyser les logs nginx pour repérer les clients RTMP (chercher les commandes PLAY), mais détecter la fin de la lecture peut s’avérer problématique. De même, il est possible de détecter les GET HTTP pour les clients HLS.

Pour rester simple, il a été choisi de générer des statistiques moyennes minute par minute, en comptant simplement le nombre de sessions TCP, le nombre de flux RTMP et le nombre d’IP différentes connectées en HTTP. Le nombre réel de clients se situe entre le nombre d’IP sur les flux RTMP/HTTP et le nombre de sessions TCP concurrentes (plusieurs clients peuvent se trouver derrière une même IP). Le nombre réel se situera beaucoup plus proche du nombre de sessions TCP concurrentes que du nombre d’IP connectées (même si avec le HTTP sans chiffrement, les proxies peuvent mettre en cache les chunks HLS).

Évolutions

Notre description technique de la mise en place va s’arrêter ici et laisser la suite des améliorations en exercice au lecteur, surtout pour qu’elles correspondent à ses besoins.

À titre d’exemple, voici ce qui est aussi mis en place ou prévu à terme pour le SSTIC.

Frontaux multiples

La manière la plus simple de mettre en place des frontaux multiples est d’utiliser le mécanisme de round-robin DNS. Cela permet de répartir la bande passante entre les frontaux, mais ne permet par exemple pas de rediriger certains clients de manière préférentielle vers l’un des frontaux. On pourrait imaginer rediriger les clients du FAI Free vers le frontal hébergé chez Online, pour des raisons de peering.

Une autre solution consiste à utiliser le javascript du lecteur HTML5 pour qu’il choisisse un frontal parmi une liste prédéfinie. Soit il le choisit au hasard, soit il le fait selon d’autres critères, dont par exemple celui du peering.

Enfin, les plus fortunés peuvent choisir une solution à base de load-balancer, ou même de CDN en y mettant en cache les chunks HLS.

TLS

La mise en place de SSL pose ses propres soucis. Si les multiples frontaux sont gérés par round-robin DNS, il est alors nécessaire de faire usages de techniques très sales pour partager la clé privée et le certificat serveur entre tous les frontaux, si tant est que l’on n’ait pas de load-balancer gérant le chiffrement.

La solution la moins coûteuse est donc de cumuler l’usage de javascript pour sélectionner un frontal avec des certificats Letsencrypt générés pour chaque serveur frontal.

Relais tiers

La mise en place de relais tiers est en réalité la configuration d’un serveur frontal supplémentaire. La différence principale réside dans le fait que la configuration de l’application hls comprend une directive pull pour aller chercher le flux vidéo vers un serveur source.

Ce serveur source peut être un frontal s’il publie les flux RTMP, ou le serveur de transcodage. Pour éviter d’exposer inutilement le serveur de transcodage à une saturation de bande passante, il n’est pas accessible par les clients finaux et peut du coup garantir à d’autres relais un accès privilégié.

Quelques problèmes à anticiper…

Pour conclure, on laissera une liste de quelques problèmes rencontrés avec les frontaux qui expliquent encore les choix développés dans cette série de billets :

  • timeouts et retries : les flux provenant du serveur de transcodage peuvent être parfois interrompus. C’est pour cette raison qu’ils sont poussés par ce dernier, plutôt que tirés par le serveur frontal. Il retentera la connexion dès l’interruption détectée, plutôt que d’attendre un délai ;
  • peering : certains clients peuvent avoir un FAI qui dispose de liens de peerings saturés vers l’hébergeur de vos serveurs frontaux. Pensez à une solution leur permettant de choisir leur serveur frontal pour limiter les ruptures de flux ;
  • anticipez l’effet slashdot, surtout si vous invitez des orateurs connus. Pour le SSTIC, la capacité en débit a toujours été supérieure au double de la bande passante consommée, permettant de réagir si on constate un dépassement inattendu. Mettre un place un nouveau serveur prend 5 minutes, sans avoir besoin de mettre en place un DNS particulier. Il peut être ajouté instantanément à la liste des serveurs choisissables par le javascript du lecteur HTML5 ;
  • réglez la taille des chunks HLS selon vos contraintes : limiter les hits/s sur vos frontaux, minimiser les délais pour vos clients ou être plus gentils avec la taille de leurs tampons. Référez-vous à la documentation du module nginx RTMP pour la marche à suivre.