应使用proxy_set_header host $http_host;,因其原样保留客户端请求中的host头(含端口),避免$host自动剥离端口导致上游服务误判;需确保无其他同名指令覆盖,且客户端http/1.1请求带host头。

默认情况下,Nginx 在反向代理时会把 Host 请求头替换成 proxy_pass 指令中指定的上游地址的 host(比如 example.com),而不是客户端原始请求中的 Host。要保持客户端的 Host 不变,关键在于显式设置 proxy_set_header Host $host; 或更准确的 $http_host。
用 $http_host 保留完整原始 Host 头
客户端请求可能带端口(如 example.com:8080)或包含用户自定义 Host,$http_host 变量会原样复现请求中的 Host 头内容(包括端口),是最贴近原始值的选择。
- 在
location或server块中添加:
proxy_set_header Host $http_host; - 确保没有其他同名
proxy_set_header Host指令覆盖它(Nginx 使用最后出现的为准) - 不需要额外开启
underscores_in_headers on,因为 Host 是标准头,不涉及下划线
避免误用 $host 导致端口丢失
$host 变量会自动去掉端口,并在 Host 为空时 fallback 到 server_name,容易造成上游服务收不到真实端口信息(例如 Websocket 升级或某些鉴权逻辑依赖端口)。
- ❌ 错误写法(丢端口):
proxy_set_header Host $host; - ✅ 正确写法(保端口):
proxy_set_header Host $http_host; - 如果上游明确不要端口(如只跑在标准 80/443),且你控制客户端行为,
$host可接受;否则优先选$http_host
注意:Host 头必须存在才可传递
HTTP/1.1 规范要求请求必须含 Host 头,但某些工具(如 curl 不加 -H "Host:...")、HTTP/1.0 请求或异常客户端可能不带。此时 $http_host 为空,Nginx 会使用 $server_name 或空值,导致上游收到空 Host。
- 可通过日志确认是否收到 Host:
log_format main '$http_host - $request'; - 若需兜底,可写成:
proxy_set_header Host $http_host;
proxy_set_header Host $host;(后者仅当前者为空时生效,但 Nginx 不支持条件赋值,所以实际仍推荐只用$http_host并确保客户端合规) - 对内部调用或测试场景,可用 curl 显式指定:
curl -H "Host: api.example.com:3000" http://nginx-proxy/
附:完整最小配置示例
以下是一个典型反向代理配置片段,重点突出 Host 透传:
location /api/ {
proxy_pass https://backend-server/;
proxy_set_header Host $http_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-Proto $scheme;
}
只要没在其他地方覆盖 Host,该配置就能让后端看到和客户端发起时完全一致的 Host 请求头。











