X-Forwarded-Host需手动配置且必须用可信原始Host(优先$http_host),避免未配置、误用$remote_addr或继承污染;HTTPS场景须同步设X-Forwarded-Proto $scheme。

核心在于明确告诉后端:用户最初访问的是哪个 Host。Nginx 默认不设置 X-Forwarded-Host,必须手动注入,且值要准确反映原始请求的 Host,不能直接用 $host 或 $http_host 简单替代,尤其在多级代理或存在 CDN 的场景下容易出错。
为什么 X-Forwarded-Host 容易不一致
常见原因有三个:
-
完全没配:只设了
proxy_set_header Host $host,但没加X-Forwarded-Host,后端收不到原始 Host,只能看到 Nginx 自己的 host 值 -
值取错了:比如写成
proxy_set_header X-Forwarded-Host $remote_addr(这是 IP,不是域名),或者用了未校验的$http_x_forwarded_host(可能被恶意篡改) -
多级代理叠加污染:上游 WAF 或 CDN 已经加了一层
X-Forwarded-Host,Nginx 又没重置,导致后端收到多个或错误的值
正确配置 X-Forwarded-Host 的关键写法
应始终使用客户端发起请求时携带的原始 Host,最稳妥的方式是:
- 优先用
$http_host:它直接取自请求头中的 Host 字段,包含端口(如app.example.com:443),适用于大多数 HTTPS 场景 - 次选用
$host:它会自动标准化(去掉端口、转小写),更干净,但丢失端口信息;如果后端不依赖端口,可用 -
绝对不要用
$http_x_forwarded_host或$proxy_host:前者不可信,后者是后端地址,完全不对
标准配置示例:
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $http_host; # ← 关键行,用原始 Host
proxy_set_header X-Forwarded-Proto $scheme;
}HTTPS 场景下的额外注意点
当 Nginx 终止 HTTPS,后端走 HTTP 时,后端常需知道原始协议是 HTTPS,否则生成的链接会变成 http://。这时需同步设置:
-
proxy_set_header X-Forwarded-Proto $scheme;:让后端知道原始是https - 部分框架(如 Django)还需配合
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') - ArcGIS Server 等特定服务明确要求
X-Forwarded-Host,缺了会报host_mismatch
防范恶意头覆盖的安全做法
如果上游有 WAF/CDN,为避免攻击者伪造 X-Forwarded-Host,应在 Nginx 中显式覆盖而非继承:
- 删掉所有
proxy_set_header X-Forwarded-Host $http_x_forwarded_host;这类写法 - 强制用可信来源重设:
proxy_set_header X-Forwarded-Host $http_host; - 必要时可加条件判断,例如只在非空时设置:
map $http_host $forwarded_host { "" ""; default $http_host; },再用$forwarded_host











