301跳转正确使用https需四者协同:最外层强制return 301、中间层干净透传x-forwarded-proto、末端nginx信任该头并跳转、后端启用协议解析。

多级反向代理下,Nginx 本身不“感知”原始协议,而是依赖上游代理逐级透传 X-Forwarded-Proto。301 跳转能否正确使用 HTTPS,关键在于:最外层入口是否强制跳转、中间层是否干净转发、末端 Nginx 是否信任并正确使用该头、后端是否据此生成安全链接——四者缺一不可。
最外层必须用 return 301 强制 HTTP→HTTPS
这是唯一可控的跳转触发点。所有后续代理都不应再做协议跳转,否则极易循环:
- 单独配置
listen 80的 server 块,仅含return 301 https://$host$request_uri; - 绝对不要在
listen 443 ssl块里写任何return 301或rewrite - 确保该 server 块不包含
proxy_pass,它只负责入口重定向
中间层只透传,不改写协议头
每级代理(如 CDN → 边缘 Nginx → 应用网关)都需明确传递原始协议,且不覆盖:
- 统一加:
proxy_set_header X-Forwarded-Proto $scheme; - 禁用硬编码:
proxy_set_header X-Forwarded-Proto "https";是错误做法 - 若某层是透明代理(如云厂商 WAF),需确认其默认透传
X-Forwarded-Proto,否则需联系支持开启
末端 Nginx 必须信任并用于跳转逻辑
当请求最终到达业务 Nginx 时,它要能识别真实协议,并让后端或自身响应正确跳转:
- 用
map提取可信协议值:map $http_x_forwarded_proto $real_scheme {<br> default $scheme;<br> "https" "https";<br> "http" "http";<br>} - 在 location 中判断并跳转(例如登录页强制 HTTPS):
if ($real_scheme = "http") {<br> return 301 https://$host$request_uri;<br>} - 同时配
proxy_redirect重写后端返回的 Location 头,避免内网地址泄露
后端服务必须启用协议解析
即使 Nginx 传了头,后端不认也白搭。常见框架配置示例:
- Spring Boot:
server.forward-headers-strategy=framework+server.tomcat.remoteip.proxies-header=x-forwarded-by - Django:
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") - Next.js:
trustHostHeader: true(v14+)或自定义getServerSideProps判断 - 验证方式:后端日志打印
X-Forwarded-Proto值,确认为https而非空或http











