应动态传递真实协议:proxy_set_header X-Forwarded-Proto $scheme;,避免硬编码https导致混合环境重定向死循环,并配合后端信任解析该头。
直接写死
是常见但危险的做法——它会让所有请求(包括真实 HTTP 请求)都“假装”是 HTTPS,后端无法区分真假,反而更容易触发重定向死循环。真正要解决的不是“加头”,而是“传对头”。
确认 X-Forwarded-Proto 的值是否动态准确
硬编码为
会掩盖协议差异,尤其在混合环境(如本地调试用 HTTP、生产走 HTTPS)、多级代理或 CDN 接入时必然出错。正确做法是让 Nginx 自动反射用户真实访问协议:
用
动态传递:
避免写成
或
若有多级 Nginx(比如 CDN → 边缘 Nginx → 应用 Nginx),下级应读取上级传来的
,而不是覆盖它
检查 Host 头是否被错误透传
Host 头错一个字符,就可能导致后端生成带端口(如
)或错误域名的跳转地址,浏览器再发请求回来,Nginx 又转发,形成套娃循环。
稿定在线PS
PS软件网页版
下载
必须用
(注意是
,不是
)
会原样保留用户请求里的 Host(含端口),例如
,后端可能据此生成
,而该地址不可达
自动剥离端口,只保留规范域名,更安全可靠
排查外部干扰源:CDN 或中间代理
Cloudflare、阿里云全站加速等 CDN 常是隐藏推手。例如:
Cloudflare SSL 模式设为「灵活」→ CDN 用 HTTP 回源到你的 Nginx → 你的 Nginx 却又强制跳 HTTPS → 循环
解决方案:CDN 端改用「完全」或「完全(严格)」模式,并关闭「自动 HTTPS 重写」功能
同时检查宝塔等面板是否残留
规则,即使开关已关,配置文件里也可能还藏着
验证后端是否真正信任转发头
光传头不够,后端必须主动读取并信任这些头。以 WordPress 为例:
仅靠
不足以让
返回 true,需在
中补上逻辑:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {$_SERVER['HTTPS'] = 'on';}
其他框架(如 Spring Boot)需启用
并设置
proxy_set_header X-Forwarded-Proto httpshttps$schemeproxy_set_header X-Forwarded-Proto $scheme;proxy_set_header X-Forwarded-Proto https;http;$http_x_forwarded_proto:8080proxy_set_header Host $host;$host$http_host$http_hostexample.com:443https://example.com:443/login$hostreturn 301 https://X-Forwarded-Protois_ssl()wp-config.phpForwardedHeaderFilterserver.forward-headers-strategy=framework