Icecast en HTTPS avec Cloudflare et Nginx

Servir une radio Icecast en HTTP depuis une page HTTPS finit toujours par casser quelque chose. Le navigateur bloque le contenu mixte, le lecteur HTML5 refuse parfois le flux, et les appels vers le JSON de statut deviennent capricieux. Bref, la radio marche, mais seulement les jours pairs. Excellent pour le suspense, moins pour l’écoute.

La solution propre consiste à placer Icecast derrière Nginx, puis à laisser Nginx gérer HTTPS avec un certificat valide. Cloudflare reste devant le serveur, le flux sort en HTTPS sur le port standard 443, et Icecast continue tranquillement d’écouter en local sur son port habituel.

Dans ce guide, nous allons donc configurer une architecture simple, fiable et durable :

  • Cloudflare gère le DNS et le proxy HTTPS public ;
  • Nginx reçoit les requêtes HTTPS sur le port 443 ;
  • Nginx transmet les requêtes à Icecast en local ;
  • Icecast reste inaccessible directement depuis Internet ;
  • le lecteur audio peut être intégré sans erreur de contenu mixte.

Cette méthode évite aussi d’exposer une URL du type https://radio.example.com:8443/. Elle fonctionne, certes, mais elle sent un peu le garage ouvert avec la lumière allumée.

Faut-il utiliser le TLS natif d’Icecast ?

Icecast peut gérer HTTPS directement. Les versions récentes utilisent notamment une directive <tls>1</tls> dans le bloc <listen-socket>, avec un certificat configuré dans les chemins d’Icecast.

Cela fonctionne, mais ce n’est pas l’option la plus confortable derrière Cloudflare et Nginx. En pratique, Nginx gère mieux les certificats, les renouvellements, les redirections, les headers, les logs HTTP et les comportements proxy. Il fait ce boulot toute la journée. Autant lui laisser les clés du camion.

Je recommande donc cette architecture :

InternetCloudflareHTTPS :443
NginxHTTP local
Icecast 127.0.0.1:8000Code language: CSS (css)

Icecast reste simple. Nginx fait la terminaison TLS. Cloudflare protège et route le trafic. Tout le monde reste dans son couloir.

Pré-requis

Pour suivre ce guide, il vous faut :

  • un serveur Linux avec Nginx ;
  • Icecast déjà installé et fonctionnel en local ;
  • un domaine géré chez Cloudflare ;
  • un certificat TLS valide côté serveur ;
  • un accès root ou sudo ;
  • un flux Icecast disponible, par exemple /stream.mp3 ou /radio.ogg.

Dans les exemples, j’utilise :

radio.example.com
127.0.0.1:8000
/stream.mp3
/status-json.xsl

Remplacez évidemment ces valeurs par votre domaine, votre port et vos points de montage Icecast.

Étape 1 : créer le sous-domaine dans Cloudflare

Créez un sous-domaine dédié à la radio. C’est plus propre que de mélanger le site principal, les flux audio, les pages d’admin et les fichiers de statut.

Dans Cloudflare, ajoutez un enregistrement DNS :

Type : A
Nom  : radio
IPv4 : 203.0.113.10Code language: CSS (css)

Vous obtenez donc :

radio.example.comCode language: CSS (css)

Vous pouvez activer le proxy Cloudflare, donc le nuage orange, si vous exposez le service sur un port compatible avec Cloudflare. Le port HTTPS standard 443 reste le choix le plus simple.

Cloudflare accepte aussi quelques ports HTTPS alternatifs, dont 8443. Toutefois, pour une radio publique, le port 443 reste plus lisible, plus compatible et plus agréable à partager.

Étape 2 : vérifier qu’Icecast fonctionne en local

Avant d’ajouter Nginx dans l’équation, vérifiez qu’Icecast répond localement :

curl -I http://127.0.0.1:8000/Code language: JavaScript (javascript)

