Назад | Перейти на главную страницу

icecast и apache на одном порту (mod_proxy, mod_rewrite)

У меня есть сервер icecast, работающий на порту 8000. Я могу получить доступ к серверу как LINK1 (см. Ниже) из Интернета. Кроме того, я создал небольшую HTML-страницу с некоторой информацией, которая также включает аудиоплеер HTML5. Работает нормально при доступе как http host dot domain dot com.

<html>
    <head>
        <title>Radio</title>
    </head>
    <body>
        <p>Some text</p>
        <audio controls>
          <source src="LINK1" type="audio/ogg">
        </audio>
    </body>
</html>

Проблема в том, что если порт 8000 заблокирован на компьютере слушателей, они не смогут слышать поток. Итак, я попытался использовать mod_proxy и mod_rewrite, но безрезультатно. Если я использую приведенную ниже конфигурацию, я могу обойти порт 8000, и поток будет нормально передаваться на порт 80, но http host dot domain dot com показывает только аудиоплеер, а не всю HTML-страницу. Я пробовал разные комбинации и гуглил, но не могу понять.

Мой вопрос в том, является ли это жизнеспособным решением. Имея Apache на 80 и icecast 8000, проксирующие через один и тот же порт? Может быть, мне нужны два IP-адреса? Какова правильная конфигурация, если я использую два IP-адреса. Вот моя конфигурация виртуального хоста Apache.

ProxyRequests Off
ProxyPass / LINK1
ProxyPassReverse / LINK1
#RewriteEngine On
#RewriteRule ^/mount\.ogg$ LINK2 [P]

Имейте в виду, что файл mount.ogg не существует. Это просто точка монтирования ледяного покрова.

==> Размещение ссылок здесь (требуется не менее 10 репутации) LINK1: http://host.domain.com:8000/mount.ogg LINK2: http://host.domain.com/mount.ogg

Спасибо

Я не хотел выбирать между Icecast, работающим на порту 80, и всеми моими виртуальными хостами Apache, работающими также на порту 80, на моем единственном внешнем IP-адресе.

Я также не хотел открывать порт 8000 на моем брандмауэре, потому что хотел, чтобы все пользователи могли получить доступ к Icecast, даже те, которые находятся за корпоративными брандмауэрами.

Итак, мне удалось запустить Apache 2.2, прослушивающий порт 80, и Icecast 2.4.1, прослушивающий порт 8000 на одном и том же хосте.

Я добавил новый виртуальный хост radio.domain.com (прослушивает порт 80), который направляет трафик Icecast на / от локального сервера Icecast (прослушивает порт 8000):

<VirtualHost *:80>
    ServerName radio.domain.com
    ServerAdmin hostmaster@domain.com
    ProxyPreserveHost On
    ProxyPass / http://localhost:8000/
    ProxyPassReverse / http://localhost:8000/
</VirtualHost>

Затем я смог подключить аудиоклиенты, такие как VLC / Winamp, к точкам монтирования Icecast, используя такие адреса, как http://radio.domain.com/my_stream.

Однако при подключении к виртуальному хосту Icecast http://radio.domain.com/ веб-страница, файлы m3u и xspf, где по-прежнему отображается URL http://radio.domain.com:8000/my_stream с этим надоедливым портом 8000. Затем люди, загружающие эти файлы, не могли подключиться к серверу Icecast, потому что они пытались подключиться не к тому порту. То же самое происходило с обновлениями YP на dir.xiph.org.

Затем я загрузил исходный код Icecast 2.4.1 и изменил его, добавив новую опцию:

<exposed-port>80</exposed-port>

Вы можете найти этот патч на https://damiengarrido.wordpress.com/2015/03/22/icecast-reachable-behind-reverse-proxy/

Если нужно, я могу вставить сюда патч.

Мне удалось найти решение (частичное), используя два виртуальных хоста. Для слушателей, которые могут получить доступ к порту 8000, конфигурация остается такой же, как указано выше, за исключением директив прокси. Но на странице HTML для первого виртуального хоста я добавил ссылку для открытия нового окна, которое указывает на 2-й виртуальный хост, на котором я использую ProxyReverse. Итак, HTML-файл для 1-го виртуального хоста

