关键不是“传递协议头”,而是让后端可信地知道原始请求是 https;前端 nginx 必须在 https server 块中设 proxy_set_header x-forwarded-proto $scheme;,后端仅信任来自可信代理的该头,并通过 realip 模块校验 ip 与协议,应用层需显式启用对 x-forwarded-proto 的信任。

关键不是“传递协议头”,而是让后端**可信地知道原始请求是 HTTPS**。Nginx 本身不加密头,安全传递的核心在于:前端 Nginx 显式设置 X-Forwarded-Proto,后端 Nginx 或应用只从可信代理来源读取该头,并忽略客户端可能伪造的值。
前端 Nginx(SSL 终结点)必须设 X-Forwarded-Proto
在处理 HTTPS 请求的 server 块的 location 中,添加:
-
proxy_set_header X-Forwarded-Proto $scheme;—— 此时$scheme恒为https,确保源头可信 - 同时建议补全其他关键头:
proxy_set_header Host $host;、proxy_set_header X-Real-IP $remote_addr;、proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - 不要用
rewrite或动态拼接,避免因变量为空或被污染导致传错值
后端 Nginx(或最终接入层)需限制可信源并校验头
仅靠 header 不安全。若后端也跑在 Nginx 上,必须启用 http_realip_module 并配置:
-
set_real_ip_from 192.168.5.10;—— 填写前端 Nginx 的真实出口 IP(或内网网段) -
real_ip_header X-Real-IP;—— 优先用更简洁可控的头做 IP 校验(非 X-Forwarded-For) -
real_ip_recursive on;—— 启用递归解析,自动剔除已知代理 IP,保留最左真实客户端 IP - 后端应用应读取经 realip 模块处理后的
$remote_addr和X-Forwarded-Proto,而非原始请求头
多级代理中禁止中间层篡改或覆盖 X-Forwarded-Proto
二级、三级内网 Nginx 只负责转发,不能自行设置 X-Forwarded-Proto:
- 若中间层
$scheme是http(比如走内网 HTTP),却写了proxy_set_header X-Forwarded-Proto $scheme;,就会把 https 请求降级为 http 透传 - 正确做法:中间层只做干净转发,保留上游已设好的
X-Forwarded-Proto,不重设、不覆盖 - 末端代理可退而求其次:
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;,直接继承链路上传来的值
后端应用必须主动读取并信任 X-Forwarded-Proto
很多框架默认只看本层协议(如 Spring Boot 的 request.isSecure() 默认不识别 header),需显式配置:
- Spring Boot:设
server.forward-headers-strategy=framework,并启用RemoteIpFilter - Node.js(Express):设
app.set('trust proxy', true),它会自动信任X-Forwarded-Proto - PHP(Laravel):需在
App\Http\Middleware\TrustProxies中指定可信代理 IP 段 - 切忌直接判断
$_SERVER['HTTPS'] === 'on'—— 这反映的是本层连接,不是原始请求











