proxy_pass在stream模块中实现四层转发,必须置于stream块内、仅支持ip:port或upstream名、不认协议头或路径;tcp/udp行为不同,且不可混用http模块指令。

直接用 proxy_pass 实现四层转发,核心就三点:位置对、写法对、协议对。它不走 HTTP 解析,只做连接透传,所以不能套用 http 模块那一套。
proxy_pass 必须写在 stream 块里
stream 是独立于 http 的顶层模块,和 events 并列。把 proxy_pass 放进 http {} 或 server {}(http 下的)里,Nginx 启动会直接报错:unknown directive "proxy_pass" 或 directive is not allowed here。
- 正确结构是:
events { ... }→stream { upstream xxx { ... }; server { listen ...; proxy_pass ...; } }→http { ... } - server 块里的 listen 只写端口(如
listen 3306),UDP 要加udp标识(如listen 53 udp) - upstream 和 server 都必须定义在 stream 块内,彼此之间不能嵌套
proxy_pass 后面只能跟 IP:PORT 或 upstream 名
它不认协议头,也不解析 URL。写 http://、https://、路径、查询参数,全都会导致启动失败。
FastAPI + Flask 混合部署最佳实践,解决路由定义、API 代理等常见问题,适用于同时运行 FastAPI API 与 Flask 前端的场景。
- 正确写法:
proxy_pass 192.168.1.10:6379;或proxy_pass redis_backend; - 如果用域名(比如
proxy_pass db.example.com:3306;),必须提前配好resolver,否则 DNS 解析失败,连接超时 - upstream 内部的 server 行也不能带协议,只写
server 10.0.2.5:22 weight=2;
TCP 和 UDP 的 proxy_pass 行为略有不同
TCP 默认建立长连接并透传全部字节流;UDP 是无连接的,每次请求/响应独立,所以需额外控制响应数量和超时。
- TCP 场景常用:
proxy_timeout 1h;(如 MySQL 长连接)、proxy_responses 1;(收到首个响应包即认为连接成功) - UDP 场景必须加
udp标识,且推荐设proxy_responses 1;,避免客户端重复收包;proxy_timeout通常设短些(如1s),适配 DNS 查询等快速交互 - UDP 不支持健康检查、keepalive、重试等高级策略,靠底层连通性判断可用性
不能用的指令,proxy_pass 也救不了
stream 层没有 request header、body、location、rewrite 这些概念,所有 http 模块专属指令在这里都无效。
- 写了
proxy_set_header、rewrite、access_log、return,Nginx -t 就会失败 - 想做 TLS SNI 路由?得靠
ssl_preread on;+$ssl_preread_server_name变量,但仅限 TLS 握手阶段,不是应用层解析 - 需要读写分离、SQL 路由、协议解析?stream 做不到,得换 ProxySQL、MaxScale 或 HAProxy










