码迷,mamicode.com
首页 > 其他好文 > 详细

nginx 反向代理

时间:2018-12-04 21:12:39      阅读:238      评论:0      收藏:0      [点我收藏+]

标签:http   防火墙   强制   使用   类型   sub   ecc   客户端   时代   

目录

1. 正向代理和反向代理

1.1 正向代理

正向代理(Forward Proxy)通常都被简称为代理,就是在用户无法正常访问外部资源,比方说受到GFW的影响无法访问twitter的时候,我们可以通过代理的方式,让用户绕过防火墙,先访问代理服务器,然后告诉代理服务器去访问twitter,取到信息后返回给我们,从而连接到目标网络或者服务。。

技术分享图片

1.2 反向代理

反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

技术分享图片

1.3 正向代理和反向代理的区别

技术分享图片

技术分享图片

正向代理中,proxy和client同属一个LAN,对server透明; 反向代理中,proxy和server同属一个LAN,对client透明。
正向代理隐藏真实客户端,反向代理隐藏真实服务端

2. 反向代理的好处

2.1 保护了真实的web服务器

web服务器对外不可见,外网只能看到反向代理服务器,而反向代理服务器上并没有真实数据,因此,保证了web服务器的资源安全,我们还可以在代理服务器层增加waf防火墙,这样可以保证发往真是服务器的请求更加安全。

2.2 节约了有限的IP地址资源

企业内所有的网站共享一个在internet中注册的IP地址,这些服务器分配私有地址,采用虚拟主机的方式对外提供服务。

2.3 减少WEB服务器压力,提高响应速度

反向代理就是通常所说的web服务器加速,它是一种通过在繁忙的web服务器和外部网络之间增加一个高速的web缓冲服务器来降低实际的web服务器的负载的一种技术。反向代理是针对web服务器提高加速功能,作为代理缓存,它并不是针对浏览器用户,而针对一台或多台特定的web服务器,它可以代理外部网络对内部网络的访问请求。

反向代理服务器会强制将外部网络对要代理的服务器的访问经过它,这样反向代理服务器负责接收客户端的请求,然后到源服务器上获取内容,把内容返回给用户,并把内容保存到本地,以便日后再收到同样的信息请求时,它会把本地缓存里的内容直接发给用户,以减少后端web服务器的压力,提高响应速度。因此Nginx还具有缓存功能。

2.4 其他优点

(1)请求的统一控制,包括设置权限、过滤规则等;

(2)区分动态和静态可缓存内容;

(3)实现负载均衡,内部可以采用多台服务器来组成服务器集群,外部还是可以采用一个地址访问;

(4)解决Ajax跨域问题;

(5)作为真实服务器的缓冲,解决瞬间负载量大的问题;

3. 应用场景

反向代理的应用场景1:

北邮的图书馆资源只能在校内访问,当一个同学暑期放假回家,想要查询图使馆资源的资料(比如知网),因为他不在校园内,所以他没有办法免费访问知网,此时如果有一个反向代理服务器(在校园内网,有权限免费访问知网),他就可以先访问反向代理服务器,然后让反向代理服务器去帮他和知网沟通。

反向代理的应用场景2:

反向代理实现负载均衡

    upstream myapp {
        server 192.168.0.100:8080;
        server 192.168.0.101:8080;
        server example.com:8080;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://myapp;
        }
    }

这样对外发布的还是一个ip地址,用户并不知道后面其实有3个真实的服务器,在处理请求,这样可以大大提高处理性能。

4. 反向代理的配置

基本配置很简单

location / { 
    proxy_pass http://zhengde.xxx.cn;
    proxy_set_header Host zhengde.xxx.cn;
}   

4.1 proxy_pass

proxy_pass 后面跟着一个 URL,用来将请求反向代理到 URL 参数指定的服务器上。例如我们上面例子中的 proxy_pass http://zhengde.xxx.cn;,则将匹配的请求反向代理到 http://zhengde.xxx.cn

4.2 proxy_set_header

语法:

proxy_set_header field value;

默认值:

proxy_set_header Host $proxy_host;
proxy_set_header Connection close;

上下文:

http, server, location

允许重新定义或者添加发往后端服务器的请求头。value可以包含文本、变量或者它们的组合。 当且仅当当前配置级别中没有定义proxy_set_header指令时,会从上面的级别继承配置。 默认情况下,只有两个请求头会被重新定义:

