一、模块原理与价值
-
PROXY Protocol 回溯
- 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。
- Stream 层接收到头部后,
ngx_stream_realip_module
从中提取原始信息,并用$realip_remote_addr
、$realip_remote_port
覆盖$remote_addr
、$remote_port
,下游模块获知真源地址。
-
兼容性
- 对 TCP/UDP/UNIX Domain Socket(
set_real_ip_from unix:
)均可生效。 - 同时支持 CIDR 方式批量信任,也可指定单 IP。
- 对 TCP/UDP/UNIX Domain Socket(
-
应用价值
- 限流/黑名单:结合
limit_conn_zone $realip_remote_addr
而非代理 IP。 - 日志真实化:
access_log
使用$realip_remote_addr
记录客户端原始 IP。 - 多层转发:当部署多级反代或自研网关时,只需在最前端开启 PROXY,即可保证中间层获得正确源地址。
- 限流/黑名单:结合
二、指令解读
stream {
# 1) 开启 PROXY Protocol 支持
server {
listen 12345 proxy_protocol;
# 2) 定义可信代理网段
set_real_ip_from 192.168.1.0/24;
set_real_ip_from 2001:db8::/32;
set_real_ip_from unix:; # 信任本地 UNIX 域套接字
# 3) 在此之后,$remote_addr/$remote_port 即为真实值
proxy_pass backend;
}
}
-
listen … proxy_protocol
:必须在listen
中开启,才会解析 PROXY 头。 -
set_real_ip_from
:可多次使用,声明 信任来源,只有来自这些地址的连接才会替换。 -
变量:
$realip_remote_addr
:保留头部中指明的客户端 IP;$realip_remote_port
:保留客户端端口;- 替换后,后续所有引用
$remote_addr
都取自$realip_remote_addr
。
三、典型场景
-
限流与黑名单
stream { limit_conn_zone $realip_remote_addr zone=ip:10m; server { listen 3306 proxy_protocol; set_real_ip_from 10.0.0.0/8; limit_conn ip 1; # 单 IP 仅一条并发 proxy_pass mysql-backend; } }
-
日志埋点
stream { log_format realip '$realip_remote_addr:$realip_remote_port -> $server_addr'; access_log /var/log/nginx/stream.log realip; server { listen 6379 proxy_protocol; set_real_ip_from 172.16.0.0/12; proxy_pass redis-backend; } }
-
多级代理链
- 前端 LB → 中间网关 → Nginx Stream
- 只在最外层 LB 输出 PROXY Protocol,后面层级都能拿到同一个真实源地址,无需在每层都开启。
四、进阶用法
-
动态信任列表
可结合keyval
或 njs 动态更新set_real_ip_from
段中 CIDR,例如根据 API 下发临时可信代理 IP。 -
协议混合
在同一实例可分stream { server { listen 9000 proxy_protocol; … } }
和常规 TCP 端口并存,仅对指定端口生效。 -
与 MQTT/HTTP 模块联动
对于 TLS 透传 SNI(ssl_preread
)或 MQTT 预读(mqtt_preread
),将真实用户 IP 替换后再做鉴权或路由。
五、常见坑与排查
问题 | 原因 | 解决办法 |
---|---|---|
$remote_addr 取到 LB IP | 未开启 proxy_protocol 或 set_real_ip_from 未包含 LB 地址 | 确认 listen … proxy_protocol 和 set_real_ip_from 区段 |
IPv6 未生效 | 忽略了 2001:db8::/32 之类 IPv6 段 | 加入对应 IPv6 CIDR 或 ::/0 (信任所有) |
UNIX Socket 透传失败 | 仅 TCP/UDP,需加 set_real_ip_from unix: | 指定 unix: 才信任本地套接字 |
多级反代仍然显示内网 IP | 中间层被覆盖,或上层未输出 PROXY 头 | 确保最前层代理使用 PROXY Protocol v2,并全链路透传 |
六、结语
ngx_stream_realip_module
是构建 透明、可观测 四层网关的基石,可在不引入第三方组件的前提下可靠还原客户端真实源地址,为限流、鉴权、审计、灰度等上层功能提供准确数据。正确配置 proxy_protocol
与 set_real_ip_from
,即可让 Nginx 一线完成真实 IP 的回溯与替换,为复杂网络架构保驾护航。