在Nginx下运行的Icecast2无法连接

时间:2018-08-10 12:20:03

标签: nginx stream streaming broadcast icecast

我想开始说,我到处寻找解决这个问题的方法,看来好像没有其他人遇到这个问题或没有人在做。因此,我最近在自己的Debian服务器上安装了icecast2,事实是,我完全可以从连接到端口8000的本地IP的本地网络向服务器广播,并可以通过radio.example.com在Internet上收听流由于我将其与nginx一起使用,因此到目前为止完全没有问题。问题出在我想广播到我用nginx stream.example.com给的域时

我有两种理论,一种是代理没有将源IP提供给icecast,因此它认为它是从127.0.0.1开始广播的,而另一种则是nginx对数据流做了一些奇怪的事情,因此没有传递正确的格式进行冰封。

有什么想法吗?预先感谢!

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

这就是我遇到的错误提示。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

2 个答案:

答案 0 :(得分:1)

tl; dr-不要反向代理Icecast。

出于各种原因,最好不要反向代理广播。这是一个专用HTTP服务器,而通用HTTP服务器往往会遇到连续HTTP流的复杂性的严重问题。

已被反复回答。人们总是喜欢尝试,并且总是以各种方式失败。

答案 1 :(得分:1)

不确定其中有多少与OP的问题直接相关,但这是我的配置中的一些摘要。

这些是我的基本知识,可以通过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更友好,所以我去了。

我从github克隆了Icecast,并查看了代码。我可能已经错过了一些,但是这些行对我来说很相关:

./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协议的服务器,将客户端IP上游传递给Nginx的默认方法是通过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。我的Nginx conf中的proxy_set_header X-Real-IP $remote_addr;指令正在传递客户端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将简单地将传入流隧道传输到上游服务器,而无需检查或修改数据包。 Nginx流配置课程101就是您所需要的:

stream {

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

我想毫无疑问,人们可能会在Nginx中遇到SOURCE连接的一个问题是在其Nginx配置中指定了错误的端口。别难过,Shoutcast v1太奇怪了。要记住的要点是:

  • 代替您在 客户端编码器,它将实际上尝试连接到端口+1

因此,如果您使用端口8000进行传入连接,请使用Shoutcast v1协议在客户端编码器中将端口设置为7999,或者使用2个块设置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将用附加到Proxy_pass的URI替换与位置块(在本例中为/icecast/)匹配的部分客户端请求URI。因此,通过在斜杠后面加上斜杠,将向https://example.com/icecast/admin/的请求被代理到http://ice.cast.ip:port/admin/

最后,我不希望我的管理页面仅对我的IP和LAN可用,因此我也将它们放在上面的位置:

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

就是这样。

sudo nginx -s reload

玩得开心。