$_server['remote_addr'] 返回 127.0.0.1 的典型场景是请求未经过公网网卡,如本地反向代理、cli调用或浏览器直连localhost;真实用户ip需通过可信代理透传并校验x-forwarded-for头获取。

PHP $_SERVER['REMOTE_ADDR'] 返回 127.0.0.1 的典型场景
这不是 PHP 本身的问题,而是请求根本没经过公网网卡——你的脚本实际被本地反向代理(如 Nginx/Apache)、CLI 调用、或浏览器直连 localhost 时触发。比如用 curl http://localhost/ 或在本地开的 VS Code Live Server 访问,$_SERVER['REMOTE_ADDR'] 必然为 127.0.0.1。
真实用户 IP 只会出现在「客户端 → 网络 → 服务器公网接口」链路中。如果中间有代理(尤其是你自建的 Nginx),默认不会透传原始 IP,PHP 就只能看到代理机器发来的连接地址。
检查是否被反向代理拦截(Nginx / Apache)
这是最常见原因。确认你的 Web 服务器配置里是否漏掉了透传头信息:
- Nginx 需确保
proxy_set_header X-Real-IP $remote_addr;和proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;已启用,且位于location块内 - Apache 需加载
mod_remoteip并配置RemoteIPHeader X-Forwarded-For,否则$_SERVER['HTTP_X_FORWARDED_FOR']不会被自动映射到$_SERVER['REMOTE_ADDR'] - 若用 Cloudflare、阿里云 SLB 等 CDN,它们会设置
X-Forwarded-For或Cf-Connecting-IP,但需在 PHP 中手动读取,不能依赖$_SERVER['REMOTE_ADDR']
PHP 中安全获取真实 IP 的写法
不要直接信任任何 HTTP 头——攻击者可伪造 X-Forwarded-For。必须结合可信代理 IP 白名单校验:
立即学习“PHP免费学习笔记(深入)”;
// 假设你只信任本机 Nginx(127.0.0.1)和内网网关(10.0.0.1)
$trustedProxies = ['127.0.0.1', '10.0.0.1'];
$clientIp = $_SERVER['REMOTE_ADDR'];
<p>if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ips = array_map('trim', explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
// 从右往左找第一个不在可信列表里的 IP(防伪造)
for ($i = count($ips) - 1; $i >= 0; $i--) {
if (!in_array($ips[$i], $trustedProxies)) {
$clientIp = $ips[$i];
break;
}
}
}</p><p>// 最终 $clientIp 才是较可靠的真实客户端 IP
注意:$_SERVER['HTTP_X_REAL_IP'] 在 Nginx 中需显式配置 proxy_set_header X-Real-IP $remote_addr; 才存在,且同样不可信,除非你知道上游一定是可信代理。
本地开发环境误判的快速验证法
运行以下命令,绕过浏览器和本地代理,直连 PHP 内置服务器并观察输出:
php -S 0.0.0.0:8000 -t ./public # 然后在另一台机器上 curl http://你的局域网IP:8000/test.php
如果此时 $_SERVER['REMOTE_ADDR'] 仍是 127.0.0.1,说明请求压根没离开本机;如果是 192.168.x.x 或公网 IP,那问题就出在你常用的访问方式(比如 hosts 绑定、Docker network 模式、WAMP/XAMPP 的监听地址配置)。
真实生产环境里,127.0.0.1 出现在访问日志中往往意味着健康检查探针、监控脚本或内部服务调用——不是 bug,是特征。别一看到它就急着改代码,先抓包或打日志确认请求来源链路。











