nginx未显式设置host头时会用upstream名称填充,若含下划线(如web_servers)将被tomcat等拒绝返回400;应避免非法字符并显式配置proxy_set_header host为后端期望值。

这个问题本质是 Nginx 在未显式设置 Host 请求头时,自动将 upstream 块的名称作为 Host 值发给后端,而该名称若含下划线(如 web_servers),就会被 Tomcat 等严格遵循 RFC 7230 的服务器拒绝,返回 400 错误。
避免 upstream 名称含非法字符
HTTP Host 头不允许出现下划线(_)、空格或特殊符号。Nginx 若未配置 proxy_set_header Host,会默认用 upstream 名称填充 Host 头。
- ❌ 错误示例:
upstream web_servers { server 192.168.1.10:8080; }→ 发出的 Host 是web_servers - ✅ 正确做法:改用短横线或驼峰,如
upstream web-servers或upstream webServers - ⚠️ 注意:即使名称合法,也不建议依赖此行为——它不可控且易被误解
显式设置 proxy_set_header Host
最可靠的方式是主动指定后端期望的 Host 值,不依赖 Nginx 默认逻辑。
- 代理到具体域名(如
api.example.com)时:proxy_set_header Host api.example.com; - 需保留客户端原始 Host(含端口)时:
proxy_set_header Host $http_host; - 通用场景(去掉端口、取请求行 host):
proxy_set_header Host $host; - ⚠️ 切勿混用:
$host和$http_host行为不同,选错会导致云服务(如 API Gateway)校验失败
验证 Host 头是否生效
配置修改后,务必抓包或在后端日志中确认实际收到的 Host 值。
- 用
curl -v http://your-nginx-domain/查看响应前的请求头 - 在 Spring Boot 中加日志:
request.getHeaders("Host") - Tomcat 可开启 access log,记录
%{Host}i字段 - 若仍看到
web_servers或其他非预期值,说明proxy_set_header Host未生效或被覆盖
补充:upstream 指向域名时的 Host 特别注意
当 upstream 直接写域名(如 server api.example.com;),而非 IP,Nginx 默认用 $proxy_host(即 upstream 名)填 Host,这极易踩坑。
- ✅ 推荐写法:
upstream api_backend { server api.example.com; }<br>location / {<br> proxy_pass https://api_backend;<br> proxy_set_header Host api.example.com;<br>} - ❌ 危险写法:
proxy_set_header Host $host;→ 此时$host是客户端访问 Nginx 的域名(如yourapp.com),不是后端需要的api.example.com











