乐趣区

关于nginx:在nginx中使用proxy-protocol协议

简介

咱们曾经介绍了 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/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不

欢送关注我的公众号:「程序那些事」, 懂技术,更懂你!

退出移动版