华为云 ELB 后面的服务拿不到真实客户端 IP?七层与四层的取法对照
背景
业务挂到华为云 ELB 后面以后,一个很常见的情况是:Nginx 访问日志、应用里记录的来源 IP 全变成了同一批内网地址,限流、黑名单、地域统计都跟着失效。ELB 其实提供了传递客户端 IP 的办法,只是七层和四层、独享型和共享型的取法不一样,后端要按对应方式去取。
本文按官方文档的说明整理各场景的取法、Nginx 配置示例和常见坑。具体开关名称和默认值以控制台监听器配置页和《弹性负载均衡用户指南》为准。
先判断属于哪种情况
| 场景 | 默认情况下后端看到的来源 | 怎么拿到客户端 IP |
|---|---|---|
| 七层 HTTP/HTTPS 监听器(独享型、共享型) | ELB 地址 | 请求头 X-Forwarded-For,文档说明第一个 IP 就是客户端真实 IP |
| 独享型 四层 TCP/UDP 监听器 | 默认就是客户端真实 IP | 一般不用配置,直接看日志即可 |
| 共享型 四层 TCP/UDP 监听器 | 100.125.0.0/16 网段地址 | 在监听器上开启「获取客户端IP」;TCP 还可以用 TOA 插件作为补充方法 |
| 独享型 TLS 监听器 | ELB 地址 | 不支持「获取客户端IP」,要开启 Proxy Protocol |
判断方法:在后端执行 ss -tn 或看访问日志,如果对端地址都是 ELB 后端子网或 100.125 网段的地址,说明当前拿到的是 ELB 地址,需要按下面的方式处理。
七层:从 X-Forwarded-For 还原
HTTP/HTTPS 监听器会把客户端地址写进 X-Forwarded-For 请求头。常见做法是在 Nginx 里用 realip 模块,把 $remote_addr 还原成真实客户端地址,这样后续的日志、limit_req、allow/deny 都能直接生效。
# http 或 server 块中
# 独享型填 ELB 后端子网网段;共享型填 100.125.0.0/16
set_real_ip_from 192.168.0.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
log_format main '$remote_addr - [$time_local] "$request" $status '
'xff="$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
几点说明:
- set_real_ip_from 要收窄到 ELB 实际使用的地址段,不要写 0.0.0.0/0。否则直连后端的请求也能靠伪造 X-Forwarded-For 冒充任意 IP。
- 前面还有 CDN 或 WAF 时,要把它们的回源地址段也加进 set_real_ip_from,配合 real_ip_recursive on 才能跳过整条代理链。
- 改完先
nginx -t检查,再nginx -s reload。日志里保留 xff 字段,方便和 $remote_addr 对照。
没有 Nginx、由应用直接读请求头时,思路一样:只信任来自 ELB 地址段的请求头,并明确可信代理的层数。比如 Python Werkzeug 的 ProxyFix、Spring Boot 的 server.forward-headers-strategy,都需要按实际代理层数配置。
四层:独享型默认透传
独享型 ELB 的 TCP/UDP 监听器默认开启「获取客户端IP」,ELB 和后端之间直接用客户端真实地址通信,看后端日志就能拿到,不需要额外配置。
文档列出的几种例外要注意:
- 后端是「IP 类型后端」,或者监听器开启了 IPv4/IPv6 地址转换时,透传会失效。TCP 监听器这时可以用 TOA 插件(仅 IPv4)或 Proxy Protocol;UDP 在这两种场景下拿不到客户端 IP。
- TLS 监听器不支持「获取客户端IP」,只能开启 Proxy Protocol。注意开启前后端必须能解析 Proxy Protocol,否则业务会中断。Nginx 对应写法是
listen 端口 proxy_protocol;加上real_ip_header proxy_protocol;。 - 请求经过 NAT 网关时,只能拿到 NAT 转换后的地址。
四层:共享型要手动开启
共享型 ELB 默认用 100.125.0.0/16 网段和后端通信。四层监听器可以在「编辑监听器」里开启「获取客户端IP」开关,开启后 ELB 和后端之间直接用客户端真实地址通信。
要点:
- 开关切换时,如果监听器已经挂了后端服务器,流量会短暂中断(文档写的是约两个健康检查间隔),尽量放在低峰期操作。
- 开启后,四层转发流量不受后端安全组和网络 ACL 规则限制,但文档同时提醒要检查操作系统防火墙和软件本身的访问规则,让客户端 IP 能访问后端。需要按来源 IP 限制访问时,建议用监听器的「访问控制」功能。
- TCP 监听器还有 TOA 插件这个补充方法;TOA 是内核模块,和内核版本强相关,升级内核后要重新确认模块是否加载(
lsmod | grep toa)。
两个容易踩的共性坑
- 自己访问自己。开启「获取客户端IP」后,不支持同一台服务器既当后端又当客户端:后端看到源 IP 是本机地址,应答回不到 ELB,表现为连接超时。这种调用改走内网直连。
- 安全组放行范围。健康检查流量仍然要放行:独享型放行 ELB 后端子网网段,共享型放行 100.125.0.0/16。很多人改完取 IP 的配置后又顺手收紧了安全组,结果健康检查失败、后端被摘除。
常见现象速查
| 现象 | 常见原因 | 处理 |
|---|---|---|
| 七层日志里全是同一批内网 IP | Web 服务器没读 X-Forwarded-For | 配置 realip 或在应用里读请求头 |
| 共享型四层拿不到真实 IP | 监听器没开「获取客户端IP」 | 低峰期开启,或用 TOA |
| 独享型四层突然拿不到真实 IP | 换成了 IP 类型后端,或开了地址转换 | 改用 TOA 或 Proxy Protocol |
| TLS 监听器拿不到真实 IP | TLS 不支持「获取客户端IP」 | 开启 Proxy Protocol 并让后端支持解析 |
| 来源 IP 能被伪造 | set_real_ip_from 范围过大 | 收窄到 ELB(和 CDN、WAF)地址段 |
| 开启后本机调用超时 | 同一台服务器既是后端又是客户端 | 改走内网直连 |
自检清单
- 先确认监听器协议(HTTP/HTTPS、TCP/UDP、TLS)和 ELB 类型(独享型或共享型)。
- 七层:只信任 ELB(和 CDN、WAF)地址段传来的 X-Forwarded-For。
- 四层独享型:确认没有 IP 类型后端和地址转换;TLS 用 Proxy Protocol。
- 四层共享型:确认「获取客户端IP」已开启,系统防火墙允许客户端地址。
- 健康检查需要的安全组规则不要删。
- 最后用一个已知公网 IP 访问一次,在日志里核对记录的地址是否正确。
- 点赞
- 收藏
- 关注作者
评论(0)