proxy_set_header Host       $proxy_host;
proxy_set_header Connection close;

如果不想改变请求头“Host”的值,可以这样来设置:

proxy_set_header Host       $http_host;

但是,如果客户端请求头中没有携带这个头部,那么传递到后端服务器的请求也不含这个头部。 这种情况下,更好的方式是使用$host变量——它的值在请求包含“Host”请求头时为“Host”字段的值,在请求未携带“Host”请求头时为虚拟主机的主域名:

proxy_set_header Host       $host;

此外,服务器名可以和后端服务器的端口一起传送:

proxy_set_header Host       $host:$proxy_port;

如果某个请求头的值为空,那么这个请求头将不会传送给后端服务器:

proxy_set_header Accept-Encoding "";

默认情况下,反向代理不会转发原始请求中的 Host 头部,真实服务器可能会根据这个host找到相应的站点,不写的话可能找不到,如果需要转发,就需要加上这句:proxy_set_header Host $host;

语法:

proxy_cookie_domain off;
proxy_cookie_domain domain replacement;

默认值:

proxy_cookie_domain off;

上下文:

http, server, location

这个指令出现在版本 1.1.15.

设置“Set-Cookie”响应头中的domain属性的替换文本。 假设后端服务器返回的“Set-Cookie”响应头含有属性“domain=localhost”,那么指令

proxy_cookie_domain localhost example.org;

将这个属性改写为“domain=example.org”。

domain和replacement配置字符串,以及domain属性中起始的点将被忽略。 匹配过程大小写不敏感。domain和replacement配置字符串中可以包含变量:

可以同时定义多条proxy_cookie_domain指令:

proxy_cookie_domain localhost example.org;
proxy_cookie_domain ~\.([a-z]+\.[a-z]+)$ $1;

off参数可以取消当前配置级别的所有proxy_cookie_domain指令:

proxy_cookie_domain off;
proxy_cookie_domain localhost example.org;
proxy_cookie_domain www.example.org example.org;

4.4 proxy_redirect

语法:

proxy_redirect [ default|off|redirect replacement ] 

默认值:

proxy_redirect default 

使用字段:

http, server, location 

背景:即便配置了nginx代理,当服务返回重定向报文时(http code为301或302),会将重定向的目标url地址放入http response报文的header的location字段内(该字段用于重定向)。用户浏览器收到重定向报文时,会解析出该字段并作跳转。此时新的请求报文将直接发送给真实服务地址,而非反代服务器地址。为了能让反代服务器nginx拦截此类请求,必须修改重定向报文的location信息。

假设被代理服务器返回Location字段为: http://localhost:8000/two/some/uri/

这个指令:

proxy_redirect http://localhost:8000/two/ http://frontend/one/;

将Location字段重写为http://frontend/one/some/uri/

如果使用“default”参数,将根据location和proxy_pass参数的设置来决定。

例如下列两个配置等效:

location /one/ {
  proxy_pass       http://upstream:port/two/;
  proxy_redirect   default;
}
 
location /one/ {
  proxy_pass       http://upstream:port/two/;
  proxy_redirect   http://upstream:port/two/   /one/;
}

在指令中可以使用一些变量:

proxy_redirect   http://localhost:8000/    http://$host:$server_port/;

参数off将在这个字段中禁止所有的proxy_redirect指令:

  proxy_redirect   off;
  proxy_redirect   default;
  proxy_redirect   http://localhost:8000/    /;
  proxy_redirect   http://www.example.com/   /;

4.5 sub_filter

ngx_http_sub_module模块是一个过滤器,它修改网站响应内容中的字符串,比如你想把响应内容中的‘xxxx’全部替换成‘yyy’,这个模块已经内置在nginx中,但是默认未安装,需要安装需要加上配置参数:--with-http_sub_module

1、语法:

sub_filter string replacement;

默认值:

配置段:

http, server, location

设置需要使用说明字符串替换说明字符串.string是要被替换的字符串,replacement是新的字符串,它里面可以带变量。

2、语法:

sub_filter_once on | off;

默认值:

sub_filter_once on;

配置段:

http, server, location

字符串替换一次还是多次替换,默认替换一次,例如你要替换响应内容中的ttlsa为运维生存时间,如果有多个ttlsa出现,那么只会替换第一个,如果off,那么所有的ttlsa都会 被替换