Vous devriez obtenir une réponse Icecast, même si elle n’est pas toujours élégante. L’important est de confirmer que le service écoute bien sur le serveur.

Vérifiez ensuite vos points de montage :

curl -I http://127.0.0.1:8000/stream.mp3
curl -I http://127.0.0.1:8000/status-json.xslCode language: JavaScript (javascript)

Si ces commandes échouent, corrigez Icecast avant de toucher à Nginx. Un reverse proxy ne répare pas un backend cassé. Il le rend juste cassé en HTTPS, ce qui reste une forme de progrès très discutable.

Étape 3 : écouter uniquement en local côté Icecast

Dans une configuration propre, Icecast n’a pas besoin d’écouter publiquement sur toutes les interfaces. Il peut écouter sur 127.0.0.1, puis Nginx se charge de l’accès public.

Ouvrez la configuration Icecast :

sudo nano /etc/icecast2/icecast.xml

Adaptez le bloc <listen-socket> comme ceci :

<listen-socket>
    <port>8000</port>
    <bind-address>127.0.0.1</bind-address>
</listen-socket>Code language: HTML, XML (xml)

Vérifiez aussi la directive <hostname>. Elle doit correspondre au nom public utilisé par les auditeurs :

<hostname>radio.example.com</hostname>Code language: HTML, XML (xml)

Ensuite, testez la syntaxe XML :

sudo xmllint --noout /etc/icecast2/icecast.xml

Si la commande ne retourne rien, c’est bon signe. XML silencieux, sysadmin heureux.

Redémarrez Icecast :

sudo systemctl restart icecast2
sudo systemctl status icecast2 --no-pager

Confirmez ensuite que le port local répond :

ss -ltnp | grep ':8000'
curl -I http://127.0.0.1:8000/Code language: JavaScript (javascript)

Étape 4 : créer le vhost Nginx pour Icecast

Créez un fichier dédié à la radio :

sudo nano /etc/nginx/sites-available/radio.example.com.conf

Ajoutez cette configuration. Elle termine HTTPS côté Nginx, puis proxifie vers Icecast en local.

server {
    listen 80;
    listen [::]:80;

    server_name radio.example.com;

    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    http2 on;

    server_name radio.example.com;

    ssl_certificate     /etc/letsencrypt/live/radio.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/radio.example.com/privkey.pem;

    access_log /var/log/nginx/radio.example.com.access.log;
    error_log  /var/log/nginx/radio.example.com.error.log warn;

    add_header X-Content-Type-Options "nosniff" always;

    location / {
        proxy_pass http://127.0.0.1:8000;

        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;

        proxy_buffering off;
        proxy_request_buffering off;
        proxy_cache off;

        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;

        tcp_nodelay on;
    }
}Code language: PHP (php)

Deux détails comptent ici.

D’abord, proxy_buffering off évite que Nginx tente de bufferiser inutilement un flux audio continu. Pour un flux, on veut transmettre au client au fil de l’eau.

Ensuite, les timeouts longs évitent de couper les auditeurs trop vite. Une radio n’est pas une page HTML. Le client peut rester connecté longtemps, et c’est précisément le but.

Activez le site :

sudo ln -s /etc/nginx/sites-available/radio.example.com.conf /etc/nginx/sites-enabled/radio.example.com.conf

Testez puis rechargez Nginx :

sudo nginx -t
sudo systemctl reload nginx

Étape 5 : installer ou renouveler le certificat TLS

Si vous utilisez Certbot, générez le certificat pour le sous-domaine :

sudo certbot certonly --nginx -d radio.example.comCode language: CSS (css)

Si vous utilisez acme.sh, installez le certificat dans un chemin stable, puis rechargez Nginx après renouvellement :

acme.sh --install-cert -d radio.example.com \
  --key-file /etc/letsencrypt/live/radio.example.com/privkey.pem \
  --fullchain-file /etc/letsencrypt/live/radio.example.com/fullchain.pem \
  --reloadcmd "systemctl reload nginx"Code language: JavaScript (javascript)

