Cloudflare Tunnel + Nginx 反向代理导致重定向循环的排查与修复

Cloudflare Tunnel + Nginx 反向代理导致重定向循环的排查与修复

背景

最近在维护一个 WordPress 多站点时遇到一个典型的"重定向次数过多"问题。架构是这样的:

  • 主站点 aiwp.pro 通过 Cloudflare Tunnel 连接到服务器
  • 需要将 aiwp.pro 的流量反向代理到同一台服务器上的另一个站点 chimy.cn/aiwp/
  • chimy.cn 是一个 WordPress 子目录型多站点(Multisite)

访问 https://chimy.cn/aiwp/ 时,浏览器直接报错:重定向次数过多

架构速览

整个请求链路如下:

用户 → https://aiwp.pro/
  → Cloudflare 边缘节点(HTTPS 终止)
  → Cloudflare Tunnel(HTTP → localhost:80)
  → Nginx(aiwp.pro 站点配置)
  → proxy_pass → https://chimy.cn/aiwp/
  → Cloudflare(chimy.cn)
  → Nginx(chimy.cn 站点配置)
  → WordPress 多站点

问题排查

第 1 步:检查 Nginx 配置

查看 aiwp.pro 的 Nginx 配置文件 aiwp.pro.conf

#HTTP_TO_HTTPS_START
set $isRedcert 1;
if ($server_port != 443) {
    set $isRedcert 2;
}
if ( $uri ~ /.well-known/ ) {
    set $isRedcert 1;
}
if ($isRedcert != 1) {
    rewrite ^(/.*)$ https://$host$1 permanent;
}
#HTTP_TO_HTTPS_END

这是常见的 HTTP 强制跳转 HTTPS 规则。当 Nginx 在端口 80 收到 HTTP 请求时,返回 301 重定向到 HTTPS 地址。

#PROXY-CONF-START
location ^~ / {
    proxy_pass https://chimy.cn/aiwp/;
    proxy_set_header Host chimy.cn;
    ...
}
#PROXY-CONF-END

反向代理将请求转发到 https://chimy.cn/aiwp/

第 2 步:分析重定向循环

关键问题出在 Cloudflare Tunnel + HTTP 强制跳转 的配合上。

Cloudflare Tunnel 的工作原理:Cloudflare 边缘节点通过 Tunnel 连接到服务器时,始终使用 HTTP(端口 80) 建立连接,即使客户端浏览器使用的是 HTTPS。

于是循环就产生了:

1. 浏览器 → https://aiwp.pro/
2. Cloudflare 边缘节点 → Tunnel → HTTP localhost:80
3. Nginx 收到 HTTP 请求
4. HTTP→HTTPS 跳转规则触发
5. 返回 301 → Location: https://aiwp.pro/
6. Cloudflare 收到 301 重定向
7. 通过 Tunnel 再次以 HTTP 连接 localhost:80
8. Nginx 再次收到 HTTP 请求
9. goto 步骤 4 → 死循环!

浏览器提示"重定向次数过多",正是因为这个循环在持续。

第 3 步:检查 WordPress 配置

继续检查 chimy.cn 的 WordPress 配置,看看是否有其他问题。

wp-config.php 中的关键配置:

define('WP_ALLOW_MULTISITE', true);
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', false);  // 子目录型多站点
define('DOMAIN_CURRENT_SITE', $_SERVER['HTTP_HOST']);
define('PATH_CURRENT_SITE', '/');
define('WP_SITEURL', $protocol . '://' . $_SERVER['HTTP_HOST']);
define('WP_HOME', WP_SITEURL);

站点 URL 是动态根据 HTTP_HOST 请求头设置的。这意味着当反向代理传入 Host: chimy.cn 时,WordPress 会正确地将自身识别为 https://chimy.cn

