Nginx环境下如何正确获取IP_Nginx配置与PHP获取IP对接方法【配置】

5次阅读

nginx 默认 $remote_addr 仅反映直连ip,经cdn/slb/反代时需配置 set_real_ip_from、real_ip_header 及 real_ip_recursive,并在php中直接使用 $_server[‘remote_addr’](已由nginx修正),日志应优先用 $realip_remote_addr。

Nginx环境下如何正确获取IP_Nginx配置与PHP获取IP对接方法【配置】

直接说结论:Nginx 默认的 $remote_addr 只能拿到客户端直连 IP,如果前端有 CDN、SLB 或反向代理,必须靠 X-forwarded-For(或 X-Real-IP)+ Nginx 配置 + PHP 主动读取三者配合,缺一不可;否则 PHP 中 $_SERVER['REMOTE_ADDR'] 永远是上一级代理的 IP。

为什么 $remote_addr 不可靠?

它只反映 TCP 连接发起方的 IP —— 在有 CDN、WAF、负载均衡器或公司内部反代时,这个值就是 CDN 节点、LB 机器或 Nginx 自身的内网 IP,不是真实用户 IP。常见现象包括:

  • 所有访问日志里 $remote_addr 都是同一个内网地址(如 10.0.1.5
  • PHP 中 $_SERVER['REMOTE_ADDR'] 固定为 127.0.0.1 或云厂商 LB 内网 IP
  • 基于 IP 的限流、封禁、地域判断全部失效

Nginx 必须设置 set_real_ip_fromreal_ip_header

光在 upstream 里加 proxy_set_header X-Real-IP $remote_addr 没用。Nginx 要“信任”某个来源的 X-Forwarded-For,得显式声明可信代理段。否则 $realip_remote_addr 不会更新,log_format 里用 $remote_addr 依然错。

正确做法:

立即学习PHP免费学习笔记(深入)”;

  • httpserver 块中添加可信代理网段:
    set_real_ip_from 10.0.0.0/8;<br>set_real_ip_from 172.16.0.0/12;<br>set_real_ip_from 192.168.0.0/16;<br>set_real_ip_from 127.0.0.1;
  • 指定从哪个 header 提取真实 IP:
    real_ip_header X-Forwarded-For;(CDN 通用)或 real_ip_header X-Real-IP;(部分自建反代习惯用)
  • 可选但推荐:real_ip_recursive on;,让 Nginx 递归解析 X-Forwarded-For 最左非可信 IP(例如 X-Forwarded-For: 203.0.113.5, 198.51.100.2, 10.0.1.3,若最后一个是可信代理,则取 198.51.100.2

PHP 中不能直接信 $_SERVER['HTTP_X_FORWARDED_FOR']

这个值可能被客户端伪造,Nginx 未做清洗前直接用极不安全。正确方式是依赖 Nginx 注入的 $_SERVER['REMOTE_ADDR'] —— 它在启用 real_ip_* 后已自动替换为真实客户端 IP。

验证是否生效:

  • 写个 phpinfo(); 页面,看 $_SERVER['REMOTE_ADDR'] 是否已是公网 IP
  • 若仍是代理 IP,说明 set_real_ip_from 没覆盖到实际代理出口网段(比如云厂商 LB 用的是 100.64.0.0/10,需补上)
  • 避免手写解析逻辑:explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0] 是危险且多余的

日志和 access_log 中记录真实 IP 的写法

别再用 $remote_addr 写日志。启用 realip 后,$remote_addr 已是真实 IP,可直接用;但更稳妥是显式使用 $realip_remote_addr(Nginx ≥1.11.0):

log_format main '$realip_remote_addr - $remote_user [$time_local] "$request" '                  '$status $body_bytes_sent "$http_referer" '                  '"$http_user_agent" "$http_x_forwarded_for"';

注意:$realip_remote_addr 在未匹配任何 set_real_ip_from 时会退化为 $remote_addr,所以它比硬写 $remote_addr 更健壮。

最易忽略的一点:set_real_ip_from 的 IP 段必须精确匹配你实际的上游代理出口地址,多一个 /32 少一个 /16 都会导致真实 IP 解析失败。上线前务必用 curl -H "X-Forwarded-For: 203.0.113.5" http://your-site/ 配合 nginx -t && nginx -s reload 验证。

text=ZqhQzanResources