关键是要每层Nginx代理都显式配置proxy_set_header Host $http_host;,因默认会将Host设为upstream地址(如backend:8080),导致跳转异常、404或Cookie失效;必须用$http_host保留原始域名和端口,且每层独立配置,不可继承。

要让后端服务始终看到客户端最初请求的 Host 值,关键不是“转发”,而是**每层 Nginx 代理都必须显式覆盖默认行为**。Nginx 默认会把 Host 头设为 upstream 地址(比如 backend:8080),而不是用户访问的 api.example.com:443 —— 这会导致重定向跳错、静态资源 404、Cookie 域名不生效等问题。
为什么 Host 头容易被破坏
Nginx 在执行 proxy_pass 时,若未配置 proxy_set_header Host,就会自动使用 $proxy_host(即 upstream 的 host 部分)作为 Host 头发送给后端。这个值和客户端毫无关系,纯属内部地址。多层链路中只要有一层漏配,Host 就会在那中断,后端拿到的就是上一层的内网 IP 或服务名。
- CDN → ALB → Nginx → 应用:如果 ALB 没透传 Host,Nginx 收到的就是 ALB 的内网地址;即使 Nginx 配了 $http_host,也已晚——原始值早就丢了
- 浏览器访问 admin.example.com:8080,但后端日志显示 Host 是 127.0.0.1:3000,说明至少有一层没配 Host 透传
- HTTPS 请求跳转成 HTTP,或 302 Location 缺少端口,往往是因为用了 $host 而非 $http_host
必须用 $http_host,不是 $host
$http_host 直接取自客户端请求头的原始字符串,完整保留域名和端口(如 app.example.com:8443)。$host 会自动剥离标准端口(80/443),导致签名失败、URL 构造错误等静默问题。
安装并运行 Aperture(Lightning Labs 的 L402 闪电反向代理),用于创建 L402 付费墙、配置付费 API 端点、为其他代理托管付费内容或测试 L402 认证流程。
- 客户端请求 Host: api.dev:8080 → $http_host = api.dev:8080,$host = api.dev
- 后端若用 Host 做 JWT 签名校验、CORS 白名单或生成绝对跳转链接,缺端口就直接失败
- 配置写法:proxy_set_header Host $http_host;,不能写成 $host 或 $proxy_host
每一级代理都要单独配,不能只配最后一层
proxy_set_header 的作用域是 location 或 server 块,且只对紧随其后的 proxy_pass 生效。它不会“继承”或“穿透”到下一层代理。所以 CDN 后的负载均衡器、负载均衡器后的 Nginx、Nginx 后的应用网关——只要它在做反向代理,就必须独立配置。
- 示例(某中间层 Nginx):
- location /api/ {
- proxy_pass http://next-hop;
- proxy_set_header Host $http_host;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- }
配合 X-Forwarded-Host 提高可信度
仅靠 Host 头不够稳妥,有些后端框架会优先读 X-Forwarded-Host(尤其在做了 rewrite 或 header 重写之后)。建议同步设置:
- proxy_set_header X-Forwarded-Host $http_host;
- 该头不参与协议转发逻辑,纯作参考校验,比直接信任 Host 更安全
- 注意:不能在 http { } 块里用 $host 或 $http_host 变量——它们在全局块不可用,必须放在 server 或 location 内

