Le point important : ne référencez pas directement les fichiers internes de ~/.acme.sh/ dans Nginx. Installez-les dans un chemin de production, puis laissez acme.sh les maintenir.

Après installation, vérifiez Nginx :

sudo nginx -t
sudo systemctl reload nginx

Étape 6 : configurer le pare-feu

Avec cette architecture, le serveur public n’a besoin d’exposer que HTTP et HTTPS. Icecast écoute uniquement sur 127.0.0.1, donc le port 8000 ne doit pas être ouvert publiquement.

Avec UFW :

sudo ufw allow 80/tcp comment "HTTP"
sudo ufw allow 443/tcp comment "HTTPS"
sudo ufw deny 8000/tcp comment "Icecast direct access"Code language: JavaScript (javascript)

Vérifiez l’état du pare-feu :

sudo ufw status verbose

Si vous filtrez les IP Cloudflare au niveau du serveur, appliquez vos règles habituelles sur les ports 80 et 443. Ne laissez pas Icecast ouvert au monde si Nginx sert déjà de frontal.

Étape 7 : tester le flux HTTPS

Testez d’abord la page racine :

curl -I https://radio.example.com/Code language: JavaScript (javascript)

Testez ensuite le flux audio :

curl -I https://radio.example.com/stream.mp3Code language: JavaScript (javascript)

Puis testez le JSON de statut :

curl -I https://radio.example.com/status-json.xslCode language: JavaScript (javascript)

Pour inspecter le certificat TLS :

openssl s_client -connect radio.example.com:443 -servername radio.example.com </dev/nullCode language: JavaScript (javascript)

Enfin, testez dans un navigateur avec votre lecteur HTML5 :

<audio controls preload="none">
    <source src="https://radio.example.com/stream.mp3" type="audio/mpeg">
    Votre navigateur ne supporte pas le lecteur audio HTML5.
</audio>Code language: HTML, XML (xml)

Si la page qui contient le lecteur est en HTTPS, le flux doit aussi être en HTTPS. Sinon, le navigateur risque de bloquer le flux comme contenu mixte.

Étape 8 : ajouter les headers CORS si nécessaire

Si votre lecteur se trouve sur un autre domaine, par exemple www.example.com, alors que le flux vient de radio.example.com, vous pouvez avoir besoin de headers CORS.

Dans Nginx, vous pouvez les ajouter dans le vhost radio :

add_header Access-Control-Allow-Origin "https://www.example.com" always;
add_header Access-Control-Allow-Methods "GET, HEAD, OPTIONS" always;
add_header Access-Control-Allow-Headers "Range" always;Code language: JavaScript (javascript)

Évitez * si vous connaissez le domaine exact du lecteur. C’est plus propre et plus prévisible.

Si vous servez plusieurs domaines légitimes, gérez-les explicitement avec une directive map dans Nginx plutôt que de transformer le serveur en buffet à volonté.

Variante : utiliser Icecast en TLS direct sur le port 8443

Cette variante reste utile si vous ne voulez pas utiliser Nginx comme reverse proxy, ou si vous devez exposer Icecast directement en HTTPS.

Cloudflare supporte le port HTTPS 8443, mais l’URL devra inclure le port :

https://radio.example.com:8443/stream.mp3Code language: JavaScript (javascript)

Dans ce cas, Icecast a besoin d’un fichier PEM contenant à la fois la chaîne de certificats et la clé privée.

Créez un répertoire sécurisé :

sudo install -d -o root -g icecast -m 0750 /etc/icecast2/tls

Créez le bundle :

sudo sh -c 'cat /etc/letsencrypt/live/radio.example.com/fullchain.pem /etc/letsencrypt/live/radio.example.com/privkey.pem > /etc/icecast2/tls/radio.example.com.pem'

