根本原因是后端未识别真实协议,需在Nginx中配置proxy_set_header X-Forwarded-Proto $scheme;并启用后端对应解析逻辑(如Spring Boot设server.forward-headers-strategy=framework),同时正确透传Host头、合理使用proxy_redirect处理绝对重定向URL。
后端误判
导致跳转到 http:// 而不是 https://
典型现象是:用户访问
,后端却返回
,浏览器被重定向到 HTTP 地址,接着又被 Nginx 强制 301 到 HTTPS,形成死循环。根本原因是后端(如 Spring Boot、Next.js、Django)没识别出真实协议,只看
或
,而它读到的是反向代理传过去的原始值(常为
),不是用户实际用的
。
必须让后端能区分真实协议:
—— 这行不能少,且必须写在
块里、
之后
后端应用需启用对应解析逻辑:Spring Boot 要设
;Next.js 需在
或
中检查
;Django 要开
避免同时设置
(硬编码),否则多层代理或 HTTP 入口时会出错
无法覆盖绝对 URL 重定向时的兜底方案
即使后端已正确识别协议,仍可能返回形如
的绝对地址——Nginx 默认不改写这类响应头,导致客户端跳转失败或绕过代理。
用
显式重写:
匹配并替换完整协议+主机+端口:
更健壮的正则写法(适配多种后端地址):
注意顺序:
必须放在
之后,否则不生效
若后端返回的是相对路径(如
),默认行为已足够,无需额外配置
Host 头透传错误引发的二次代理循环
现象是 Nginx 日志中出现大量重复的
IP、请求耗时飙升、最终返回
或
。本质是后端把 Nginx 当作普通客户端,又把请求打回给 Nginx 自己,形成套娃。
Nginx
在宝塔面板中轻松管理Nginx高性能Web服务器。提供可视化配置反向代理、负载均衡、SSL证书及HTTP缓存功能,一键优化高并发性能,助您高效搭建稳定、快速的网站运行环境。
下载
关键点在
请求头处理:
不要写
—— 它会把用户原始 Host(如
)传给后端,后端生成跳转 URL 时可能带错端口
应改为
(不含端口)或更稳妥的
(即 upstream 的 Host)
如果后端依赖 Host 做路由(如多租户 SaaS),可显式写死:
配合
,供后端做辅助判断
非根路径代理(如
)下跳转路径错位
例如 Nginx 配置
,后端返回
,结果浏览器跳转到
(丢了
前缀),404。
这不是协议问题,而是路径上下文丢失:
后端需配置基础路径(base URL),如 Next.js 的
,Spring Boot 的
若后端无法改,可用
补救:
(把所有相对路径重写为带前缀)
注意
末尾斜杠:写成
才会剥离
;写成
会保留,后端收到
避免混用:不要一边靠后端拼路径,一边靠 Nginx 重写,容易冲突
最易被忽略的是
和
头的组合效果——单独设对一个没用,两个都错才爆雷;而日志里往往只显示最终跳转结果,看不到中间哪一层改写了哪个头。建议用
抓响应头,再对照 Nginx access log 确认每段代理是否真传了预期的头。
$schemehttps://example.com/loginLocation: http://example.com/dashboardrequest.schemereq.protocolhttphttpsproxy_set_header X-Forwarded-Proto $scheme;locationproxy_passserver.forward-headers-strategy=frameworkgetServerSidePropsheaders()X-Forwarded-ProtoSECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')proxy_set_header X-Forwarded-Proto https;proxy_redirectLocation: https://localhost:8080/finishproxy_redirectproxy_redirect https://localhost:8080/ $scheme://$host/;proxy_redirect ~^https?://[^/]+(/.*)$ $scheme://$host$1;proxy_redirectproxy_passLocation: /loginX-Forwarded-For413 Request Entity Too Large500 Internal Redirection CycleHostproxy_set_header Host $http_host;example.com:8443proxy_set_header Host $host;proxy_set_header Host $proxy_host;proxy_set_header Host backend.example.com;proxy_set_header X-Forwarded-Host $host;/admin/location /admin/ { proxy_pass http://127.0.0.1:3000/; }Location: /dashboardhttps://example.com/dashboard/adminbasePath: '/admin'server.servlet.context-path=/adminproxy_redirectproxy_redirect / /admin/;proxy_passhttp://127.0.0.1:3000//admin/http://127.0.0.1:3000/admin/loginX-Forwarded-ProtoHostcurl -v