要让Nginx日志准确记录客户端真实IP,必须启用http_realip_module,配置set_real_ip_from声明可信代理网段、real_ip_header指定X-Forwarded-For头、real_ip_recursive on开启递归解析,使$remote_addr变量本身变为真实IP,并在log_format中直接使用$remote_addr。

要让 Nginx 访问日志准确记录客户端真实 IP,而不是 CDN 节点的 IP,核心不是“读取 X-Forwarded-For 头”,而是让 $remote_addr 变量本身变成真实 IP —— 这需要启用并正确配置 http_realip_module 模块。
必须启用 realip 模块并声明可信代理
Nginx 默认把直连它的 IP(即 CDN 节点 IP)当作 $remote_addr。要替换它,必须告诉 Nginx 哪些上游是可信代理:
- 确认模块已加载:运行 nginx -V 2>&1 | grep -o http_realip,有输出即支持
- 在 http 或 server 块中添加可信网段,例如 CDN 常用段:
set_real_ip_from 100.64.0.0/10;
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 才会从 XFF 列表里,从右往左剔除所有已知可信代理 IP,留下最左边那个未被白名单覆盖的地址,也就是用户真实 IP
日志格式中直接使用 $remote_addr
配置生效后,$remote_addr 就已是真实 IP,无需改用 $http_x_forwarded_for 或 $realip_remote_addr(后者仅在旧版或特殊场景下备用):
- 在 http 块中定义日志格式:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"'; - 确保站点 access_log 引用该格式:
access_log /var/log/nginx/access.log main; - 不要用 $http_x_forwarded_for 替代 $remote_addr —— 它可能被伪造、含多个 IP、格式不稳,仅适合审计参考
验证上游是否正确传递 XFF 头
如果日志仍显示 CDN IP,大概率是前端没传 X-Forwarded-For,或传错格式:
- 检查 CDN 控制台或文档,确认已开启“透传客户端 IP”功能(如 Cloudflare 的 “True Client IP”、阿里云 CDN 的“回源携带 X-Forwarded-For”)
- 若你控制前置代理(如自建 LB 或另一层 Nginx),需确保它设置了:
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - 避免重复添加 XFF 头导致内容异常(如出现 203.208.60.1, 203.208.60.1, 1.1.1.1),realip 模块依赖干净的 IP 链路
常见误区提醒
以下做法看似简单,实则不可靠:
- 只写 log_format ... $http_x_forwarded_for ... —— 无法过滤伪造 IP,且多级代理时取值不准
- 用 set_real_ip_from 0.0.0.0/0 —— 相当于信任所有 IP,完全丧失安全校验,极易被伪造绕过
- 漏掉 real_ip_recursive on —— 即使配置了 set_real_ip_from,Nginx 也只会取 XFF 最右一个非可信 IP,通常是最后一级代理 IP,而非用户真实 IP


