<audio controls>
    <source src="LINK1" type="audio/ogg">
</audio>
<a href="/"  onclick="window.open('LINK3', 'newwindow','width=300, height=100'); return false;"> No audio?</a>

где LINK3 - ссылка на второй виртуальный хост, например. host2 точка домен точка com косая черта

И затем конфигурация этого 2-го виртуального хоста фактически выполняет обратный прокси-сервер.

ProxyRequests Off
ProxyPass / LINK1
ProxyPassReverse / LINK1

Возможно, я могу использовать кадр в 1 пиксель и указать там ссылку, но меня тоже устраивает это решение.

Спасибо

Предпочтительно, чтобы Icecast слушал напрямую порт 80, в конце концов, это HTTP-сервер.

Обратное проксирование не рекомендуется по многим причинам.

  • много долгоживущих соединений, если они не настроены правильно, выйдет из строя apache
  • некоторые унаследованные функции (ИСТОЧНИК, СТАТИСТИКА) недоступны, доступны только через простой HTTP в 2.4.1 и будущих версиях Icecast
  • код сообщения публичного каталога YP не может быть уведомлен обратным прокси, это нарушит списки
  • веб-интерфейс и сгенерированные списки воспроизведения, по крайней мере, нелегко получить правильно

Подводя итог, можно сказать, что если вы работаете над производственной настройкой и являетесь профессионалом, который точно знает, что они делают, это возможно, но непросто. Если вы просто случайно думаете: «О, эй, давайте просто отменим прокси, как и все остальное», то вас ждет некоторая боль.

Получите дополнительный IP, заставьте Icecast прослушивать порт 80, просто.

У меня была такая же проблема с объединением моей домашней страницы index.php, которая работает на порту 443 в apache2 в Ubuntu 16.04. Я хотел использовать свою собственную веб-страницу и передать «скрипт» музыкального потока (без ssl) и того, что сейчас воспроизводится (также без ssl). Происходило то, что все могло работать через порт 80, но когда я переключился на порт 443, браузеры (особенно Chrome) блокировали мои «небезопасные скрипты», и звук не воспроизводился.

Итак, поискав по всему Интернету и обнаружив это, но не узнав, как это сделать, я наконец понял!

Вот моя установка для заинтересованных:

  1. Icecast 2.4.3 на Windows, работающий на порту 8080
  2. Ubuntu 16.04 LTS работает на Oracle VirtualBox с почти 20 веб-сайтами
  3. Я использую MediaMonkey 4.1.16 и подключаемый модуль edcast для подключения к Icecast.

Файл конфигурации Apache2:

<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName radio.domain.com
DocumentRoot /var/www/radio.domain.com

<Directory /var/www/radio.domain.com>
    Options Indexes FollowSymLinks MultiViews
    Order allow,deny
    allow from all
</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLCertificateFile /etc/letsencrypt/live/radio.domain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/radio.domain.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf

Options -Includes -ExecCGI
RewriteEngine On
RewriteCond %{THE_REQUEST} !HTTP/1.1$
RewriteRule .* - [F]

LimitRequestBody 512000
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"
Header always set X-Frame-Options DENY

FileETag None
TraceEnable off
Header set X-XSS-Protection "1; mode=block"
Timeout 60

<Proxy *>
    Order deny,allow
    Allow from all
</Proxy>

ProxyRequests Off
ProxyPreserveHost On
SSLProxyEngine On
RequestHeader set Front-End-Https "On"

ProxyPass /stream http://192.168.1.2:8080/stream #IP and port of local computer on same network
ProxyPassReverse /stream http://192.168.1.2:8080/stream #IP and port of local computer on same network
ProxyPass /np.xsl http://192.168.1.2:8080/np.xsl #np.xsl is a file that I call using ajax from my index.php page to get the track currently playing
ProxyPassReverse /np.xsl http://192.168.1.2:8080/np.xsl #np.xsl is a file that I call using ajax from my index.php page to get the track currently playing

</VirtualHost>
</IfModule>

