Icecast2, работающий под nginx, не может подключиться

Я хочу начать с того, что я искал везде, чтобы найти ответ на эту проблему, и просто кажется, что либо никто больше не сталкивался с этой проблемой, либо никто этим не занимается. Итак, я недавно установил icecast2 на свой сервер Debian. Дело в том, что я полностью могу транслировать на свой сервер из своей локальной сети, подключаясь к его локальному IP-адресу через порт 8000, и слышать поток через Интернет на radio.example.com. так как я проксирую его с помощью nginx, пока вообще никаких проблем. Проблема заключается в том, что я хочу транслировать на домен, который я дал с помощью nginx stream.example.com.

У меня есть две теории: одна заключается в том, что прокси-сервер не передает исходный IP-адрес для icecast, поэтому он думает, что он транслируется с 127.0.0.1, а другая заключается в том, что nginx делает что-то странное с потоком данных и, таким образом, не доставляет правильный формат для ледяной.

Какие-нибудь мысли? Заранее спасибо!

Вот конфиг нгинкс

server {
    listen 80;
    listen [::]:80;
    server_name radio.example.com;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Real-IP $remote_addr;


    location / {
            proxy_pass http://127.0.0.1:8000/radio;
            subs_filter_types application/xspf+xml audio/x-mpegurl audio/x-vclt text/css text/html text/xml;
            subs_filter ':80/' '/' gi;
            subs_filter '@localhost' '@stream.example.com' gi;
            subs_filter 'localhost' $host gi;
            subs_filter 'Mount Point ' $host gi;
    }
}

server {
    listen 80;
    listen [::]:80;
    server_name stream.example.com;

    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Real-IP $remote_addr;
    location / {
            proxy_pass http://localhost:8000/;
            subs_filter_types application/xspf+xml audio/x-mpegurl audio/x-vclt text/css text/html text/xml;
            subs_filter ':8000/' ':80/' gi;
            subs_filter '@localhost' '@stream.example.com' gi;
            subs_filter 'localhost' $host gi;
            subs_filter 'Mount Point ' $host gi;
    }
}

И это то, что я получаю в журнале icecast error.log

[2018-08-10  14:15:45] INFO source/get_next_buffer End of Stream /radio
[2018-08-10  14:15:45] INFO source/source_shutdown Source from 127.0.0.1 at "/radioitavya" exiting

person Oscar H.    schedule 10.08.2018    source источник


Ответы (2)


tl;dr — Не использовать обратный прокси-сервер Icecast.

Icecast по разным причинам лучше не использовать обратное проксирование. Это специально созданный HTTP-сервер, а общие HTTP-серверы, как правило, имеют серьезные проблемы со сложностями непрерывной потоковой передачи HTTP.

На это неоднократно отвечали. Людям все равно нравится пробовать, и они неизменно терпят неудачу по разным причинам.