数据库查询确认 wp_blogs 表中只有主站点(chimy.cn,路径 /),没有 /aiwp/ 子站点记录。这意味着 WordPress 会以主站点来处理 /aiwp/ 路径的请求,而不会触发重定向——所以问题不在 WordPress 这边。

第 4 步:发现问题根源

综合以上分析,根本原因是 Cloudflare Tunnel 的 HTTP 连接与 Nginx 的强制 HTTPS 跳转产生了冲突

另外还发现一个次要问题:proxy_pass https://chimy.cn/aiwp/ 中的 chimy.cn 域名通过 DNS 解析到了 Cloudflare 的 IP,导致代理请求从本机 Nginx 出去后,又经过 Cloudflare 绕回本机,多了一层不必要的网络中转。

解决方案

修复 1:移除 HTTP→HTTPS 强制跳转

由于 Cloudflare 已经在边缘节点处理了 HTTPS 终止,Nginx 不再需要做 HTTP→HTTPS 跳转。直接移除相关规则:

# 修改前
#HTTP_TO_HTTPS_START
set $isRedcert 1;
if ($server_port != 443) {
    set $isRedcert 2;
}
if ( $uri ~ /.well-known/ ) {
    set $isRedcert 1;
}
if ($isRedcert != 1) {
    rewrite ^(/.*)$ https://$host$1 permanent;
}
#HTTP_TO_HTTPS_END

# 修改后
#HTTP_TO_HTTPS_START
# Cloudflare 已处理 HTTPS 终止,无需在此强制跳转
#HTTP_TO_HTTPS_END

修复 2:proxy_pass 直连本地

将代理目标从公共域名改为本地回环地址,绕开 Cloudflare:

# 修改前
proxy_pass https://chimy.cn/aiwp/;

# 修改后
proxy_pass https://127.0.0.1/aiwp/;
proxy_ssl_verify off;

这样代理请求直接走本地回环(loopback),不再经过 Cloudflare,既减少了网络延迟,也避免了潜在的重定向问题。

修复后的配置

location ^~ / {
    proxy_pass https://127.0.0.1/aiwp/;
    proxy_set_header Host chimy.cn;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_ssl_verify off;
    proxy_ssl_server_name on;
    ...
}

最终流量路径

用户 → https://aiwp.pro/
  → Cloudflare 边缘节点(HTTPS 终止)
  → Cloudflare Tunnel(HTTP → localhost:80)
  → Nginx aiwp.pro(无 HTTP→HTTPS 跳转)
  → proxy_pass 直连 127.0.0.1:443
  → Nginx chimy.cn
  → WordPress 多站点

教训与总结

1. Cloudflare Tunnel 的协议理解

Cloudflare Tunnel 始终以 HTTP 连接本地服务,不论客户端使用什么协议。这意味着本地 Nginx 不需要也不能再做协议跳转,否则就会和 Cloudflare 形成循环。

2. 反向代理避免回环

当代理目标域名解析到 Cloudflare IP 时,请求会多一层网络中转。对于同机代理的场景,直接使用 127.0.0.1 本地回环地址是最优选择。

3. 排查思路

面对"重定向次数过多"这类问题,可以按以下步骤排查:

  • 第一步:用 curl -I 测试每个环节的 HTTP 响应头和重定向链
  • 第二步:理清完整的请求链路,检查每一层是否有跳转规则
  • 第三步:关注反向代理和 CDN/Tunnel 的协议交互(HTTP vs HTTPS)
  • 第四步:检查后端应用的 URL 配置是否与代理后的请求 URL 一致

写在最后

Cloudflare Tunnel 是一个很方便的内网穿透工具,但在配合 Nginx 反向代理使用时,需要特别注意 HTTP/HTTPS 协议的处理。Cloudflare 处理了 HTTPS,你的 Nginx 就不要再做 HTTPS 强制跳转了——这听起来简单,但在实际配置中很容易被忽略。

只要理解了这一点,类似的"重定向循环"问题就能迎刃而解了。