重定向循环(err_too_many_redirects)本质是后端误判访问协议,因nginx未透传x-forwarded-proto等关键头导致反复301跳转;需在proxy_pass块中配置proxy_set_header x-forwarded-proto $scheme;并配合host、x-real-ip等头透传,且后端必须信任并解析这些头,必要时用proxy_redirect修正后端返回的绝对跳转地址。

重定向循环(ERR_TOO_MANY_REDIRECTS)本质是后端应用误判了用户真实访问协议,Nginx 作为反向代理没把关键信息传过去,导致后端反复跳转。核心不是 Nginx 自己在跳,而是它转发的请求让后端“以为”自己跑在 HTTP 上,于是拼命 301 到 HTTPS,浏览器再发 HTTPS 请求,Nginx 又转一次——闭环就形成了。
必须透传 X-Forwarded-Proto 头
这是最关键的一行配置,缺了它,90% 的循环问题都解决不了:
- 在 包含 proxy_pass 的 location 块内 添加:
proxy_set_header X-Forwarded-Proto $scheme; -
$scheme会自动取值为http或https,取决于用户直连 Nginx 时用的是哪个协议 - 不要写成
X-Forwarded-Proto https—— 硬编码会让 HTTP 入口也变成 HTTPS,出错 - 如果前面有 CDN(比如 Cloudflare),CDN 可能已经设置了这个头,这时应改用:
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
配套透传 Host 和其他关键头
只传协议不够。后端还需要知道用户访问的真实域名、IP 和端口,否则生成的跳转地址可能指向 localhost 或错误端口:
-
proxy_set_header Host $host;—— 传原始域名,不是上游地址 -
proxy_set_header X-Forwarded-Host $host;—— 辅助后端构造正确 URL -
proxy_set_header X-Real-IP $remote_addr;和X-Forwarded-For $proxy_add_x_forwarded_for; - 如果代理监听非标准端口(如 8443),加一句:
proxy_set_header X-Forwarded-Port $server_port;
后端必须信任并解析这些头
Nginx 传了,后端不认也没用。不同框架启用方式不同:
-
WordPress:在
wp-config.php开头加:if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $_SERVER['HTTPS'] = 'on'; } -
Django:设置
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https'),并开USE_X_FORWARDED_HOST = True -
Spring Boot:配置
server.forward-headers-strategy=framework,或手动加ForwardedHeaderFilter -
Next.js / Express / Flask:需在代码中主动读取
X-Forwarded-Proto判断协议,不能只依赖req.protocol或req.secure
用 proxy_redirect 修正后端返回的绝对跳转地址
即使后端逻辑正确,仍可能返回类似 Location: http://localhost:8080/login 这样的内部地址。Nginx 默认不改写,浏览器就会直连失败或触发二次跳转:
- 基础写法(匹配并替换):
proxy_redirect http://localhost:8080/ $scheme://$host/; - 更通用的正则写法(适配多种后端地址):
proxy_redirect ~^https?://[^/]+(/.*)$ $scheme://$host$1; - 注意:
proxy_redirect必须放在proxy_pass之后才生效 - 如果后端全用相对路径(如
Location: /login),这一步可省略











