简介我们已经介绍了haproxy提出的代理协议。通过代理协议,服务端可以获得客户端的真实IP地址和端口,从而可以进行一些非常有意义的操作。为什么获取客户端的真实IP地址有意义?考虑一个隐藏在代理后面的数据库。如果有多个客户端通过代理连接数据库,其实因为都是通过代理连接的,所以对数据库的所有操作都是代理服务器的IP地址。数据库的性能监控和优化是不利的,因为我们不知道真正异常的服务器IP地址。在这种情况下,就需要通过代理协议让数据库反映真实客户端的IP地址,方便数据库监控和问题定位。其实数据库只是一个具体的例子,在其他很多情况下我们可能还需要知道客户端的真实IP。以最流行的http服务器和代理服务器nginx为例,我们来看看如何在nginx中配置代理协议。代理协议应用在nginx中。我们知道nginx是一个web服务器和代理服务器。一般工作在代理服务器或负载均衡软件(Haproxy、AmazonElasticLoadBalancer(ELB))的后面。客户端先请求代理服务器或LSB负载均衡软件,然后再去nginx进行真正的web访问。由于多层软件,可能会隐藏一些客户端信息如ip地址,端口号等,不利于我们的问题分析和数据统计,因为对于nginx来说,我们希望获取真实的客户端IP地址,从而获取真正的请求环境,这种情况下,我们需要使用PROXY协议,如果前面提到的proxy或者LSB已经实现了PROXY协议,协议方面,无论是HTTP、SSL、HTTP/2、SPDY、WebSocket还是TCP协议,nginx可以获取到客户端的原始IP地址,从而根据原始IP地址进行一些特殊的操作,比如屏蔽恶意IP访问,根据显示不同语言或者不同IP的页面是非常有效的,或更简单的日志记录和统计信息。当然,如果要支持PROXY协议,对nginx版本也是有要求的。具体版本要求如下:支持PROXY协议v2,需要NGINXPlusR16或NGINXOpenSource1.13.11。要支持HTTP的ROXY协议,需要NGINXPlusR3或NGINXOpenSource1.5.12。要支持TCP客户端PROXY协议,需要NGINXPlusR7或NGINXOpenSource1.9.3。要支持TCP的PROXY协议,需要NGINXPlusR11或NGINXOpenSource1.11.4。在nginx中,可以通过以下变量获取对应的客户端信息,具体如下:$proxy_protocol_addr和$proxy_protocol_port分别代表原始客户端的IP地址和端口号。$remote_addr和$remote_port表示负载均衡器的IP地址和端口。如果你使用RealIP扩展模块,那么这个模块会重写$remote_addr和$remote_port这两个值,用原来的客户端IP地址和端口号代替。然后使用$realip_remote_addr和$realip_remote_port来指示负载均衡器的IP地址和端口。在RealIP扩展模块中,$proxy_protocol_addr和$proxy_protocol_port的含义不变,仍然是原来客户端的IP地址和端口号。在nginx中配置和使用代理协议上面我们提到了代理协议在nginx中的基本应用。下面说说如何在nginx中进行配置。在nginx中启用代理协议如果你的nginx已经支持代理协议,启用代理协议很简单,只需要在server中添加proxy_protocol监听即可,如下图:http{#...server{listen80proxy_protocol;听443sslproxy_protocol;#...}}流{#...服务器{听112233proxy_protocol;#...}}你可能熟悉http块,这意味着nginx支持http/HTTPS支持。流模块可能大家比较陌生。这是nginx提供的对tcp/udp协议的支持。通过以上配置,nginx可以同时支持tcp/udp协议和http/https协议中的代理协议。使用Real?IP模块Real?IP模块是nginx自带的模块。可以使用如下命令查看nginx是否安装了real-ip模块:nginx-V2>&1|grep--'http_realip_module'nginx-V2>&1|grep--'stream_realip_module'如果你现在使用的版本没有真实ip,不用担心,这时候你可能需要从源码编译。在编译过程中,我们需要执行一个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_from192.168.1.0/24;#...}然后我们需要把proxy或者SLB的IP地址换成真实的client的地址,那么就可以这样使用:http{server{#...real_ip_headerproxy_protocol;}}请求转发无论是http还是streamblock,都可能会遇到请求被转发到后续upstream的情况。对于upstream,他们希望接收真实的客户端IP地址,而不是代理或者slb地址,所以可以通过如下设置来解决:http{proxy_set_headerX-Real-IP$proxy_protocol_addr;proxy_set_headerX-Forwarded-For$proxy_protocol_addr;}stream{server{listen12345;proxy_passexample.com:12345;proxy_protocol开启;}}http和流设置方法不同。日志记录是一个非常重要的功能。它对于定位问题和进行数据的统计分析非常有用。当然,我们需要的是真实的客户端IP地址。我们可以通过变量$proxy_protocol_addr在http和streamblock中记录相应的日志,如下:$http_referer""$http_user_agent"';}stream{#...log_formatbasic'$proxy_protocol_addr-$remote_user[$time_local]''$protocol$status$bytes_sent$bytes_received''$session_time';}Summarypassed同上设置中,nginx已经可以使用proxoy协议了,这样可以方便我们后续的分析工作。更多内容请参考http://www.flydean.com/02-nginx-proxy-protocol/最通俗的解读,最深刻的干货,最简洁的教程,多多不谢我的公众号:《程序那些事》,懂技术,更懂你!
