Je ne sais pas si cela a un rapport direct avec la question de l'OP, mais voici quelques extraits de ma configuration.
Ce sont les bases de mon bloc pour servir des flux aux clients via SSL sur le port 443.
Dans le premier bloc de localisation, toutes les requêtes dont l'URI est différent de /ogg, /128, /192 ou /320 sont réécrites pour empêcher les clients d'accéder à toute sortie du serveur Icecast autre que les flux eux-mêmes.
server {
listen 443 ssl http2;
server_name stream.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
rewrite ~*(ogg) https://stream.example.com/ogg last;
rewrite ~*([0-1][0-5]\d) https://stream.example.com/128 last;
rewrite ~*(?|([1][6-9]\d)|([2]\d\d)) https://stream.example.com/192 last;
rewrite ~*([3-9]\d\d) https://stream.example.com/320 break;
return https://stream.example.com/320;
}
location ~ ^/(ogg|128|192|320)$ {
proxy_bind $remote_addr transparent;
set $stream_url http://192.168.100.100:8900/$1;
types { }
default_type audio/mpeg;
proxy_pass_request_headers on;
proxy_set_header Access-Control-Allow-Origin *;
proxy_set_header Host $host;
proxy_set_header Range bytes=0-;
proxy_set_header X-Real-IP $remote_addr;
proxy_buffering off;
tcp_nodelay on;
proxy_pass $stream_url;
}
}
Réglage de proxy_bind
avec le transparent
drapeau :
permet aux connexions sortantes vers un serveur proxié de provenir d'une adresse IP non locale, par exemple, l'adresse IP réelle d'un client.
Cela résout le problème des adresses IP locales dans vos journaux/stats au lieu des IP des clients. Pour que cela fonctionne, vous devez également reconfigurer vos tables de routage du noyau pour capturer les réponses envoyées par le serveur en amont et les renvoyer à Nginx.
Cela nécessite un accès Root et une compréhension raisonnable de la configuration des réseaux Linux, ce qui n'est pas le cas de tout le monde. Je me rends également compte que tous ceux qui utilisent Icecast et qui pourraient vouloir utiliser un proxy inverse ne liront pas cet article. Une bien meilleure solution serait de rendre Icecast plus convivial pour Nginx, alors j'ai essayé.
J'ai cloné Icecast depuis github et j'ai jeté un coup d'oeil au code. J'ai peut-être raté quelque chose, mais ces lignes m'ont semblé pertinentes :
./src/logging.c:159: client->con->ip,
./src/admin.c:700: xmlNewTextChild(node, NULL, XMLSTR(mode == OMODE_LEGACY ? "IP" : "ip"), XMLSTR(client->con->ip));
Pour les serveurs qui ne prennent pas en charge le protocole PROXY, la méthode par défaut de Nginx pour transmettre l'IP du client en amont est via le paramètre X-Real-IP
en-tête. Icecast semble utiliser la valeur de client->con->ip
pour la journalisation des IP des auditeurs. Changeons un peu les choses. J'ai ajouté ceci :
const char *realip;
realip = httpp_getvar (client->parser, "x-real-ip");
if (realip == NULL)
realip = client->con->ip;
Et j'ai changé les lignes précédentes en ceci :
./src/logging.c:163: realip,
./src/admin.c:700: xmlNewTextChild(node, NULL, XMLSTR(mode == OMODE_LEGACY ? "IP" : "ip"), XMLSTR(realip));
puis j'ai construit Icecast à partir des sources comme indiqué dans la documentation. Le site proxy_set_header X-Real-IP $remote_addr;
dans mon fichier de configuration de Nginx transmet l'adresse IP du client, si vous avez d'autres serveurs en amont qui traitent également la demande, vous devrez ajouter des directives de type set_real_ip_from
spécifiant chaque IP, real_ip_recursive on;
et utiliser le $proxy_add_x_forwarded_for;
qui capturera l'adresse IP de chaque serveur qui traite la demande.
J'ai mis en route ma nouvelle version d'Icecast et cela semble fonctionner parfaitement. Si le X-Real-IP
est défini, Icecast l'enregistre comme l'adresse IP de l'écouteur et, dans le cas contraire, il enregistre l'adresse IP de la demande du client. Cela devrait donc fonctionner pour les configurations normales et les proxy inversés. Cela semble trop simple, peut-être ai-je manqué quelque chose @TBR ?
OK, vous devriez maintenant avoir des flux d'auditeurs fonctionnels servis par SSL avec des statistiques/logs corrects. Vous avez fait le plus dur. Maintenant, diffusons quelque chose vers eux !
Depuis l'ajout du module stream à Nginx, la gestion des connexions entrantes est simple, qu'elles utilisent ou non PUT/SOURCE.
Si vous spécifiez un serveur dans une directive de flux, Nginx tunnelise simplement le flux entrant vers le serveur en amont sans inspecter ou modifier les paquets. La leçon 101 de la configuration des flux de Nginx est tout ce dont vous avez besoin :
stream {
server {
listen pub.lic.ip:port;
proxy_pass ice.cast.ip:port;
}
}
Je pense que l'un des problèmes que les personnes peu méfiantes peuvent rencontrer avec les connexions SOURCE dans Nginx est de spécifier le mauvais port dans leur configuration Nginx. Ne vous sentez pas mal, Shoutcast v1 est simplement bizarre. Le point à retenir est le suivant :
- Au lieu du port que vous spécifiez dans l'option l'encodeur du client, il tentera en fait de se connecter au port+1
Ainsi, si vous utilisiez le port 8000 pour les connexions entrantes, définissez le port à 7999 dans les encodeurs clients utilisant le protocole Shoutcast v1, ou configurez vos directives de flux Nginx avec 2 blocs, un pour le port 8000 et un pour le port 8001.
Votre installation Nginx doit être construite avec le module stream, il ne fait pas partie de la construction standard. Vous n'êtes pas sûr ? Exécutez :
nginx -V 2>&1 | grep -qF -- --with-stream && echo ":)" || echo ":("
Si vous voyez un visage souriant, vous êtes prêt à partir. Sinon, vous devrez construire Nginx et l'inclure. De nombreux dépôts ont un nginx-extras
qui inclut le module stream.
Presque terminé, tout ce dont nous avons besoin maintenant est l'accès aux pages d'administration. Je les sers à partir de https://example.com/icecast/
mais Icecast génère tous les URI dans les liens de la page d'administration en utilisant le chemin d'accès Root, à l'exception des éléments suivants icecast/
donc ils ne fonctionneront pas. Réparons cela en utilisant le module de sous-filtre de Nginx pour ajouter icecast/
aux liens dans les pages retournées :
location /icecast/ {
sub_filter_types text/xhtml text/xml text/css;
sub_filter 'href="http://stackoverflow.com/' 'href="http://stackoverflow.com/icecast/';
sub_filter 'url(/' 'url(/icecast/';
sub_filter_once off;
sub_filter_last_modified on;
proxy_set_header Accept-Encoding "";
proxy_pass http://ice.cast.ip:port/;
}
La barre oblique à la fin de proxy_pass http://ice.cast.ip:port/;
est d'une importance vitale pour que cela fonctionne.
Si une directive proxy_pass est spécifiée comme server:port, l'URI complet de la requête du client sera ajouté et transmis au serveur en amont. Si le proxy_pass comporte un URI ajouté (même simplement /
), Nginx remplacera la partie de l'URI de la requête du client qui correspond au bloc d'emplacement (dans ce cas, il s'agit de /icecast/
) avec l'URI ajouté au proxy_pass. Ainsi, en ajoutant un slash, une requête à https://example.com/icecast/admin/
sera transmis par procuration à http://ice.cast.ip:port/admin/
Enfin, je ne veux pas que mes pages d'administration soient accessibles au monde entier, mais seulement à mon IP et au réseau local, c'est pourquoi je les inclus également dans l'emplacement ci-dessus :
allow 127.0.0.1;
allow 192.168.1.0/24;
allow my.ip.add.ress;
deny all;
C'est tout.
sudo nginx -s reload
Amusez-vous bien.