3、语法:

sub_filter_types mime-type ...;

默认值:

sub_filter_types text/html;

配置段:

http, server, location

指定需要被替换的MIME类型,默认为“text/html”,如果制定为*,那么所有的

4、示例:

location / {
    proxy_pass http://zhengde.xxx.cn;
    proxy_set_header Host zhengde.xxx.cn;
    sub_filter  xxx.com  yyy.com;
    sub_filter_once on;
    sub_filter_types text/html;
}

解释:

  • sub_filter 前面字符串(xxx.com)是需要替换的内容,后面字符串(yyy.com)是替换成的内容。
  • sub_filter_once 意思是只查找并替换一次。on是开启此功能,off是关闭,默认值是on。
  • sub_filter_types 一行意思是选定查找替换文件类型为文本型。也可以不加此行,因为默认只查找文本型文件。

5. 使用nginx反向代理后如何在web应用中获取用户ip

在实际应用中,我们可能需要获取用户的ip地址,比如做异地登陆的判断,或者统计ip访问次数等,通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了nginx作为反向代理后,使用request.getRemoteAddr()获取到的就一直是nginx服务器的ip的地址。

经过反向代理后,由于在客户端和web服务器之间增加了中间层,通过$remote_addr变量拿到的将是反向代理服务器的ip地址,在web端使用request.getRemoteAddr()(本质上就是获取$remote_addr),取得的是nginx的地址,当然是没法获得用户的真实ip的。

但是,nginx是可以获得用户的真实ip的,也就是说nginx使用$remote_addr变量时获得的是用户的真实ip,如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下:

proxy_set_header X-real-ip $remote_addr;

其中这个X-real-ip是一个自定义的变量名,名字可以随意取,这样做完之后,用户的真实ip就被放在X-real-ip这个变量里了,然后,在web端可以这样获取:

request.getAttribute("X-real-ip")

简单描述如下:

web端直接获取$remote_addr,实际上获取的是反代服务器地址,无法得到用户真实地址

但是,nginx端存在关系

$remote_addr => 真实用户地址

在nginx端,新定义一个变量,将这个值存起来,发给web端

$x-real-ip = $remote_addr

在web端获取$x-real-ip,实际上就可以获取到真实用户地址了


既然提到了真实的用户地址,这里再探讨下X-Forwarded-For

X-Forwarded-For 是一个 HTTP 扩展头部。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP。如今它已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中。

X-Forwarded-For 请求头格式非常简单,就这样:

X-Forwarded-For: client, proxy1, proxy2

可以看到,XFF 的内容由「英文逗号 + 空格」隔开的多个部分组成,最开始的是离服务端最远的设备 IP,然后是每一级代理设备的 IP。

当我们
意思是增加一个$proxy_add_x_forwarded_for到X-Forwarded-For里去,注意是增加,而不是覆盖,实际过程是如下的,

假如一个 HTTP 请求到达真实服务器(real_server)之前,经过了三个代理 Proxy1、Proxy2,IP 分别为 IP1、IP2,用户真实 IP 为 IP0,在每台代理服务器nginx增加了如下配置:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

以上配置中,$proxy_add_x_forwarded_for变量包含客户端请求头中的"X-Forwarded-For",与$remote_addr两部分,他们之间用逗号分开。以下是$proxy_add_x_forwarded_for变量在不同服务器中的值变化

那么第一台代理服务器proxy1的情形:X-Forwarded-For(空) + $remote_addr(IP0)

那么第二台代理服务器proxy2的情形:X-Forwarded-For(IP0) + $remote_addr(IP1)

那么真实服务器real_server的情形:X-Forwarded-For(IP0,IP1) + $remote_addr(IP2)

此时服务端获取的X-Forwarded-For的值为 IP0,IP1,IP2,其中并没有包含真实服务器的地址,这个地址可以通过Remote Address 字段获得。

参考资料:

https://imququ.com/post/x-forwarded-for-header-in-http.html

http://tengine.taobao.org/nginx_docs/cn/docs/http/ngx_http_proxy_module.html#proxy_set_header

http://gong1208.iteye.com/blog/1559835

nginx 反向代理

标签:http   防火墙   强制   使用   类型   sub   ecc   客户端   时代   

原文地址:https://www.cnblogs.com/redirect/p/10066752.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!