Nginx访问日志中真实客户端IP获取
很多人在Nginx后面挂CDN或负载均衡后,打开access.log一看,记录的全是代理服务器IP,比如127.0.0.1或内网地址,根本找不到真实访客。
这个问题的根源是Nginx默认只记录直接连到它的TCP对端IP,也就是代理IP。
要拿到真实客户端IP,通常需要借助X-Forwarded-For请求头,再配合Nginx的real_ip模块做一层解析。
下面直接给出可落地的配置方法,适合零基础用户复制执行。
先确认你的代理链路
动手之前,先理清请求经过了哪些代理。
常见场景有两种:
- 单层代理:客户端 → CDN/Nginx → 后端Nginx。
- 多层代理:客户端 → CDN → 负载均衡 → Nginx。
不管几层,只要上游代理在转发请求时追加了X-Forwarded-For头,Nginx就能从里面提取出真实客户端IP。
你只需要搞清楚最后一层接入代理的IP段,比如CDN的回源IP段、负载均衡的IP,或者干脆写0.0.0.0/0(只在完全可信内网时这么做)。
Nginx获取真实IP的核心配置
在nginx.conf的http块或对应server块中,加入以下配置:
# 构造出可用的代理IP段,通常写最靠近本机的代理IP
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 203.0.113.10; # 你的CDN回源IP
# 从X-Forwarded-For头取真实IP
real_ip_header X-Forwarded-For;
# 开启递归查找
real_ip_recursive on;
配置项说明:
set_real_ip_from:声明哪些IP是可信代理。Nginx会忽略来自这些IP的X-Forwarded-For值,防止伪造。real_ip_header:指定从哪个头获取真实IP,这里用X-Forwarded-For。real_ip_recursive on:当X-Forwarded-For里有多个IP时,Nginx会从右往左找第一个不在set_real_ip_from列表里的IP作为客户端IP。比如头是1.2.3.4, 10.0.0.5,且10.0.0.0/8在信任列表里,最终记录1.2.3.4。
保存后用nginx -t检查语法,再执行systemctl reload nginx或nginx -s reload。
配置后如何验证结果
修改完别急着看日志,先模拟请求。
在服务器上执行:
curl -H "X-Forwarded-For: 8.8.8.8" http://你的域名/test
然后查看访问日志:
tail -n 5 /var/log/nginx/access.log
如果日志里出现的地址是8.8.8.8,说明real_ip模块生效了。
再配合log_format里的$remote_addr变量,记录的就是真实客户端IP。
注意,$proxy_add_x_forwarded_for会在原头上追加你的本机IP,一般用于传递给更下游的服务,不会影响$remote_addr的解析结果。
几个容易踩的坑
信任列表写得太宽。
直接把set_real_ip_from 0.0.0.0/0;意味着接受任何来源的X-Forwarded-For,攻击者可以随便伪造IP,导致日志污染和风控失效。
生产环境应尽量列出准确的代理IP段,或者使用类似geo模块配合白名单。
real_ip_recursive 设为 off 或缺失。
当链路上有两个代理时,X-Forwarded-For里会有两个IP。
如果没开启递归,Nginx默认取最左边的IP,可能取到上一级代理的IP,而不是真实客户端。
建议显式设置为on。
只在server块配置,忘记http块。
有时候虚拟主机里覆盖了配置,导致某些server不生效。
建议在http块统一配置,再在需要覆盖的server里单独调整。
日志格式也要顺手检查
如果你的log_format里写的是$http_x_forwarded_for,那看到的仍可能是原始头内容,而且包含多个IP。
真正要使用的是$remote_addr,它经过real_ip模块处理后就是清洗后的客户端IP。
例如:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '; # 只记录真实IP,不再用$http_x_forwarded_for
配置完记得重载Nginx并再次测试。
如果你现在使用的环境是宝塔面板,可以在Nginx管理里的“配置文件”或“性能调整”中直接修改,位置相同,改动后同样要重载Nginx。
简单总结一下,要让Nginx访问日志记录真实客户端IP,核心就三步:确认代理来源,配好set_real_ip_from和real_ip_header,开启real_ip_recursive并验证日志输出。
只要信任列表准确,你就能在多级转发下拿到干净的访客IP,后续再做日志分析、限流或封禁也更有依据。