广州总部电话:020-85564311
广州总部电话:020-85564311

广州网站建设-小程序商城开发-广州小程序开发-企业微信开发公司-网站建设高端品牌-优网科技

20年
互联网应用服务商
请输入搜索关键词
知识库 知识库

优网知识库

探索行业前沿,共享知识宝库

nginx反向代理之获取客户端IP(一)
发布日期:2025-04-15 18:23:18 浏览次数: 828 来源:重生之运维


前言

随着nginx的迅速崛起,越来越多公司将apache更换成nginx. 同时也越来越多人使用nginx作为负载均衡和反向代理, 并且代理前面可能还加上了CDN加速,但是随之也遇到一个问题:后端应用如何获取用户的真实IP地址。

nginx作为高性能反向代理服务器,在传递真实IP到后端的过程中,需要使用到ngx_http_proxy_module模块,此模块默认会编译。

常见配置

...
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
                      
    access_log          /var/log/nginx/access.log  main;

    include             mime.types;
    default_type        application/octet-stream;
    sendfile            on;
    keepalive_timeout   65;

    upstream ywnm {
       server 192.168.0.1;
       server 192.168.0.2;
    }
    server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass http://ywnm;
              # 下面三行为常见反向代理传递真实客户端IP的配置,如果配置在http{}中,则全局对所有server生效
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

...

在nginx中,我们可以通过$remote_addr变量来获取客户端的IP。获取了客户端IP之后,我们可以做很多事情如限速限流、用户画像等。但是如果客户端A通过反向代理B访问到后端服务C,假设后端服务是我们的nginx服务,那么后端服务$remote_addr获取到的是反向代理B的IP,因为直接访问C的是反向代理B而不是客户端A如果在客户端A和反向代理B之间有CDN加速或其他代理,那这个真实客户端A的IP又是如何传送到后端服务C的呢?

配置详解

proxy_set_header

在传递给后端服务器的请求头中,可以使用proxy_set_header 重新定义或添加字段。一般我们使用 proxy_set_header 向后端服务器传递一些必要的信息。

  • Host
    Host 是表明请求的主机名。默认情况下,Nginx 向后端服务器发送请求时,请求头中的 Host 字段是后端真实服务器的IP和端口。如果我们想让传递给后端服务器的 Host 字段,包含的是用户访问反向代理时使用的域名,就需要通过 proxy_set_header 设置 Host 字段,值可以为$host$http_host,区别是前者只包含IP,而后者包含IP和端口号。

  • X-Real-IP
    经过反向代理后,后端服务器无法直接拿到客户端的 ip,也就是说,在应用中使用request.getRemoteAddr() 获得的是 Nginx 的地址。通过 proxy_set_header X-Real-IP $remote_addr;,将客户端的 ip 添加到了 HTTP header中,让应用可以使用 request.getHeader(“X-Real-IP”) 获取客户端的真实ip。

  • X-Forwarded-For如果配置了多层反向代理,当一个请求经过多层代理到达后端服务器时,后端服务器通过X-Real-IP获得的就不是客户端的真实IP了。那么这个时候就要用到 X-Forwarded-For ,设置 X-Forwarded-For 时是增加,而不是覆盖,从客户的真实IP为起点,穿过多层级代理 ,最终到达后端服务器,都会被记录下来。

实战

下面通过实验,揭秘上述参数变量的工作原理

环境

角色ip软件及版本
客户端192.168.124.101nginx1.22.1
反向代理A192.168.124.170nginx1.22.1
反向代理B192.168.124.171nginx1.22.1
反向代理C192.168.124.172nginx1.22.1
后端web服务器192.168.124.173nginx1.22.1

客户端配置域名解析文件C:\Windows\System32\drivers\etc\hosts

192.168.124.170   www.ywnm.com

X-Real-IP

三个代理节点及后端web服务的nginx初始配置如下(基础配置部分省略):

