nginx 反向代理
Posted redirect
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nginx 反向代理相关的知识,希望对你有一定的参考价值。
目录
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;
4.3 proxy_cookie_domain
语法:
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 反向代理的主要内容,如果未能解决你的问题,请参考以下文章