Nginx四层Stream代理透传客户端真实IP需代理侧封装PROXY Protocol头且上游侧解析,两端必须协同配置:代理端listen后加proxy_protocol,上游端启用proxy_protocol并正确设置set_real_ip_from信任网段,缺一不可。

要让 Nginx 四层 Stream 代理把客户端真实 IP 透传给上游服务器,关键不是“加个开关”,而是代理侧封装 + 上游侧解析两头都得配对生效。单独开 proxy_protocol 或只在 upstream 写 IP 都没用。
必须两端协同:代理发、上游收
-
代理侧(Nginx Stream)要主动封装 PROXY Protocol 头
在server块的listen指令后加上proxy_protocol,比如:stream { upstream backend { server 192.168.10.5:3306; } server { listen 3306 proxy_protocol; # ← 这一行是核心动作 proxy_pass backend; } }这样 Nginx 就会在 TCP 连接建立时,在原始数据流最前面插入一行类似
PROXY TCP4 203.0.113.25 192.0.2.10 54321 3306\r\n的文本头。 -
上游服务器必须能识别并解析这个头部
如果上游是另一台 Nginx(Stream 模式),需配置:stream { server { listen 3306 proxy_protocol; # ← 同样要开启接收 set_real_ip_from 10.0.0.0/8; # ← 声明信任的代理网段(即前一级 Nginx 的出口 IP) # 后续 $realip_remote_addr 就是客户端真实 IP proxy_pass final_service; } }如果上游是 MySQL、Redis、自研服务等,它必须原生支持 PROXY Protocol v1 解析;否则会把头部当脏数据读入,导致协议错乱甚至连接中断。
信任网段设置不能漏
-
set_real_ip_from必须精确填写前一级代理的出口 IP 或 CIDR
比如用阿里云 ESA,填set_real_ip_from 100.64.0.0/10;;用内网 SLB,填对应内网段,例如172.16.0.0/12 - 可多次写,支持 IPv4、IPv6、UNIX 套接字:
set_real_ip_from 192.168.1.10; set_real_ip_from 2001:db8::/32; set_real_ip_from unix:;
验证是否真正生效
- 查
access_log,用$realip_remote_addr替代$remote_addr输出log_format realip '$realip_remote_addr → $server_addr:$server_port'; access_log /var/log/nginx/stream.log realip;
- 对比日志:如果
$realip_remote_addr和$remote_addr总是相同,说明没生效 - 看 error log:出现
client sent invalid PROXY header,大概率是中间有防火墙、另一层 LB 或配置错位截断了头部
注意事项
- UDP 不支持 PROXY Protocol 透传真实 IP(协议本身不适用)
-
proxy_protocol on;是旧写法,Nginx 1.12+ 推荐直接写listen xxx proxy_protocol; - 不要用
real_ip_header proxy_protocol—— 这是 HTTP 模块指令,Stream 里无效 - 所有
proxy_pass目标只能是IP:PORT或upstream 名,不能带http://或路径
不复杂但容易忽略细节。


















