一、说明

当服务前面有多层代理服务,例如CDN,经过多层代理服务器,服务这边显示的IP 为上层代理的IP,而不是用户ip

二、使用realip获取

已确定多层代理的IP或IP段

nginx官方文档:

https://nginx.org/en/docs/http/ngx_http_realip_module.html

优点:程序不需要改动,直接使用remote_addr即可获取IP地址

缺点:ip地址有可能被伪装,而且需要知道所有代理节点的ip地址或者ip段

set_real_ip_from :真实服务器上一级代理的IP地址或者IP段,可以写多行

real_ip_header :从哪个header头检索出要的IP地址

real_ip_recursive :递归排除IP地址,ip串从右到左开始排除 set_real_ip_from 里面出现的IP,如果出现了未出现这些ip段的IP,那么这个IP将被认为是用户的IP,赋值到 remote_addr 变量。

nginx 代理多个内网ip(nginx多层代理获取用户真实IP)(1)

例如,服务器$http_x_forwarded_for获取到的IP地址串如下:

117.61.240.104,10.0.32.45,10.0.32.41,10.0.32.42

在real_ip_recursive off或者不设置的情况下

192.168.50.121出现在set_real_ip_from中,排除掉,接下来的ip地址便认为是用户的ip地址

如下配置:

set_real_ip_from 10.0.32.45;

set_real_ip_from 10.0.32.41;

set_real_ip_from 10.0.32.42;

real_ip_header X-Forwarded-For;

real_ip_recursive off;

那么获取的IP为10.0.32.41

real_ip_recursive on开启,每层代理的IP 都加上,如果是同网段,可以写成IP段

set_real_ip_from 10.0.32.45;

set_real_ip_from 10.0.32.41;

set_real_ip_from 10.0.32.42;

real_ip_header X-Forwarded-For;

real_ip_recursive on;

在real_ip_recursive on的情况下

10.0.32.45,10.0.32.41,10..0.32.42都出现在set_real_ip_from中,仅仅117.61.240.104没出现,那么他就被认为是用户的ip地址,并且赋值到remote_addr变量

配置可以添加在http, server, location 下

注意问题

设置后 $http_x_forwarded_for 和 $proxy_add_x_forwarded_for 变量的不同

$remote_addr 会添加到 $proxy_add_x_forwarded_for 变量中,$proxy_add_x_forwarded_for 就会有重复的IP

$http_x_forwarded_for 变量默认是比$proxy_add_x_forwarded_for 少一层,这时与

$remote_addr 相同为用户真实IP

最后的配置

...

location / {

# 限制内网

set_real_ip_from 10.0.32.45;

real_ip_header X-Forwarded-For;

real_ip_recursive on;

allow 10.0.0.0/8;

deny all;

proxy_pass http://demo;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $http_x_forwarded_for;

}

...

三、获取x-forwarded-for头

不确定多层代理的IP时

优点:可以获取到用户的IP地址

缺点:程序需要改动,以及用户IP有可能是伪装的

通过多层代理时,而且不知道多层代理的真实地址是多少时,默认的 $remote_addr 记录的是上层代理服务器的IP, $http_x_forwarded_for 第一位IP为用户的真实IP, 后面为每层代理服务器的IP, 所以获取 $http_x_forwarded_for 记录的第一层IP,赋值给新定义 $client_real_ip 为用户真实IP

nginx 代理多个内网ip(nginx多层代理获取用户真实IP)(2)

1、单个IP或者IP段匹配

vim nginx.conf

http {

....

....

....

## 获取多层代理用户真实IP

map $http_x_forwarded_for $client_real_ip {

"" $remote_addr;

~^(?P<firstAddr>[0-9\.] ),?.*$ $firstAddr;

}

....

....

}

vim conf.d/demo.conf

server{

listen 80;

.......

server_name aptly.uniontech.com ;

........

location /api {

# 没有代理时的配置

allow 10.0.0.0/8;

deny all;

# 匹配远程用户真实IP

if ($client_real_ip !~ "10.*.*.*") {

return 403;

}

proxy_pass http://aptly_api;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

2、多个IP时,访问权限设置

一层代理时使用 $http_x_forwarded_for 获取用户IP

map $http_x_forwarded_for $rbac_access {

...

}

多层代理时,使用前面定义的 $client_real_ip 获取用户IP进行访问控制

map $client_real_ip $rbac_access {

default false; # 默认false拒绝

~*10.*.*.* true; # 内网IP

115.28.139.68 true; # 商店

121.36.167.218 true; # hwy-chinauos-02

159.138.53.176 true; # bbs-next.deepin.org

47.56.88.11 true; # bbs.chinauos.com

114.55.93.175 true; # k8s

47.97.105.51 true; # k8s

47.96.99.187 true; # 阿里云集群预生产环境

120.27.220.167 true; # www.chinauos.com

47.242.84.233 true; # uniontech hk bbs.deepin.org

47.75.108.56 true; # uniontech hk bbs.deepin.org

123.116.158.134 true; # 北京普天

121.196.167.180 true; # 深圳 商店测试服务器

47.111.86.15 true; # k8s store 商店 测试

113.57.152.160 true; # 武汉联通出口

116.62.132.68 true; # 阿里云

47.115.116.186 true; # 消费者事业部 应用商店CMS管理平台

}

server{

......

......

location / {

## 匹配map, 不为ture, 返回403拒绝

if ( $rbac_access = 'false') { return 403; }

proxy_pass http://rbac10002;

proxy_set_header Host $host;

proxy_set_header X-Real-IP $remote_addr;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

......

}

nginx 代理多个内网ip(nginx多层代理获取用户真实IP)(3)

,