person TBR    schedule 10.08.2018
comment
Спасибо за ваш ответ, я вижу, что вы на самом деле поддерживаете Icecast, поэтому я уверен, что ваш ответ более чем верен, и я ценю ваши предложения, если честно. Я просто хочу посмотреть, может ли кто-нибудь, достаточно опытный в Nginx, сказать мне, что это невозможно, и если да, то я полностью откажусь от этого, поскольку два эксперта говорят то же самое. Чтобы ответить на ваши предложения: • Я не могу запустить его на 80-м порту напрямую, так как у меня есть сервер nginx, работающий на 80-м, который обслуживает некоторые веб-сайты и некоторые приложения. • Я не получу другой адрес, так как это просто доказательство концепции, а не коммерческий проект. • Спасибо, что напомнили мне об этом! - person Oscar H.; 10.08.2018
comment
Конечно, удачи, но особенно с исходными клиентскими подключениями это будет сложно. Чтобы добавить некоторые ключевые слова, если кто-то хочет попробовать свои силы: запросы PUT или SOURCE (специальный HTTP-глагол!), без длины содержимого, потенциально бесконечное время соединения, PUT, но без фрагментированного кодирования (исправлено для 2.5) и, возможно, некоторые вещи Я не помню. - person TBR; 10.08.2018
comment
Спасибо за ответ, в итоге я открыл еще один порт для потоковой передачи, так как другого решения не нашел. - person Oscar H.; 17.08.2018
comment
Я извиняюсь, но это полная ерунда. Я реверсирую прокси-сервер Icecast через локальный порт 8900 на общедоступный сервер через порт 443, используя SSL через Nginx. Это работает нормально. - person miknik; 19.08.2018
comment
Тот факт, что он работает для вашего простого (узкого) варианта использования, и вы не возражаете против ограничений или не замечаете их, не исключает существования дополнительных проблем и ограничений. Как видно из приведенной выше проблемы (SOURCE не будет работать). ср. wiki.xiph.org/Icecast_Server/known_reverse_proxy_restrictions - person TBR; 19.08.2018
comment
У меня есть 20 ди-джеев, работающих на разных кодировщиках и ОС, которые подключаются и транслируют в прямом эфире без проблем. Мы транслируем несколько разных каналов для нашего веб-сайта, приложения Alexa/iPhone/Android, настройки, vtuner и т. д. IP-адреса слушателя и ди-джея корректно передаются через прокси-сервер для ведения журнала и статистики. Что вы думаете о (широком) сценарии использования Icecast? Чтобы решить проблему SOURCE, Nginx изменит метод проксируемого запроса на PUT и вставит необходимые заголовки запроса, вернет клиенту ответ 200 вместо 100. Ограничения, с которыми сталкивается большинство людей, связаны с их пониманием Nginx, а не с программным обеспечением. - person miknik; 19.08.2018
comment
Может быть, вы хотели бы внести это как правильный ответ, ОП может это оценить. Вы, кажется, вложили в свою установку больше мыслей и особенно работы, чем большинство других людей. Как вы сами говорите, решение некоторых вопросов далеко не тривиально. Делиться заботой. Также мне интересно, так как на Xiph.org мы не знаем, о чем нам не говорят пользователи. - person TBR; 19.08.2018
comment
Да, пожалуйста, приведите пример того, как изменить метод запроса, чтобы поместить и внедрить необходимые заголовки, это будет фантастически, так как я предпочитаю не открывать больше, чем необходимые порты. Я буду очень признателен, кстати, я догадался, что проблема заключалась в моем непонимании nginx, поэтому я буду более чем счастлив, если вы поделитесь со мной этой информацией. - person Oscar H.; 20.08.2018
comment
@miknik привет, мы все еще с нетерпением ждем вашего ответа с подробной информацией о вашей настройке / конфигурации. - person TBR; 07.09.2018
comment
@TBR Надеюсь, это достаточно подробно, чтобы убедить вас, что у меня нет простого (узкого) варианта использования ???? - person miknik; 12.09.2018
comment
@miknik Я только что прочитал ваш комментарий, и мне понравилась идея преобразования запросов GET в PUT. Не могли бы вы указать мне рабочий пример этой настройки с NGINX? В частности, как преобразовать запрос GET в PUT. Спасибо заранее! - person Paul D.; 20.03.2021

Не уверен, насколько это имеет прямое отношение к вопросу ОП, но вот несколько фрагментов из моей конфигурации.

Это основы моего блока для обслуживания потоков клиентов через SSL на порту 443.

В первом блоке местоположения любые запросы с URI, отличным от /ogg, /128, /192 или /320, переписываются, чтобы предотвратить доступ клиентов к каким-либо выходным данным сервера Icecast, кроме самих потоков.

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;
  }
}

Установка proxy_bind с флагом transparent:

позволяет исходящим подключениям к проксируемому серверу исходить с нелокального IP-адреса, например, с реального IP-адреса клиента

Это решает проблемы с локальными IP-адресами в ваших журналах / статистике вместо IP-адресов клиентов, чтобы это работало, вам также необходимо перенастроить таблицы маршрутизации ядра, чтобы захватывать ответы, отправленные с вышестоящего сервера, и перенаправлять их обратно в Nginx.

Для этого требуется root-доступ и разумное понимание сетевой конфигурации Linux, что, я понимаю, есть не у всех. Я также ценю, что не все, кто использует Icecast и может захотеть использовать обратный прокси, прочитают это. Гораздо лучшим решением было бы сделать Icecast более дружественным к Nginx, так что я попробовал.

Я клонировал Icecast с github и просмотрел код. Возможно, я что-то пропустил, но эти строки мне показались актуальными:

./src/logging.c:159:  client->con->ip,
./src/admin.c:700:    xmlNewTextChild(node, NULL, XMLSTR(mode == OMODE_LEGACY ? "IP" : "ip"), XMLSTR(client->con->ip)); 

Для серверов, которые не поддерживают протокол PROXY, Nginx по умолчанию передает IP-адрес клиента вверх по течению через заголовок X-Real-IP. Icecast, похоже, использует значение client->con->ip для регистрации IP-адресов слушателей. Давайте немного изменим ситуацию. Я добавил это:

const char *realip;
realip = httpp_getvar (client->parser, "x-real-ip");
if (realip == NULL)
  realip = client->con->ip;

И изменил предыдущие строки на это:

