nginx实战之反向代理

1、反向代理

所谓反向代理就是nginx接受到请求后,将请求转发给内部的一台服务器处理,比如我们启动了一个tomcat是8081端口,但是我们防火墙不会开放8081端口,只会开放nginx的80端口,那么我们需要再nginx上进行反向代理配置,让到80端口的请求转发给8081端口处理,这样安全性也有很大的提高,并且后续可以进行负载均衡:80端口进来,从代理的多台服务器按策略选一台处理。

1.1、8081端口服务搭建

我们这里就不启动tomcat来模拟服务了,直接在nginx上配置个8081端口的server即可,nginx配置文件做如下处理

server {
        listen       8081;
        server_name  localhost;
        location / {
            root   html;
            index  index8081.html index.htm;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

这里的意思是,请求从8081进来,会返回index8081.html的页面,这个页面会在nginx目录下面的html里面,内容如下

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    html { color-scheme: light dark; }
    body { width: 35em; margin: 0 auto;
    font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
    <h1>Welcome to 8081!</h1>
</body>
</html>

到这里就相当于有一个新的服务了。

1.2、nginx反向代理配置

下面我们来配置负载均衡,我们在nginx.conf的http配置里面新增upstream.

 upstream first { 
   server  localhost:8081; 
}

然后,在80的server进行代理配置

server {
        listen       80;
        server_name  localhost;
        location / {
        #反向代理配置
            proxy_pass         http://first; 
            proxy_set_header   Host             $host; 
            proxy_set_header   X-Real-IP        $remote_addr; 
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }

1.3、重新启动nginx

我们可以先用-t命令校验下配置文件是否正确

./nginx -t

检查正确后,进行重新加载

./nginx -s reload

1.4、访问测试

我们访问80端口,然后可以看到返回了index8081.html的页面内容,表面反向代理成功。

1.5、proxy_set_header

我们看到,反向代理设置的时候,有进行proxy_set_header设置,那这个的作用是什么呢?

即允许重新定义或添加字段传递给代理服务器的请求头,简而言之,proxy_set_header 就是可设置请求头-并将头信息传递到服务器端,不属于请求头的参数中也需要传递时,重定义下即可!

主要有三个参数需要设置

Host

若客户端发过来的请求header中有HOST这个字段,$http_host和$host表示的就是原始请求

X-Real-IP

是指客户端的真实IP,如果设置了$remote_addr这个值,后端服务器就能获取到客户端的真实IP

X-Forwarded-For

这个变量的值有$proxy_add_x_forwarded_for,可以真实的显示出客户端原始ip。

我们这里来测试下

环境搭建

在本机搭建一个springboot应用,springboot应用搭建方法参考:从官网开始用IDEA在JDK1.8环境搭建springboot2.7.14项目,然后代码如下

@RestController
public class DemoController {
    @GetMapping("/hello")
    public Map<String,Object> hello(HttpServletRequest request){
        Map<String,Object> result = new TreeMap<String,Object>();
        result.put("hello","Hello World");
        String scheme = request.getScheme();
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        String xRealIp = request.getHeader("X-Real-IP");
        String host = request.getHeader("Host");
        String serverName = request.getServerName();
        int serverPort = request.getServerPort();
        String remoteName = request.getRemoteAddr();
        int remotePort = request.getRemotePort();
        result.put("scheme",scheme);
        result.put("serverName",serverName);
        result.put("serverPort",serverPort);
        result.put("remoteName",remoteName);
        result.put("remotePort",remotePort);
        result.put("xForwardedFor",xForwardedFor);
        result.put("xRealIp",xRealIp);
        result.put("host",host);
        return result;
    }
}

我本机的ip为:192.168.192.1
nginx所在的ip:192.168.192.11

nginx的反向代理的配置为

upstream first { 
   server  192.168.192.1:8080; 
}
server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass         http://first; 
            #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暴露的80服务就是反向代理到我本机启动的springboot应用。下面我们来测试proxy_set_header的作用

不配置proxy_set_header的测试

我们上面是把proxy_set_header都注释了,此时在浏览器上访问
http://192.168.192.11/hello
返回了

{"hello":"Hello World","host":"first","remoteName":"192.168.192.11","remotePort":35058,"scheme":"http","serverName":"first","serverPort":80,"xForwardedFor":null,"xRealIp":null}

可以看到完全没有拿到任何客户端的信息.

配置proxy_set_header的测试

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

在浏览器上访问
http://192.168.192.11/hello
返回了

{"hello":"Hello World","host":"192.168.192.11","remoteName":"192.168.192.11","remotePort":35060,"scheme":"http","serverName":"192.168.192.11","serverPort":80,"xForwardedFor":"192.168.192.1","xRealIp":"192.168.192.1"}

request.getRemoteAddr():获取的永远都是代理对象的IP
X-Forwarded-For和X-Real-IP:都获取了客户端的真实IP

X-Forwarded-For和X-Real-IP有什么区别呢

我们上面的例子发现,这两个获取的都是客户端的真实IP地址,其实如果只有一个反向代理服务器,那结果都是一样的,但是如果有多个,这里可以就用一个nginx来模拟一下。配置如下

我们首先在nginx配置一个服务,代理到我们的springboot应用.

upstream second { 
   server  192.168.192.1:8080; 
}
server {
        listen       8081;
        server_name  localhost;
        location / {
            proxy_pass         http://second; 
            proxy_set_header   Host             $http_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服务器代理了,端口是8081,我们再配置一个80端口代理到8081,就模拟了两台代理服务器的情况

upstream first { 
   server  localhost:8081; 
}
server {
        listen       80;
        server_name  localhost;
        location / {
            proxy_pass         http://first; 
            proxy_set_header   Host             $host; 
            proxy_set_header   X-Real-IP        $remote_addr; 
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

我们再尝试在本机的浏览器请求:http://192.168.192.11/hello,返回了

{"hello":"Hello World","host":"192.168.192.11","remoteName":"192.168.192.11","remotePort":35086,"scheme":"http","serverName":"192.168.192.11","serverPort":80,"xForwardedFor":"192.168.192.1, 127.0.0.1","xRealIp":"127.0.0.1"}

可以看到X-Real-IP获取的就不是客户端的地址了,而是第一次代理发起的地址,但是我们的X-Forwarded-For却有全部的客户端IP地址,我们想要获取真实客户端,只需要获取X-Forwarded-For第一个即可。

总结:X-Forwarded-For记录服务器的地址,会把记录添加到结尾,X-Real-IP用来记录服务器的地址,它不把记录添加到结尾,而是直接替换。所以用X-Forwarded-For就不会错。

相关文章

Nginx反向代理原理详解(图文全面总结)

关注△mikechen△,十余年BAT架构经验倾囊相授!大家好,我是mikechen睿哥。Nginx是大型架构的必备技能,下面我就重点来详解Nginx反向代理原理@mikechenNginx反向代理反...

Nginx反向代理

Nginx配置反向代理在server块中配置 #监听80端口 listen 80; #监听的ip或域名 server_name...

听说你的资源被盗用了,那你知道 Nginx 怎么防盗链吗?

简单有效的防盗链手段场景如果做过个人站点的同学,可能会遇到别人盗用自己站点资源链接的情况,这就是盗链。说到盗链就要说一个 HTTP 协议的 头部,referer 头部。当其他网站通过 URL 引用了你...

完整版nginx反向代理配置

完整版nginx反向代理配置项目发布了只提供了一个ip和端口使用。要完成前后分离项目的部署,因此需要把后端服务代理到前端访问的域名和端口上去,因此用上了nginx的反向代理。我们找到了nginx的配置...

使用Nginx搭建反向代理

反向代理的好处:可以隐藏真实服务器ip地址,而且一个端口运行多个应用,每个应用端口号不一样。那么如何使用nginx搭建反向代理进入安装好的nginx目录,找到nginx.conf文件并打开编辑找到se...