核心是透传x-forwarded-proto头并确保后端信任:nginx需在proxy_pass前配置proxy_set_header x-forwarded-proto $scheme;,禁用硬编码https;同步设置host、x-real-ip等头,并在后端框架(如django、spring boot)启用对应代理头解析机制。

核心问题是后端应用无法识别用户真实访问协议,误判为 HTTP 并强制跳转 HTTPS,而 Nginx 又在 HTTP 入口做了 301 跳转,形成闭环。修复关键不在“禁用跳转”,而在让后端准确知道“用户确实是走 HTTPS 来的”。
必须透传 X-Forwarded-Proto 头
这是 90% 死循环的根因。Nginx 终止 HTTPS 后以 HTTP 转发给后端,若不告诉后端原始协议,它就永远认为自己跑在 HTTP 上。
- 在 包含 proxy_pass 的 location 块内添加:
proxy_set_header X-Forwarded-Proto $scheme; - 不要写死成
X-Forwarded-Proto https,否则 HTTP 访问也会被当成 HTTPS - 如果前面有 CDN(如 Cloudflare),改用:
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
同步修正 Host 和其他关键头
只传协议不够,后端还需知道用户访问的是哪个域名、来自哪里,否则生成的跳转地址可能指向 localhost 或错误端口。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
-
proxy_set_header Host $host;——传原始域名(不含端口) -
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 -
Node.js / Express:设
app.set('trust proxy', true),再用req.protocol判断
主动重写后端返回的 Location 头
即使后端协议识别正确,仍可能返回 http://localhost:8000/login 这类内网地址。Nginx 需主动拦截并替换:
- 基础写法(已知后端地址):
proxy_redirect http://localhost:8000/ https://$host/; - 推荐通用正则:
proxy_redirect ~^https?://[^/]+(/.*)$ $scheme://$host$1;
→ 自动把任意 http:// 或 https:// 开头的绝对跳转,改成当前协议 + 当前域名 + 路径 - 注意:
proxy_redirect必须放在proxy_pass之后才生效
检查并清理冗余跳转逻辑
避免 Nginx 自身引入额外跳转,尤其要防止和后端行为叠加:
- HTTPS server 块里不要写
return 301 https://...—— 这种跳转只应在 HTTP server 块中做 - 删掉可能冲突的
if ($scheme = http) { rewrite ... }类配置,优先用return 301 - 确认没有多个 location 块相互 redirect,比如
/old → /new又/new → /old