sudo chown root:icecast /etc/icecast2/tls/radio.example.com.pem
sudo chmod 0640 /etc/icecast2/tls/radio.example.com.pemCode language: JavaScript (javascript)

Adaptez ensuite Icecast :

<listen-socket>
    <port>8443</port>
    <tls>1</tls>
</listen-socket>

<paths>
    <tls-certificate>/etc/icecast2/tls/radio.example.com.pem</tls-certificate>
</paths>Code language: HTML, XML (xml)

Je ne recommande pas de définir manuellement une longue liste de chiffrements TLS, sauf contrainte précise. Les défauts d’Icecast et d’OpenSSL sont généralement plus faciles à maintenir que des suites cryptographiques copiées d’un vieux tutoriel.

Redémarrez Icecast :

sudo xmllint --noout /etc/icecast2/icecast.xml
sudo systemctl restart icecast2

Si vous utilisez acme.sh, ajoutez une commande de rechargement qui recrée le bundle puis redémarre Icecast après renouvellement :

sudo nano /usr/local/sbin/update-icecast-cert.sh

Contenu du script :

#!/usr/bin/env sh
set -eu

cat \
  /etc/letsencrypt/live/radio.example.com/fullchain.pem \
  /etc/letsencrypt/live/radio.example.com/privkey.pem \
  > /etc/icecast2/tls/radio.example.com.pem

chown root:icecast /etc/icecast2/tls/radio.example.com.pem
chmod 0640 /etc/icecast2/tls/radio.example.com.pem

systemctl restart icecast2Code language: JavaScript (javascript)

Rendez-le exécutable :

sudo chmod 0750 /usr/local/sbin/update-icecast-cert.sh

Puis utilisez ce script comme commande de rechargement lors de l’installation du certificat.

Dépannage : les erreurs fréquentes

Le lecteur HTML5 ne charge pas le flux

Vérifiez d’abord la console du navigateur. Si vous voyez une erreur de contenu mixte, le lecteur charge encore une URL en HTTP.

Corrigez l’URL du flux :

https://radio.example.com/stream.mp3Code language: JavaScript (javascript)

Évitez les URLs absolues en HTTP dans vos templates, shortcodes ou scripts JavaScript.

Cloudflare affiche une erreur 521 ou 522

Cloudflare n’arrive pas à joindre votre serveur. Vérifiez Nginx, le pare-feu et les ports ouverts :

sudo systemctl status nginx --no-pager
sudo nginx -t
sudo ufw status verbose
curl -I http://127.0.0.1:8000/Code language: JavaScript (javascript)

Si vous limitez l’accès aux IP Cloudflare, assurez-vous que votre liste d’IP est à jour.

Cloudflare affiche une erreur 526

L’erreur 526 indique généralement un problème de certificat côté origine lorsque Cloudflare fonctionne en mode strict. Vérifiez que le certificat Nginx correspond bien à radio.example.com.

openssl s_client -connect radio.example.com:443 -servername radio.example.com </dev/nullCode language: JavaScript (javascript)

Le flux coupe après quelques secondes

Vérifiez les timeouts Nginx et désactivez le buffering pour le proxy :

proxy_buffering off;
proxy_request_buffering off;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

Regardez ensuite les logs :

sudo tail -f /var/log/nginx/radio.example.com.error.log
sudo journalctl -u icecast2 -fCode language: JavaScript (javascript)

Le JSON de statut ne fonctionne pas

Testez l’endpoint directement :

curl https://radio.example.com/status-json.xslCode language: JavaScript (javascript)

Si l’appel fonctionne en terminal mais pas dans le navigateur, cherchez une erreur CORS. Ajoutez alors les headers nécessaires dans Nginx, en ciblant le domaine qui héberge votre lecteur.

