Nginx upstream中每个server必须显式写端口,仅80/443有默认行为;省略非标端口(如3000、8080)会导致转发失败;upstream名称禁用下划线,否则Host头透传可能触发后端400错误。
Upstream 中每个 server 必须显式写端口
upstream 块里定义后端节点时,不能省略非标准端口。Nginx 不会自动补 8080、3000、9001 这类端口,只对 80/443 有默认行为:
-
正确写法:server 192.168.1.10:3000; 或 server api.internal:8080;
-
错误写法:server 192.168.1.10;(默认走 80,后端收不到请求)
- 使用容器名或内网域名时,同样要带端口,比如 server backend-app:9001;
proxy_pass 引用 upstream 时仍需协议+端口语义一致
location 中的 proxy_pass 指向 upstream 名称时,本身不包含端口信息,但实际转发仍依赖 upstream 内各 server 的端口配置。关键是保持协议与端口在整条链路中一致:
- upstream 定义了 server 10.0.0.5:8080,proxy_pass http://my_backend; 就等价于发往 http://10.0.0.5:8080
- 若 upstream 中混用端口(如一个 8080、一个 9001),负载均衡仍正常工作,但后端应用必须能处理不同端口上的相同路径逻辑
- 不建议在 proxy_pass 后加路径(如 http://my_backend/api),应由 location 控制路径映射
Host 头透传要避开下划线陷阱
upstream 名称含下划线(如 upstream api_servers { ... })且未设置 Host 头时,Nginx 会把 upstream 名作为 Host 值发给后端。而 Tomcat、Spring Boot 内嵌容器等严格遵循 RFC 7230,拒绝含下划线的 Host,直接返回 400。
- 解决方案一:改 upstream 名为短横线或驼峰,如 upstream api-servers { ... } 或 upstream apiServers { ... }
- 解决方案二:显式设置 Host 头,proxy_set_header Host $host;(最稳妥)
- 若后端需感知 Nginx 监听端口(如生成重定向 URL),可用 proxy_set_header Host $host:$server_port;
WebSocket 和长连接需要额外头支持
后端跑在非标端口上,若涉及 WebSocket(如前端 dev server)、SSE 或 gRPC,仅靠 upstream + proxy_pass 不够,必须启用 HTTP/1.1 升级机制:
- 在对应 location 块中加入三行:proxy_http_version 1.1;、proxy_set_header Upgrade $http_upgrade;、proxy_set_header Connection "upgrade";
- 这三者缺一不可,否则连接会在默认 60 秒后被静默关闭
- 该配置与 upstream 是否含端口无关,但常出现在非标端口服务(如 vite dev server 默认 5173)场景中