Icecast2 运行 在 nginx 下无法连接

Icecast2 running under nginx not able to connect

我想开始说,我已经到处寻找这个问题的答案,但似乎没有其他人 运行 解决这个问题,或者没有人在做。所以,我最近在我的 Debian 服务器上安装了 icecast2,事情是我完全能够从我的本地网络广播到我的服务器,连接到端口 8000 上的本地 IP,并通过互联网在 radio.example.com 上收听流因为我用 nginx 代理它,所以到目前为止完全没有问题。问题出在我想广播到我用 nginx stream.example.com

提供的域时

我有两个理论,一个是代理没有将源 IP 提供给 icecast,因此它认为它是从 127.0.0.1 广播的,另一个是 nginx 正在做一些 st运行ge数据流,因此没有向 icecast 提供正确的格式。

有什么想法吗?提前致谢!

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

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

出于各种原因,Icecast 最好不要反向代理。它是专门构建的 HTTP 服务器,而通用 HTTP 服务器往往会在复杂的连续 HTTP 流传输方面出现重大问题。

已多次回答。人们无论如何都喜欢尝试,总是以各种方式失败。

不确定其中有多少与 OP 的问题直接相关,但这里有一些来自我的配置的片段。

这些是我的块的基础知识,用于在端口 443 上通过 SSL 向客户端提供流。

在第一个位置块中,任何 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/;
    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;
  }
}

使用 transparent 标志设置 proxy_bind

allows outgoing connections to a proxied server originate from a non-local IP address, for example, from a real IP address of a client

这解决了 logs/stats 中本地 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 协议的服务器,Nginx 向上游传递客户端 IP 的默认方法是通过 X-Real-IP header。 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 header 被设置,那么 Icecast 将其记录为监听器 IP,如果没有,则它记录客户端请求 IP,因此它应该适用于反向代理和正常设置。似乎太简单了,也许我错过了什么@TBR?

好的,现在您应该可以使用正确的 stats/logs 通过 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/; 末尾的斜杠对于此工作至关重要。

如果像 server:port 一样指定了 proxy_pass 指令,那么完整的原始客户端请求 URI 将被附加并传递到上游服务器。如果 proxy_pass 附加了任何 URI(即使只是 /),那么 Nginx 将用附加的 URI 替换客户端请求 URI 中与位置块(在本例中为 /icecast/)匹配的部分到 proxy_pass。因此,通过附加斜线,对 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

玩得开心。

这一行....

subs_filter '@localhost' '@stream.example.com' gi;

应该是....

subs_filter '@localhost' '@example.com' gi;

我不熟悉 nginx,所以我最好的猜测是这条线将 radio.example.com 链接到 example.com 的主站点。添加 stream.example.com 会将其定向到不存在的站点,从而造成混淆。

我从配置文件中得到这个 posted here:

反正试试也无妨