## 通过 Proxy Protocol 获取客户端真实 IP Proxy Protocol是一种Internet协议,通过为TCP报文添加Proxy Protocol报头来获取客户端源IP。 Proxy Protocol的接收端必须在接收到完整有效的Proxy Protocol头部后才能开始处理连接数据,因此对于服务器中的同一个监听端口,不能同时接收携带Proxy Protocol和未携带Proxy Protocol的连接请求。如果接收到的第一个数据包不符合Proxy Protocol格式,那么服务器会直接终止连接。 # Proxy Protocol 是通过为 TCP 添加一个头部信息,来方便的传递客户端信息(协议栈、源 IP、目的 IP、源端口、目的端口等),在网络情况复杂又需要获取用户真实 IP 时非常有用。其本质是在三次握手结束后由代理在连接中插入一个携带了原始连接四元组信息的数据包。 # Proxy Protocol 方式获取客户端 IP 需要在控制台配置使用(当前仅支持协议为 TCP 的监听器使用),加速服务在和源站建立连接后,会在传输的第一个 payload 的报文前插入Proxy Protocol 协议文本。 # http://www.haproxy.org/download/1.8/doc/proxy-protocol.txt 当前 Nginx 和 HaProxy 都已经支持 Proxy Protocol 协议,如下,Nginx 配置支持 Proxy Protocol 协议只需要将参数 proxy\_protocol 添加在 server 块中的 listen 指令后 ~~~ http { ... server { listen 80 proxy_protocol; listen 443 ssl proxy_protocol; "tcp_xff":"$proxy_protocol_addr" ... } } ~~~ 对 TCP stream 流的配置: ~~~ stream { ... server { listen 12345 proxy_protocol; ... } } ~~~ 现在可以使用表示客户端 IP 地址和端口的`$proxy_protocol_addr`和`$proxy_protocol_port`变量。TCP协议端口 后端服务器需要在 TCP 连接建立后,读取 Proxy Protocol 的文本行并进行字符串解析来获取客户端 IP。 # # ## http 或 stream 对于 http 或 stream,可以使用`log_format`指令和[`$proxy_protocol_addr`](https://nginx.org/en/docs/http/ngx_http_core_module.html#var_proxy_protocol_addr)变量: ###对于 http {} 块: ~~~ http { ... log_format combined '$proxy_protocol_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; } ~~~ ### 对于 stream {} 块: ~~~ stream { ... log_format basic '$proxy_protocol_addr - $remote_user [$time_local] ' '$protocol $status $bytes_sent $bytes_received ' '$session_time'; } ~~~