应通过全局map指令结合可信代理IP和X-Forwarded-Proto头生成防伪造的$real_scheme_secure变量:优先信任来自已知代理IP的X-Forwarded-Proto值,否则fallback至$scheme,确保多层代理下HTTPS识别准确可靠。

要让 Nginx 在多层反向代理中准确识别“最外层是否为 HTTPS”,不能依赖单个固定变量(比如 $scheme 或 $https),因为中间代理会覆盖原始协议信息。核心思路是:**由最外层代理显式透传协议标识,Nginx 在全局作用域统一接收并标准化为一个可信的变量**。
关键配置:在 http 块定义可信的 HTTPS 标识变量
在 http 块顶层(即全局 HTTP 上下文)使用 map 指令,基于可信请求头动态生成一个稳定、防伪造的变量,例如 $real_scheme:
http {
# 优先信任 X-Forwarded-Proto,若为空则 fallback 到 $scheme
map $http_x_forwarded_proto $real_scheme {
default $scheme;
"https" "https";
"http" "http";
}
<pre class="brush:php;toolbar:false;"># 可选:进一步强化可信度,只接受来自已知代理 IP 的头
map $remote_addr $trusted_proxy {
192.168.10.1 1; # 第一层 LB IP
10.0.5.254 1; # CDN 或 WAF IP
default 0;
}
map $trusted_proxy:$http_x_forwarded_proto $real_scheme_secure {
"1:https" "https";
"1:http" "http";
default $scheme;
}}
这样定义后,$real_scheme_secure 就是一个仅在可信代理发起的请求中才被信任的协议变量,避免了客户端伪造 X-Forwarded-Proto 的风险。
上游代理必须正确设置 X-Forwarded-Proto
最外层代理(如云厂商 SLB、CDN、或前置 Nginx)必须确保:
- 对所有 HTTPS 入口请求,添加请求头
X-Forwarded-Proto: https - 对 HTTP 入口请求,设为
X-Forwarded-Proto: http - 不透传客户端自行携带的该头(防止污染),应在入口处强制覆盖
例如,在最外层 Nginx 的 server 块中写:
location / {
proxy_pass http://inner-nginx;
proxy_set_header X-Forwarded-Proto $scheme; # 关键:用 $scheme 而非客户端传入的
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
}在 server 或 location 中安全使用该变量
一旦全局 map 定义完成,你可在任意 server 或 location 块中直接使用 $real_scheme_secure 做逻辑判断,例如:
- 强制跳转 HTTPS:
if ($real_scheme_secure = "http") { return 301 https://$host$request_uri; } - 注入响应头:
add_header X-Protocol $real_scheme_secure; - 日志记录:
log_format main '$remote_addr - [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$real_scheme_secure"';
验证与调试建议
临时加一条日志,确认变量行为是否符合预期:
log_format debug '$remote_addr — $http_x_forwarded_proto | $scheme | $https | $real_scheme_secure'; access_log /var/log/nginx/debug.log debug;
然后用 curl 模拟不同链路测试:
-
curl -H "X-Forwarded-Proto: https" http://your-domain/→ 应输出https -
curl http://your-domain/(直连)→ 应输出http(因$trusted_proxy为 0,fallback 到$scheme) -
curl -H "X-Forwarded-Proto: https" --interface 192.168.10.1 http://your-domain/→ 若源 IP 匹配,则走可信路径


