反向代理A
http {
...
    log_format  main  '$remote_addr + "$http_host" + "$http_x_forwarded_for" + "$http_x_real_ip"';
    access_log logs/access.log main;

    server {
        listen       80;
        server_name  www.ywnm.com;
        location / {
            proxy_pass http://192.168.124.171;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
...
    }
}

反向代理B
http {
...
    log_format  main  '$remote_addr + "$http_host" + "$http_x_forwarded_for" + "$http_x_real_ip"';
    access_log logs/access.log main;

    server {
        listen       80;
        server_name  192.168.124.171;
        location / {
            proxy_pass http://102.168.124.172;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
...
    }
}

反向代理C
http {
...
    log_format  main  '$remote_addr + "$http_host" + "$http_x_forwarded_for" + "$http_x_real_ip"';
    access_log logs/access.log main;

    server {
        listen       80;
        server_name  192.168.124.172;
        location / {
            proxy_pass http://102.168.124.173;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
...
    }
}

后端web服务器
http {
...
    log_format  main  '$remote_addr + "$http_host" + "$http_x_forwarded_for" + "$http_x_real_ip"';
    access_log logs/access.log main;

    server {
        listen       80;
        server_name  192.168.124.173;
        location / {
            root   html/;
            index  index.html index.htm;
        }
...
    }
}

只在反向代理A设置X-Real-IP

三个节点都注释掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,并在节点BC上注释掉proxy_set_header X-Real-IP $remote_addr;,在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "192.168.124.101"
节点C:192.168.124.171 + "www.ywnm.com" + "-" + "192.168.124.101"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "-" + "192.168.124.101"

只在反向代理B设置X-Real-IP

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "-" + "192.168.124.170"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "-" + "192.168.124.170"

只在反向代理C设置X-Real-IP

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "-" + "-"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "-" + "192.168.124.171"

只在反向代理A/B设置X-Real-IP

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "192.168.124.101"
节点C:192.168.124.171 + "www.ywnm.com" + "-" + "192.168.124.170"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "-" + "192.168.124.170"

只在反向代理A/C设置X-Real-IP

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "192.168.124.101"
节点C:192.168.124.171 + "www.ywnm.com" + "-" + "192.168.124.101"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "-" + "192.168.124.171"

只在反向代理B/C设置X-Real-IP

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "-" + "192.168.124.170"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "-" + "192.168.124.171"

所有代理节点都设置X-Real-IP

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "192.168.124.101"
节点C:192.168.124.171 + "www.ywnm.com" + "-" + "192.168.124.170"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "-" + "192.168.124.171"

总结

  • X-Real-IP只是一个变量,后面的设置会覆盖前面的设置
  • 我们一般只在第一个代理设置proxy_set_header X-Real-IP $remote_addr;,然后在应用端直接引用$http_x_real_ip即可
  • X-Real-IP的值总为1个

X-Forward-For

三个代理节点及后端web服务的nginx初始配置同上

只在反向代理A设置X-Forward-For

三个节点都注释掉proxy_set_header X-Real-IP $remote_addr;,并在节点BC上注释掉proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;,在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "192.168.124.101" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "192.168.124.101" + "-"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "192.168.124.101" + "-"

只在反向代理B设置X-Forward-For

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "192.168.124.170" + "-"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "192.168.124.170" + "-"

只在反向代理C设置X-Forward-For

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "-" + "-"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "192.168.124.171" + "-"

只在反向代理A/B设置X-Forward-For

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "192.168.124.101" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170" + "-"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170" + "-"

只在反向代理A/C设置X-Forward-For

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "192.168.124.101" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "192.168.124.101" + "-"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "192.168.124.101, 192.168.124.171" + "-"

只在反向代理B/C设置X-Forward-For

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "-" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "192.168.124.170" + "-"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "192.168.124.170, 192.168.124.171" + "-"

所有代理节点都设置X-Forward-For

在客户端访问www.ywnm.com,各节点日志如下:

节点A:192.168.124.101 + "www.ywnm.com" + "-" + "-"
节点B:192.168.124.170 + "www.ywnm.com" + "192.168.124.101" + "-"
节点C:192.168.124.171 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170" + "-"
后端web服务器:192.168.124.172 + "www.ywnm.com" + "192.168.124.101, 192.168.124.170, 192.168.124.171" + "-"

总结

  • X-Forwarded-For是一个可叠加的过程,代理会把$remote_addr加入到X-Forwarded-For,发送到下一层
  • 我们看到在三层代理情况下无论如何设置,后端web服务器不可能从$http_x_forwarded_for拿到与它直连的代理服务器的ip(反向代C ip),此时我们可以使用$remote_addr(远程ip,表示直连的那台代理)
  • 在代理过程中至少有一个代理设置了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;否则后面代理或者应用服务器无法获得相关信息
  • 想要获取客户端IP(必须要在反向代理A设置了proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;我们取第一IP就好了)

优网科技,优秀企业首选的互联网供应服务商

优网科技秉承"专业团队、品质服务" 的经营理念,诚信务实的服务了近万家客户,成为众多世界500强、集团和上市公司的长期合作伙伴!

优网科技成立于2001年,擅长网站建设、网站与各类业务系统深度整合,致力于提供完善的企业互联网解决方案。优网科技提供PC端网站建设(品牌展示型、官方门户型、营销商务型、电子商务型、信息门户型、DIY体验、720全景展厅及3D虚拟仿真)、移动端应用(手机站APP开发)、微信定制开发(微信官网、微信商城、企业微信)、微信小程序定制开发等一系列互联网应用服务。


我要投稿

姓名

文章链接

提交即表示你已阅读并同意《个人信息保护声明》

专属顾问 专属顾问
扫码咨询您的优网专属顾问!
专属顾问
马上咨询
扫一扫马上咨询
扫一扫马上咨询

扫一扫马上咨询