nginx 日志准确记录真实客户端 ip 的关键是启用 http_realip_module 并配置 set_real_ip_from、real_ip_header 和 real_ip_recursive on,使 $remote_addr 自动更新为经可信代理链路校验后的用户真实 ip。

Nginx 日志里默认记的 $remote_addr 是直连它的 IP,不是用户真实 IP。要让日志准确记录真实客户端 IP,不能只靠 X-Forwarded-For 头简单写入,必须配合可信代理识别和变量替换,否则日志会混入伪造 IP 或中间代理地址。
Nginx 日志中正确记录真实 IP 的关键配置
- 必须启用
http_realip_module模块(多数编译版已内置,可通过nginx -V 2>&1 | grep -o http_realip确认) - 在
http或server块中声明可信代理网段:set_real_ip_from 100.64.0.0/10;(云厂商 SLB 常用)set_real_ip_from 192.168.0.0/16;(内网 LB 或 CDN 回源段)set_real_ip_from 172.16.0.0/12;set_real_ip_from 10.0.0.0/8; - 指定从哪个请求头提取 IP 链路:
real_ip_header X-Forwarded-For; - 开启递归解析:
real_ip_recursive on;—— 这样 Nginx 才会从X-Forwarded-For列表中,从右往左逐个剔除已知可信代理 IP,最终留下最左边那个未被白名单覆盖的 IP,即用户真实 IP - 配置生效后,
$remote_addr变量自动更新为真实 IP,日志格式中直接使用它即可
日志格式建议与常见误区
- 推荐日志格式(在
http块中定义):log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
注意:这里$remote_addr已是真实 IP(经 realip 处理后),而$http_x_forwarded_for仅作辅助审计,不用于业务逻辑 - 不要直接在日志里写
$http_x_forwarded_for当主 IP 字段——它可能被客户端篡改,且含多个 IP,格式不稳定 - 若未启用
real_ip_recursive on,即使写了set_real_ip_from,Nginx 仍可能取到倒数第二个 IP(即最后一级可信代理的 IP),而非用户真实 IP
反向代理链路上的头透传必须一致
- 每一级 Nginx(包括 CDN、WAF、SLB、自建 LB)都需配置:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-Proto $scheme; -
$proxy_add_x_forwarded_for会自动继承旧值并追加当前$remote_addr,保证链路完整;而$remote_addr是上一跳的出口 IP,不能直接当用户 IP 使用
PHP 或其他后端读取时不要绕过 Nginx realip 处理
- 即使 Nginx 已正确设置
$remote_addr,PHP 代码仍不应依赖$_SERVER['REMOTE_ADDR']—— 它反映的是 PHP-FPM 与 Nginx 的连接来源(通常是127.0.0.1) - 应统一使用 Nginx 设置的
X-Real-IP或X-Forwarded-For头,并结合可信链路校验逻辑(如只取X-Forwarded-For中第一个 IP,且该 IP 不在任何已知代理网段内)
不复杂但容易忽略











