简介
咱们曾经介绍了haproxy提出的proxy protocol协定,通过proxy protocol协定,服务器端能够取得客户端的实在IP地址和端口,从而能够进行一些十分有意义的操作。
为什么取得客户端的实在IP地址会十分有意义呢?
思考一个藏在proxy背地的数据库,如果有多个客户端通过proxy进行数据库的连贯,事实上因为都是通过代理进行连贯,所以数据库中的所有的操作都是proxy服务器的IP地址,这在对数据库的性能监控和优化是不利的,因为咱们不晓得实在异样的服务器IP地址。
这种状况下就须要用到proxy protocol协定,让数据库能够反映出实在客户端的IP地址,从而便于数据库的监控和问题定位。
事实上,数据库只是一个特定的例子,咱们在很多其余的状况下也可能须要晓得客户端实在IP的状况。
以当初最风行的http服务器和代理服务器nginx为例,咱们来看一下如何在nginx中配置proxy protocol。
proxy protocol在nginx中利用
咱们晓得nginx是一个web服务器和代理服务器,它个别工作在proxy server或者负载平衡软件(Haproxy,Amazon Elastic Load Balancer (ELB)的前面。
客户端首先申请proxy server或者LSB负载平衡软件,而后再到nginx进行实在的web拜访。
因为通过了多层软件,所以客户端的一些信息比方ip地址,端口号等可能就会被暗藏,这对于咱们问题剖析,数据统计都是不利的。因为对于nginx来说,咱们心愿可能取得实在的客户端IP地址,这样能力获取实在的申请环境。
这种状况下就须要用到PROXY protocol了。
如果后面所说的proxy或者LSB都实现了PROXY protocol协定的话,不论是HTTP, SSL, HTTP/2, SPDY, WebSocket 还是 TCP协定,nginx都能够拿到客户端的原始IP地址,从而依据原始IP地址进行一些非凡的操作,比方屏蔽歹意IP的拜访,依据IP不同展现不同的语言或者页面,或者更加简略的日志记录和统计等,都十分无效。
当然,如果想要反对PROXY protocol,对nginx的版本也是有要求的,具体版本需要如下:
- 想要反对PROXY protocol v2,须要NGINX Plus R16或者NGINX Open Source 1.13.11。
- 想要反对ROXY protocol for HTTP,须要NGINX Plus R3或者NGINX Open Source 1.5.12。
- 想要反对TCP client‑side PROXY protocol,须要NGINX Plus R7或者 NGINX Open Source 1.9.3。
- 想要反对PROXY protocol for TCP,须要NGINX Plus R11 或者 NGINX Open Source 1.11.4。
在nginx中能够通过上面的变量来取得对应的客户端信息,具体而言如下所示:
$proxy_protocol_addr
和$proxy_protocol_port
别离示意的是原始客户端的IP地址和端口号。
$remote_addr
和 $remote_port
示意的是load balancer的的IP地址和端口。
如果你应用了RealIP扩大模块,那么这个模块会重写$remote_addr
和 $remote_port
这两个值,将其替换成原始客户端的IP地址和端口号。
而后应用$realip_remote_addr
和 $realip_remote_port
来示意load balancer的的IP地址和端口。
在RealIP扩大模块中,$proxy_protocol_addr
和$proxy_protocol_port
示意的含意不变,还是原始客户端的IP地址和端口号。
在nginx中配置应用proxy protocol
下面咱们提到了nginx中proxy protocol的根本利用,上面来讲一下如何在nginx中进行具体的配置。
在nginx中启用proxy protocol
如果你的nginx曾经是反对proxy protocol的版本,那么启用proxy protocol非常简单,只须要在server中的listen中增加proxy_protocol即可,如下所示:
http { #... server { listen 80 proxy_protocol; listen 443 ssl proxy_protocol; #... }} stream { #... server { listen 112233 proxy_protocol; #... }}
可能大家比拟相熟的是http block,这示意的是nginx对http/https的反对。stream模块可能大家比拟生疏,这是nginx提供的对tcp/udp协定的反对。
通过下面的配置,nginx能够实现在tcp/udp协定和http/https协定同时反对proxy protocol。
应用Real‑IP modules
Real‑IP modules是nginx自带的一个模块,能够通过上面的命令来查看nginx是否有装置real-ip模块:
nginx -V 2>&1 | grep -- 'http_realip_module'nginx -V 2>&1 | grep -- 'stream_realip_module'
如果你以后应用的版本没有real ip,也不要急,这时候你可能须要从源代码进行编译。
在编译的过程中,咱们须要执行一个configure命令,在这个configure命令中能够指定要开启的性能,比方stream或者http_ssl_module:
$ ./configure--sbin-path=/usr/local/nginx/nginx--conf-path=/usr/local/nginx/nginx.conf--pid-path=/usr/local/nginx/nginx.pid--with-pcre=../pcre-8.44--with-zlib=../zlib-1.2.11--with-http_ssl_module--with-stream--with-mail
如果要开启real-ip性能,则能够增加:
--with-http_realip_module
如果nginx是运行在SLB或者proxy之后的,那么能够通过set_real_ip_from命令来指定代理或者负载平衡服务器的IP范畴,如下所示:
server { #... set_real_ip_from 192.168.1.0/24; #...}
而后咱们须要将proxy或者SLB的IP地址替换成为实在客户端的地址,那么能够这样应用:
http { server { #... real_ip_header proxy_protocol; }}
申请转发
不论是http还是stream block,都可能遇到申请向后续的upstream进行转发的状况,对于upstream来说,他们心愿收到的是实在客户端IP地址,而不是proxy或者slb的地址,那么能够通过上面的设置来解决:
http { proxy_set_header X-Real-IP $proxy_protocol_addr; proxy_set_header X-Forwarded-For $proxy_protocol_addr;}
stream { server { listen 12345; proxy_pass example.com:12345; proxy_protocol on; }}
http和stream的设置形式是不同的。
日志记录
日志是一个十分重要的性能,对于定位问题,执行数据统计分析都十分有用,当然咱们须要的是实在的客户端IP地址。
咱们能够通过应用变量$proxy_protocol_addr在http和stream block中记录对应的日志,如下所示:
http { #... log_format combined '$proxy_protocol_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';}
stream { #... log_format basic '$proxy_protocol_addr - $remote_user [$time_local] ' '$protocol $status $bytes_sent $bytes_received ' '$session_time';}
总结
通过下面的设置,nginx曾经能够应用proxoy protocol了,这会让咱们的后续剖析工作变得更加轻松。
更多内容请参考 http://www.flydean.com/02-nginx-proxy-protocol/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!