【博客搭建】Cloudflare Tunnel与Nginx目录重定向冲突
问题现象
我的博客部署在内网机器上,通过 Cloudflare Tunnel 进行内网穿透,将内网地址 172.22.26.185:50001 映射到了外网域名 tianlejin.top。
在测试访问时,有以下现象:
- 内网访问正常:在内网直接访问
http://172.22.26.185:50001/blog/Linux_Clash/或http://172.22.26.185:50001/blog/Linux_Clash(不带末尾斜杠),都能正常打开页面。 - 外网带斜杠访问正常:通过外网域名访问
https://tianlejin.top/blog/Linux_Clash/,页面秒开。 - 外网不带斜杠访问异常:通过外网域名访问
https://tianlejin.top/blog/Linux_Clash(不带末尾斜杠),浏览器会卡住很久,然后地址栏变成了http://tianlejin.top:50001/blog/Linux_Clash/,最终页面显示“tianlejin.top 目前无法处理此请求。HTTP ERROR 502”。
原因分析
这个问题本质上是 Nginx 的目录重定向机制和 Cloudflare 的端口限制共同作用的结果。
1. Nginx 的目录重定向(Trailing Slash Redirect)
当我们在浏览器中访问 https://tianlejin.top/blog/Linux_Clash(末尾没有斜杠)时,Nginx 收到请求后,会在服务器的硬盘上查找这个路径。
Nginx 发现 Linux_Clash 实际上是一个目录(文件夹),而不是一个具体的文件(比如 .html 文件)。为了确保这个目录下的相对路径资源(比如图片、CSS 文件)能够被浏览器正确解析,Nginx 会自动返回一个 301 永久重定向(Moved Permanently) 响应,要求浏览器去访问带斜杠的地址(/blog/Linux_Clash/)。
2. 端口泄露(Port Leakage)
在返回 301 重定向时,Nginx 需要在响应头的 Location 字段中告诉浏览器新的地址。默认情况下,Nginx 拼接这个新地址的规则是:
协议 + 服务器名称 + Nginx 监听的端口号 + 请求的 URI + /
在我的架构中,请求链路是:
外网用户 -> Cloudflare (443端口) -> 内网 Nginx (50001端口)
因为 Nginx 是在本地监听 50001 端口,且位于 Cloudflare Tunnel 之后,它并不知道外网用户是通过 HTTPS (443端口) 访问的。所以,它拼接出来的重定向地址变成了:
http://tianlejin.top:50001/blog/Linux_Clash/
3. Cloudflare 的端口限制导致 502
浏览器收到 Nginx 返回的 301 重定向响应后,会尝试去请求新的地址:http://tianlejin.top:50001/blog/Linux_Clash/。
但是,tianlejin.top 的 DNS 解析是指向 Cloudflare 的。Cloudflare 默认只代理标准的 Web 端口(如 80, 443 等),外网根本无法访问 50001 端口。
因此,浏览器发出的请求一直等不到回应,卡了很久之后最终超时,报出 502 错误。
解决方法
最根本的解决方法是告诉 Nginx:在进行重定向时,不要加上本地的端口号。
这可以通过修改 Nginx 的 port_in_redirect 指令来实现。
- 打开 Nginx 的站点配置文件(我使用的是宝塔面板,可以在“网站” -> “设置” -> “配置文件”中找到)。
- 在对应的
server { ... }块中,添加一行port_in_redirect off;。
修改后的配置大概如下:
1 | server { |
- 保存配置并重载 Nginx:
1 | sudo nginx -s reload |
为什么这样就能解决?
port_in_redirect 的默认值是 on,即 Nginx 在生成重定向 URL 时会带上它自己监听的端口号。
将其设置为 off 后,Nginx 拼接重定向地址的规则变成了:
协议 + 服务器名称 + 请求的 URI + /
这样,Nginx 返回给浏览器的重定向地址就变成了 http://tianlejin.top/blog/Linux_Clash/(没有了 :50001)。浏览器收到这个新地址后,会去请求标准的 80 端口(随后 Cloudflare 会自动将其升级为 443 端口的 HTTPS),请求就能顺利通过 Cloudflare 到达内网服务器,页面也就正常打开了。
总结
在使用反向代理(如 Cloudflare Tunnel、FRP 等)将内网非标准端口映射到外网标准端口时,如果后端使用的是 Nginx,很容易遇到这种因为目录重定向导致的端口泄露问题。记住在 Nginx 配置中加上 port_in_redirect off;,可以避免很多不必要的麻烦。
作者:Copilot + Genimi 3.1 Pro