./src/logging.c:163:  realip,
./src/admin.c:700:    xmlNewTextChild(node, NULL, XMLSTR(mode == OMODE_LEGACY ? "IP" : "ip"), XMLSTR(realip));

затем я собрал Icecast из исходников согласно документации. Директива proxy_set_header X-Real-IP $remote_addr; в моей конфигурации Nginx передает IP-адрес клиента, если у вас есть дополнительные восходящие серверы, также обрабатывающие запрос, вам нужно будет добавить некоторые директивы set_real_ip_from, определяющие каждый IP-адрес, real_ip_recursive on; и использовать $proxy_add_x_forwarded_for;, который будет захватывать IP-адрес каждого сервера, который обрабатывает запрос.

Запустил мою новую сборку Icecast, и она работает отлично. Если установлен заголовок X-Real-IP, Icecast регистрирует его как IP-адрес слушателя, а если нет, то регистрирует IP-адрес запроса клиента, поэтому он должен работать для обратного прокси-сервера и обычных настроек. Кажется слишком простым, может быть, я что-то пропустил @TBR?

Хорошо, теперь у вас должны быть работающие потоки слушателей, обслуживаемые через SSL, с правильной статистикой/журналами. Вы сделали трудную часть. Теперь давайте передадим им что-нибудь!

Поскольку в Nginx добавлен модуль потока, обработка входящих подключений становится простой, независимо от того, используют ли они PUT/SOURCE.

Если вы укажете сервер в директиве потока, Nginx просто туннелирует входящий поток на вышестоящий сервер без проверки или изменения пакетов. Урок 101 по настройке потоков Nginx — это все, что вам нужно:

stream {

  server {
    listen pub.lic.ip:port;
    proxy_pass ice.cast.ip:port;
  }
}

Я предполагаю, что одна проблема, с которой могут столкнуться ничего не подозревающие люди с SOURCE-соединениями в Nginx, заключается в указании неправильного порта в их конфигурации Nginx. Не расстраивайтесь, Shoutcast v1 просто странный. Пункт, который нужно помнить:

  • Вместо порта, который вы указываете в кодировщике клиента, он фактически попытается подключиться к порту +1.

Поэтому, если вы использовали порт 8000 для входящих подключений, либо установите порт на 7999 в клиентских кодировщиках, использующих протокол Shoutcast v1, либо настройте директивы потока Nginx с двумя блоками, один для порта 8000 и один для порта 8001.

Ваша установка Nginx должна быть собрана с модулем потока, он не является частью стандартной сборки. Не уверены? Бежать:

nginx -V 2>&1 | grep -qF -- --with-stream && echo ":)" || echo ":("

Если вы видите смайлик, вы можете идти. Если нет, вам нужно собрать Nginx и включить его. Во многих репозиториях есть пакет nginx-extras, который включает модуль потока.

Почти готово, все, что нам нужно сейчас, это доступ к страницам администратора. Я обслуживаю их из https://example.com/icecast/, но Icecast генерирует все URI в ссылках на страницы администратора, используя корневой путь, не включая icecast/, поэтому они не будут работать. Давайте исправим это, используя модуль подфильтра Nginx, чтобы добавить icecast/ к ссылкам на возвращаемых страницах:

location /icecast/ {
  sub_filter_types text/xhtml text/xml text/css;
  sub_filter 'href="/'  'href="/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/;
}

Косая черта в конце proxy_pass http://ice.cast.ip:port/; жизненно важна для того, чтобы это работало.

Если директива proxy_pass указана так же, как server:port, то полный исходный URI запроса клиента будет добавлен и передан вышестоящему серверу. Если к proxy_pass добавлен какой-либо URI (даже просто /), то Nginx заменит часть URI клиентского запроса, которая соответствует блоку местоположения (в данном случае /icecast/), на URI, добавленный к proxy_pass. Таким образом, добавив косую черту, запрос к https://example.com/icecast/admin/ будет проксирован на http://ice.cast.ip:port/admin/.

Наконец, я не хочу, чтобы мои страницы администратора были доступны для всего мира, только мой IP и локальная сеть, поэтому я также включаю их в расположение выше:

allow 127.0.0.1;
allow 192.168.1.0/24;
allow my.ip.add.ress;
deny all;

Вот и все.

sudo nginx -s reload

Веселиться.

person miknik    schedule 11.09.2018
comment
Ух ты! большое спасибо, я проверю это, когда у меня будет немного времени, действительно спасибо, что нашли время! если это поможет мне заставить его работать так, как задумано, мне придется изменить отмеченный ответ! - person Oscar H.; 25.09.2018
comment
@ОскарХ. Поделитесь своим опытом. Спасибо. - person moonstruck; 02.07.2021