Nginx将REMOTE_ADDR替换为X-Forwarded-For

29

我对Nginx很陌生,感觉很混乱。我的服务器设置得很好,但问题是,由于我的服务器受到HTTP代理的保护;所以它记录的是代理服务器的IP而不是真实用户的IP。

我尝试将$_SERVER['REMOTE_ADDR'];设置为$_SERVER['X-Forwarded-For'];,但我得到了未定义索引错误,所以我猜我必须在Nginx中定义X-Forwarded-For? 但我不知道如何做,我只有一个简单的设置,就是Nginx和PHP。没有更多的内容,也没有更少的内容。

我已经在网上搜索了很多,但找不到友好易懂的信息。

如果有需要,我可以访问源代码。我尝试了很多解决方案,但都无济于事。

4个回答

39

正确的方法是在nginx中设置real_ip_header配置。

使用可信的HTTP代理IP的示例:

set_real_ip_from 127.0.0.1/32;
real_ip_header X-Forwarded-For;

这样,$_SERVER['REMOTE_ADDR'] 将会在 PHP fastcgi 中被正确填充。

文档链接 - nginx.org


1
我在各个地方都寻找一个真正有效的解决方案。非常感谢!太棒了!只需将其放入您的服务器 { location ~ .php$ {块部分。它就可以工作了!做得好! - CGray
1
使用 0.0.0.0/0::/0 来匹配所有 IP 地址。 - pravdomil

8

$http_x_forwared_for 可能包含多个IP地址,其中第一个应该是客户端的IP地址。 REMOTE_ADDR 只应该是客户端的IP地址。

因此,在您的 nginx.conf 中使用正则表达式,您可以将 REMOTE_ADDR 设置为 $http_x_forwarded_for 的第一个IP地址,如下所示:

  set $realip $remote_addr;
  if ($http_x_forwarded_for ~ "^(\d+\.\d+\.\d+\.\d+)") {
    set $realip $1;
  }
  fastcgi_param REMOTE_ADDR $realip;

1
由于在http块中无法使用set指令,因此最好使用map代替。 - antonbormotov
这个不能直接使用,也不支持IPv6地址! - LassePoulsen
@LassePoulsen 是的,这个正则表达式只适用于IPv4,但我相信修改它以适用于IPv6是可能的。还有什么问题“原样”无法解决吗? - fredrik
以防万一,有一个官方的Nginx模块ngx_http_realip_module,其中包含set_real_ip_fromreal_ip_recursive指令,正如@Razvan Grigore在这个SE问题的答案中提到的,专门用于这个目的。相关链接:http://nginx.org/en/docs/http/ngx_http_realip_module.html - undefined

7
@fredrik的回答还有一个补充。
使用map指令设置$real_ip可能会更好:
map $http_x_forwarded_for $real_ip {
        ~^(\d+\.\d+\.\d+\.\d+) $1;
        default $remote_addr;
    }

然后,在fastcgi_params文件或位置块中设置fastcgi_param REMOTE_ADDR

fastcgi_param  REMOTE_ADDR          $real_ip;

编辑:变量名称中的错字已经修正。


-1

我解决了自己的问题,由于PHP通过FastCGI进行过滤,我只需添加一个FastCGI参数,将REMOTE_ADDR设置为变量http_x_forwarded_for,类似于以下内容:

fastcgi_param REMOTE_ADDR $http_x_forwarded_for;

2
这是一种方式,但是如果请求不是通过代理而来,例如从localhost进行的测试请求,你该怎么处理? - Brad
5
不要这样做。如果原始客户端发送了X-Forwarded-For头部(代理服务器会这样做),那么你的REMOTE_ADDR将会有两个逗号分隔的IP地址,导致此方法失效。 - Konstantin Pereiaslov
1
这对我的情况很有帮助,因为我可以从不同的头部(Cloudflare客户端IP)获取真实的IP地址。 - Tom St

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接