必须启用http_realip_module并配置set_real_ip_from、real_ip_header和real_ip_recursive on,使$remote_addr自动更新为经可信代理链路校验后的用户真实ip,日志中直接使用$remote_addr即可准确记录。

要在 Nginx 访问日志中准确记录客户端真实 IP,不能只靠 X-Forwarded-For 头简单写入,必须配合可信代理识别和变量替换。否则日志里记的会是 CDN、SLB 或上一级代理的 IP,而不是用户真实地址。
启用 realip 模块并配置可信代理来源
确保 Nginx 编译时启用了 http_realip_module(多数发行版已内置,可通过 nginx -V 2>&1 | grep http_realip 确认)。在 http 块中添加:
-
set_real_ip_from 100.64.0.0/10;(云厂商 SLB 常用网段) -
set_real_ip_from 192.168.0.0/16;(内网负载均衡或回源段) set_real_ip_from 172.16.0.0/12;set_real_ip_from 10.0.0.0/8;real_ip_header X-Forwarded-For;real_ip_recursive on;
开启递归后,Nginx 会从 X-Forwarded-For 列表中从右往左逐个剔除已声明的可信代理 IP,最终把最左边那个未被白名单覆盖的 IP 赋给 $remote_addr 变量。
定义日志格式并使用 $remote_addr
配置生效后,$remote_addr 就已经是真实客户端 IP,直接在日志格式中引用即可:
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent"';- 然后在
server或location中启用:access_log /var/log/nginx/access.log main;
不建议用 $http_x_forwarded_for 或 $http_x_real_ip 直接写日志——它们可能被伪造,且未经过可信链路校验。
确保上游代理正确透传头信息
如果前面有 CDN、WAF 或多级 Nginx 代理,每一层都必须统一配置头透传:
proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;
$proxy_add_x_forwarded_for 会自动继承旧值并追加当前 $remote_addr,保证链路完整;而 $remote_addr 是上一跳出口 IP,本身不是用户 IP,不能跳过 realip 处理直接使用。
后端应用不要绕过 Nginx 的 realip 处理
即使 Nginx 已正确设置 $remote_addr,PHP、Java 等后端仍不应依赖 $_SERVER['REMOTE_ADDR'](它通常是 127.0.0.1 或本地代理 IP):
- PHP 应读取
$_SERVER['HTTP_X_REAL_IP']或经校验后的$_SERVER['HTTP_X_FORWARDED_FOR']首项 - Java Tomcat 推荐配置
RemoteIpValve,并设置remoteIpHeader="X-Forwarded-For"和protocolHeader="X-Forwarded-Proto" - 关键逻辑:只取
X-Forwarded-For中第一个 IP,且该 IP 不在任何已知代理网段内
不复杂但容易忽略