Мой файл np.xsl (в каталоге Icecast "web"):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output omit-xml-declaration="yes" method="text" indent="no" media-type="text/javascript" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/icestats">
parseMusic({
    <xsl:for-each select="source">"<xsl:value-of select="@mount"/>":{
        "server_name":"<xsl:value-of select="server_name"/>",
        "title":"<xsl:if test="artist"><xsl:value-of select="artist" /> - </xsl:if><xsl:value-of select="title" />",
        "bitrate":"<xsl:value-of select="bitrate" />"}
    <xsl:if test="position() != last()"><xsl:text>,</xsl:text>
    </xsl:if>
</xsl:for-each>});
</xsl:template>
</xsl:stylesheet>

Моя страница index.php:

<!DOCTYPE html>
<html>
<head>
    <link rel="icon" href="favicon.ico" type="image/x-icon">
    <link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
    <title id="track-title"></title>
    <style>
        html{width:100%;}
        body{background-color:#bfbfbf; text-align:center; font-family:Helvetica;}
        #wrapper{position:absolute; max-width:550px; left:50%; transform:translate(-50%,0); -ms-transform:translate(-50%,0); -webkit-transform:translate(-50%,0); margin-right:-50%; text-align:center; box-shadow:1px 1px 20px 5px #4d4d4d;}
    </style>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    <script>
    function updateTitle() {
    $.ajax({
            type: 'GET',
            url: 'https://radio.domain.com/np.xsl',
            jsonpCallback: 'parseMusic',
            dataType: 'jsonp'
    }).then(function (data) {
            var $track = $('#track-title').text(data['/stream'].title);
            var text = $track.text();
            $track.text(text.replace(" - MediaMonkey",""));
    }).fail(function (e) {
            console.log(e);
    }).always(function () {
            setTimeout(updateTitle, 5000);
    });
    }
    $(updateTitle);
    function updateTitle2() {
    $.ajax({
            type: 'GET',
            url: 'https://radio.domain.com/np.xsl',
            jsonpCallback: 'parseMusic',
            dataType: 'jsonp'
    }).then(function (data) {
            var $track = $('#track-title2').text(data['/stream'].title);
            var text = $track.text();
            $track.text(text.replace(" - MediaMonkey",""));
    }).fail(function (e) {
            console.log(e);
    }).always(function () {
            setTimeout(updateTitle2, 5000);
    });
    }
    $(updateTitle2);
    </script>
</head>
<body>
    <div id="wrapper">
    <h2>Live Radio</h2></br>
    <h4><span id="track-title2"></span></h4></br></br>
    <audio controls src="https://radio.domain.com/stream" type="audio/mp3"></audio><br></br>
    </div>
</body>
</html>

Наконец, мой код icecast.xml:

<icecast>
<location>Minneapolips, MN</location>
<admin>info@radio.domain.com</admin>
<hostname>radio.domain.com</hostname>
<limits>
    <clients>50</clients>
    <sources>1</sources>
    <queue-size>524288</queue-size>
    <client-timeout>30</client-timeout>
    <header-timeout>15</header-timeout>
    <source-timeout>10</source-timeout>
    <burst-on-connect>1</burst-on-connect>
    <burst-size>65535</burst-size>
</limits>
<authentication>
    <source-password>hackme</source-password>
    <relay-password>hackme</relay-password>
    <admin-user>admin</admin-user>
    <admin-password>hackmemore</admin-password>
</authentication>
<listen-socket>
    <port>8080</port>
    <shoutcast-mount>/stream</shoutcast-mount>
</listen-socket>
<http-headers>
    <header name="Access-Control-Allow-Origin" value="*" />
</http-headers>
<fileserve>1</fileserve>
<paths>
    <logdir>./log</logdir>
    <webroot>./web</webroot>
    <adminroot>./admin</adminroot>
    <alias source="/" destination="/status.xsl"/>
</paths>

<logging>
    <accesslog>access.log</accesslog>
    <errorlog>error.log</errorlog>
    <loglevel>4</loglevel> <!-- 4 Debug, 3 Info, 2 Warn, 1 Error -->
    <logsize>10000</logsize> <!-- Max size of a logfile -->
</logging>
</icecast>

И как это выглядит: радио