6.接受proxy协议
本文介绍如何将 NGINX 配置为接受 PROXY 协议,将负载均衡器或代理的 IP 地址重写为 PROXY 协议标头中收到的 IP 地址,配置客户端 IP 地址的简单日志记录,以及启用 NGINX 和 TCP upstream服务器之间的 PROXY 协议。
介绍
PROXY 协议(PROXY protocol)使 NGINX 能够接收通过代理服务器和负载均衡器(如 HAproxy 和 Amazon Elastic Load Balancer (ELB))传递的客户端连接信息。
使用代理协议,NGINX可以从HTTP,SSL,HTTP / 2,SPDY,WebSocket和TCP中学习原始IP地址。了解客户端的原始 IP 地址对于为网站设置特定语言、保留 IP 地址拒绝列表或仅用于日志记录和统计目的可能很有用。
通过 PROXY 协议传递的信息是客户端 IP 地址、代理服务器 IP 地址和两个端 口号。
使用此数据,NGINX可以通过多种方式获取客户端的原始IP地址:
- 使用
$proxy_protocol_addr和$proxy_protocol_port变量捕获原始客户端 IP 地址和端口。$remote_addr和$remote_port变量捕获负载均衡器的 IP 地址和端口。 - 使用 RealIP 模块重写
$remote_addr和$remote_port变量中的值,将负载均衡器的 IP 地址和端口替换为原始客户端 IP 地址和端口。$realip_remote_addr和$realip_remote_port变量保留负载均衡器的地址和端口,$proxy_protocol_addr和$proxy_protocol_port变量仍保留原始客户端 IP 地址和端口。
4.配置 NGINX 以接受代理协议
要将 NGINX 配置为接受 PROXY 协议标头,请将 proxy_protocol参数添加到 http 或 upstream {} 块中的 server块中的 listen指令中。
http {
#...
server {
listen 80 proxy_protocol;
listen 443 ssl proxy_protocol;
#...
}
}
stream {
#...
server {
listen 12345 proxy_protocol;
#...
}
}
4.将负载均衡器的 IP 地址更改为客户端 IP 地址
您可以将负载均衡器或 TCP 代理的地址替换为从 PROXY 协议接收的客户端 IP 地址。 这可以通过HTTP和 upstreamRealIP模块来完成。使用这些模块,$remote_addr 和 $remote_port 变量保留客户端的实际 IP 地址和端口,而 $realip_remote_addr和 $realip_remote_port 变量保留负载均衡器的 IP 地址和端口。
要将 IP 地址从负载均衡器的 IP 地址更改为客户端的 IP 地址,请执行以下操作:
-
确保已将NGINX配置为接受PROXY 协议标头。请参阅配置 NGINX 以接受代理协议。
-
确保您的NGINX安装包含HTTP和Stream Real-IP模块
nginx -V 2>&1 | grep -- 'http_realip_module'
nginx -V 2>&1 | grep -- 'stream_realip_module'如果没有,请使用这些模块重新编译NGINX。
-
在 HTTP或stream的
set_real_ip_from指令中,指定 TCP 代理或负载均衡器的 IP 地址或 CIDR 地址范围:server {
#...
set_real_ip_from 192.168.1.0/24;
#...
} -
在
http {}上下文中,通过指定real_ip_header指令的proxy_protocol参数,将负载均衡器的 IP 地址更改为从 PROXY 协议标头接收的客户端的 IP 地址:http {
server {
#...
real_ip_header proxy_protocol;
}
}
记录原始 IP 地址
知道客户端的原始 IP 地址后,可以配置正确的日志记录:
对于 HTTP,将 NGINX 配置为使用 $proxy_protocol_addr 变量和 proxy_set_header 指令将客户端 IP 地址传递给upstream服务器:
http {
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
}
将 $proxy_protocol_addr 变量添加到 log_format指令(HTTP 或 Stream):
#在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';
}
用于与上游的 TCP 连接的代理协议
对于TCP流,可以为NGINX和upstream服务器之间的连接启用PROXY协议。要启用 PROXY 协议,请在以下级别 stream {}的 server块中包含 proxy_protocol指令:
stream {
server {
listen 12345;
proxy_pass example.com:12345;
proxy_protocol on;
}
}
示例
http {
log_format combined '$proxy_protocol_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
#...
server {
server_name localhost;
listen 80 proxy_protocol;
listen 443 ssl proxy_protocol;
ssl_certificate /etc/nginx/ssl/public.example.com.pem;
ssl_certificate_key /etc/nginx/ssl/public.example.com.key;
location /app/ {
proxy_pass http://backend1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $proxy_protocol_addr;
proxy_set_header X-Forwarded-For $proxy_protocol_addr;
}
}
}
stream {
log_format basic '$proxy_protocol_addr - $remote_user [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time';
#...
server {
listen 12345 ssl proxy_protocol;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/cert.key;
proxy_pass backend.example.com:12345;
proxy_protocol on;
}
}
该示例假设 NGINX 前面有一个负载均衡器来处理所有传入的 HTTPS 流量,例如 Amazon ELB。NGINX 接受端口 443 (listen 443 ssl) 上的 HTTPS 流量,端口 12345 上的 TCP 流量,并接受通过 PROXY 协议从负载均衡器传递的客户端 IP 地址(http {}和 stream {}块中 listen指令的 proxy_protocol参数)。
NGINX终止HTTPS流量(ssl_certificate和 ssl_certificate_key指令)并将解密的数据代理到后端服务器:
- 对于 HTTP:
proxy_pass http://backend1; - 对于 TCP:
proxy_pass backend.example.com:12345
它包括客户端 IP 地址和端口以及 proxy_set_header 指令。
log_format 指令中指定的 $proxy_protocol_addr 变量还将客户端的 IP 地址传递给 HTTP 和 TCP 的日志。
此外,TCP 服务器(stream {}块)将自己的 PROXY 协议数据发送到其后端服务器(proxy_protocol on指令)。