nginx+tomcat 获取正确的remoteAddr

一、问题背景

通过nginx来反向代理客户端请求,经过nginx中转转发给tomcat服务器,但发现tomcat服务器无法获取到正确的remoteAddr客户端地址,每次请求拿到的都是nginx所在服务器的IP

1、在tomcat服务器上查看tomcat服务日志,发现打印的请求日志,remoteAddr都是nginx的IP,而不是客户端的真实IP

## 192.168.200.251是nginx负载均衡服务器的地址
15:08:12 INFO    [tid:166453,Q:W228AFjoBcRQIzvVzOuJ] [L-Android]func=xxxx,remote=192.168.200.251

二、定位过程

1、nginx配置如下

location /myService {
                   proxy_set_header    X-FORWARDED-FOR $remote_addr;
                   proxy_set_header    X-Forwarded-Proto $scheme;
                   proxy_set_header    Host   $http_host;

                   #分发到tomcat服务器,192.168.201.228为tomcat服务器
                   proxy_pass http://192.168.201.228:9900;
               }

一开始以为是nginx配置有问题,设置了各种参数后,发现不是nginx问题,而是tomcat 的设置影响,在tomcat的conf/server.xml里RemoteIpValve项的InternalProxies

<Engine name="Catalina" defaultHost="localhost">
      <Host name="localhost" appBase="webapps"
            unpackWARs="false" autoDeploy="true"
        <Valve className="org.apache.catalina.valves.AccessLogValve"
        <!-- for nginx -->
        <Valve className="org.apache.catalina.valves.RemoteIpValve"
                 remoteIpHeader="X-FORWARDED-FOR"
                 protocolHeader="X-FORWARDED-PROTO"
                 internalProxies="192\.168\.*"/>
       </Host>
</Engine>

在使用Nginx代理网络请求时,设置proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for,但是在我的server端(Tomcat,Spring)收到的网络请求中却得不到这个x-forwarded-for的信息,原因是我的代理机器的IP地址与Tomcat RemoteIpValve中配置的默认内部代理地址internalProxies能匹配,于是x-forwarded-for信息被忽略并删除了。
(在server.xml中删除RemoteIpValve的默认配置,或者配置internalProxies为其他地址(如server的地址),就可以在x-forwarded-for中得到代理传输过来的信息。)

三、解决方案

1、将tomcat server.xml的internalProxies修改为nginx的IP,tomcat即可正确处理x-forwarded-for逻辑,获取正确的remoteAddr

<Engine name="Catalina" defaultHost="localhost">
      <Host name="localhost" appBase="webapps"
            unpackWARs="false" autoDeploy="true"
        <Valve className="org.apache.catalina.valves.AccessLogValve"
        <!-- for nginx -->
        <Valve className="org.apache.catalina.valves.RemoteIpValve"
                 remoteIpHeader="X-FORWARDED-FOR"
                 protocolHeader="X-FORWARDED-PROTO"
                 ## 修改internalProxies为nginx的IP
                 internalProxies="127\.0\.0\.1|192\.168\.200\.251"/>
       </Host>
</Engine>

2、重启tomcat,查看客户端请求日志,可以看到remoteAddr已经是客户端的真实IP而不是nginx的IP了

16:08:12 INFO    [tid:166453,Q:W228AFjoBcRQIzvVzOuJ] [L-Android]func=xxxx,remote=192.168.201.46

四、tomcat RemoteIpValve InternalProxies原理解析

X-Forwarded-For
x-forwarded-for在HTTP Header中,用来记录代理链的IP信息(不包括最后一次的代理)。

RemoteIpValve
Tomcat中的RemoteIpValve的设计意图是根据InternalProxies和TrustedProxies的配置,来过滤代理信息链X-Forwarded-For中的信息,获取代理机器之前的IP地址,并改写RemoteAddress的值。如果没有RemoteIpValve的处理,且有代理转发的情况下,则RemoteAddress永远为代理机器的IP地址,而不是代理机器之前发送数据包机器的IP地址(根据网络情况,可能为实际的用户IP地址)
具体逻辑如下图所示。

初始RemoteAddress为代理机器的IP地址,首先判断是否与InternalProxies匹配,如果不匹配,则RemoterIpValve不会做处理;如果匹配,则根据InternalProxies和TrustedProxies的配置来决定是否改写X-Forwarded-For和RemoteAddress以及X-Forwarded-By。

internalProxies默认情况下是有配置值的(貌似是常见的局域网IP地址),trustedProxies默认为null。而我的内网代理机器和我本机的IP地址都与InternalProxies匹配,则X-Forwarded-For中代理链的信息被删除。

参考:

  1. Tomcat 8的RemoteIpValve源码(Valve是阀门的意思),核心处理逻辑是invoke函数
  2. RemoteIpValve文档
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
您好!对于您提到的keepalived、nginxtomcat、redis和mysql,这些是常用于构建高可用和负载均衡的Web应用架构的关键组件。 1. Keepalived:Keepalived是一种开源的高可用解决方案,可以提供IP地址和服务的故障转移。它通常与负载均衡器(如Nginx)一起使用,以确保当主服务器故障时,备份服务器可以接管服务。 2. NginxNginx是一款高性能的开源Web服务器和反向代理服务器。它可以作为负载均衡器,在多个后端服务器(如Tomcat、Redis和MySQL)之间分发请求,并提供静态文件的高效传输。 3. TomcatTomcat是Java Servlet容器,用于部署和运行Java Web应用程序。它可以作为应用服务器与Nginx配合使用,通过反向代理将请求分发到多个Tomcat实例,以实现负载均衡和高可用性。 4. Redis:Redis是一种基于内存的开源键值存储数据库,被广泛用于缓存、会话存储和消息队列等场景。在Web应用架构中,Redis可以作为缓存层,提高数据读取速度,并减轻后端数据库(如MySQL)的负载。 5. MySQL:MySQL是一种流行的开源关系型数据库管理系统,常用于存储应用程序的持久化数据。它可以与Tomcat结合使用,作为后端数据库存储和管理数据。 以上是对keepalived、nginxtomcat、redis和mysql的简要介绍,它们在Web应用架构中扮演着不同的角色,以提供高可用、高性能和负载均衡的服务。如果您对其中任何一个组件有更具体的问题,我很乐意为您解答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Venlenter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值