proxy_set_header 通过设置 host 和 x-forwarded-host 等请求头,使后端获知用户原始访问域名;必须设 host $host 以保留原始域名,搭配 x-forwarded-host $host、x-forwarded-proto $scheme 等确保后端正确重建请求。

proxy_set_header 本身不“传递域名”,而是通过设置请求头,让后端感知到用户最初访问的域名。关键不是改 URL,而是让后端拿到正确的 Host 或 X-Forwarded-Host 值,从而生成正确链接、做路由判断或校验来源。
必须设置 Host 头,否则后端看到的是内网地址
Nginx 默认转发时,Host 头会变成 proxy_pass 目标(比如 backend.internal:8000),而不是用户访问的 api.example.com。后端若依赖 Host 构建跳转链接,就会出错。
推荐写法:
保留原始域名(最常用)
proxy_set_header Host $host;$host是客户端请求中 Host 字段的值(自动去掉端口),安全可靠。更完整:带端口的原始 Host(如需 HTTPS 端口信息)
proxy_set_header Host $http_host;
注意:如果客户端带了:443或:80,这个值也会包含端口,部分后端可能不兼容。强制固定域名(适合单入口后端)
proxy_set_header Host api.company.local;
适用于后端只认一个域名、不处理多租户或多子域的场景。
补充 X-Forwarded-Host,专用于透传原始域名
X-Forwarded-Host 是标准辅助头,语义明确——它只表示“用户最初访问的 Host”,后端可放心读取,而不与 Host 头混淆(后者可能被 Nginx 或上游代理覆盖)。
正确配置:
proxy_set_header X-Forwarded-Host $host;
⚠️ 不要写成:
-
proxy_set_header X-Forwarded-Host $http_host;→ 可能含端口,不纯净 -
proxy_set_header X-Forwarded-Host example.com;→ 失去泛域名适配能力
同时建议搭配:
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
这样后端就能组合出完整原始请求:https://api.example.com/path。
后端必须主动读取,Nginx 不会自动“生效”
Nginx 只负责把头发过去,后端框架默认仍用连接 IP 或 Host 头原始值(可能已被覆盖)。你需要:
- Django:设
USE_X_FORWARDED_HOST = True,并确保ALLOWED_HOSTS包含$host值 - Flask:用
ProxyFix中间件,指定trusted_hosts为 Nginx IP - Node.js(Express):
app.set('trust proxy', true),再通过req.hostname获取 - Java/Spring:读
X-Forwarded-Host,别用request.getServerName()
常见陷阱提醒
- 如果用了
rewrite修改 URI,必须在proxy_set_header之前执行,否则路径和 Host 不匹配 - 多层代理(如 CDN → Nginx → 后端)时,
$host仍是用户原始 Host,但$remote_addr需用set_real_ip_from修正,否则X-Real-IP会不准 - 不要遗漏
X-Forwarded-Proto:否则后端可能误判为 HTTP,导致跳转链接变成http://而非https://
不复杂但容易忽略