Checklist de configuration

  • Le sous-domaine radio pointe vers le serveur dans Cloudflare.
  • Le trafic public passe par HTTPS sur le port 443.
  • Nginx possède un certificat valide pour le sous-domaine.
  • Icecast écoute en local sur 127.0.0.1:8000.
  • Le port Icecast n’est pas exposé publiquement.
  • Nginx proxifie vers Icecast avec proxy_buffering off.
  • Le lecteur HTML5 utilise une URL HTTPS.
  • Le JSON de statut répond en HTTPS.
  • Le renouvellement du certificat recharge Nginx automatiquement.

Liens internes utiles

Besoin d’un serveur fiable pour votre site ou vos services web ?

Un flux Icecast, un site WordPress, une boutique WooCommerce ou une stack Nginx propre demandent la même chose : une configuration claire, maintenable et testée. J’aide les entreprises à fiabiliser leur infrastructure web sans empiler les rustines.

  • configuration Nginx, HTTPS, Cloudflare et certificats TLS ;
  • optimisation WordPress et WooCommerce côté performance ;
  • durcissement serveur, logs, sauvegardes et supervision ;
  • correction de problèmes techniques complexes en production.

Vous voulez une configuration propre, documentée et durable ? Contactez-moi et regardons cela ensemble.

FAQ

Peut-on utiliser Icecast en HTTPS sans Nginx ?

Oui. Icecast peut gérer TLS directement avec un certificat PEM contenant la clé privée et le certificat public. Toutefois, derrière Cloudflare, Nginx reste souvent plus pratique pour gérer HTTPS, les logs, les headers, les redirections et les renouvellements.

Faut-il utiliser le port 8443 avec Cloudflare ?

Pas forcément. Cloudflare supporte le port HTTPS 8443, mais le port 443 reste préférable. Il évite d’afficher un port dans l’URL et améliore la compatibilité avec les navigateurs, lecteurs audio, réseaux d’entreprise et applications mobiles.

Pourquoi ne pas exposer directement le port 8000 d’Icecast ?

Parce que Nginx peut servir de frontal HTTPS propre, tandis qu’Icecast reste limité à l’interface locale. Cela réduit la surface exposée, simplifie les certificats et centralise les logs HTTP publics au même endroit.

Cloudflare peut-il mettre en cache un flux Icecast ?

Il ne faut pas compter dessus pour un flux audio continu. Un flux radio doit être transmis en direct, sans cache applicatif classique. Côté Nginx, désactivez aussi le buffering proxy pour éviter les comportements bizarres.

Quel format utiliser pour le lecteur HTML5 ?

MP3 reste le choix le plus compatible. OGG Vorbis reste intéressant pour un format libre, mais tous les environnements clients ne le gèrent pas aussi bien. Si vous voulez limiter les surprises, proposez plusieurs sources dans le lecteur.

Conclusion

Pour servir Icecast en HTTPS derrière Cloudflare, la solution la plus propre consiste à laisser Nginx gérer TLS sur le port 443, puis à proxifier le trafic vers Icecast en local. Vous évitez le contenu mixte, vous gardez une URL simple, et vous centralisez la configuration HTTPS au bon endroit.

Le TLS natif d’Icecast reste possible, notamment sur le port 8443, mais il ajoute souvent plus de maintenance que de bénéfices. Pour une webradio intégrée à un site moderne, Nginx en reverse proxy reste le chemin le plus net.

Sources

Demandez à l'IA son opinion
Gravatar for Matt Biscay

Je suis Matt Biscay, développeur WordPress & WooCommerce certifié chez Codeable, administrateur système et enseignant.

J’aide les entreprises à créer, optimiser et fiabiliser leurs sites WordPress avec une approche technique propre : performance, sécurité, maintenance, développement sur mesure et résolution de problèmes complexes.

Sur Skyminds, je partage des tutoriels WordPress, WooCommerce, Linux et administration système, avec des solutions testées sur des cas réels et pensées pour durer.

Découvrez mes services WordPress et WooCommerce.

Opinions