关键是要每层nginx都显式配置proxy_set_header host $http_host;或$host;,禁用默认的$proxy_host,并同步设置x-forwarded-proto、x-forwarded-host等头字段,确保多层代理中客户端原始域名和协议信息完整透传至后端。

要让后端拿到用户访问的真实域名(比如 app.example.com),关键不是“转发 Host”,而是**每层 Nginx 都必须主动覆盖默认行为**。Nginx 默认会把 Host 头设成 upstream 地址(如 127.0.0.1:3000),而不是客户端发来的原始值。只要配置对,问题就解决了。
必须用 $http_host 或 $host,别用 $proxy_host
默认情况下,Nginx 会用 $proxy_host(即 proxy_pass 后面写的地址)填充 Host 头,这完全脱离用户请求。正确做法是显式指定:
-
proxy_set_header Host $http_host;:完整保留客户端原始 Host,含端口(如admin.example.com:8443),适合需要端口信息的场景(JWT 签名、CORS 白名单、非标 HTTPS 端口) -
proxy_set_header Host $host;:只传域名,自动剥离标准端口(80/443),更干净,适合多数 Web 应用 - 务必删掉或注释掉类似
proxy_set_header Host $proxy_host;或硬编码proxy_set_header Host example.com;的错误配置
多层代理必须每一层都单独配
CDN → 负载均衡器 → Nginx → 后端?只要中间任意一层没配,Host 就会在那断掉。比如:
- CDN 没透传 Host,负载均衡器收到的就是 CDN 内网 IP,再往后配
$http_host也没用 -
proxy_set_header只对当前 location 或 server 块内紧随其后的proxy_pass生效,不会自动传递到下一层 - 所有做反向代理的环节(包括 Nginx Proxy Manager、ALB、自建网关)都要各自加上这行配置
配合其他头字段,避免协议和跳转出错
光修 Host 不够,后端生成跳转链接、判断 HTTPS、校验来源时还依赖这些:
-
proxy_set_header X-Forwarded-Proto $scheme;:告诉后端是 http 还是 https,防止 302 跳转变成 http:// -
proxy_set_header X-Forwarded-Host $host;:提供纯域名版原始 Host,供后端安全读取(比直接信任 Host 头更可靠) -
proxy_set_header X-Real-IP $remote_addr;和proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;:辅助风控与日志溯源
验证是否生效
改完配置别急着上线,先确认效果:
- 执行
nginx -t检查语法,再nginx -s reload生效 - 在后端打印
Host、X-Forwarded-Host、X-Forwarded-Proto字段,看值是不是你期望的 - 用
curl -v http://your-domain/path观察响应头和后端日志,对比直连后端时的差异 - 如果仍不对,重点查是否有上游设备(CDN/WAF)已篡改 Host,或某一层漏配











