- Home
- F5 NGINX Plus
- Admin Guide
- Load Balancer Accepting the PROXY Protocol
Accepting the PROXY Protocol
This article explains how to configure NGINX and F5 NGINX Plus to accept the PROXY protocol, rewrite the IP address of a load balancer or proxy to the one received in the PROXY protocol header, configure simple logging of a client’s IP address, and enable the PROXY protocol between NGINX and a TCP upstream server.
ThePROXY protocol enables NGINX and NGINX Plus to receive client connection information passed through proxy servers and load balancers such as HAproxy and Amazon Elastic Load Balancer (ELB).
With the PROXY protocol, NGINX can learn the originating IP address from HTTP, SSL, HTTP/2, SPDY, WebSocket, and TCP. Knowing the originating IP address of a client may be useful for setting a particular language for a website, keeping a denylist of IP addresses, or simply for logging and statistics purposes.
The information passed via the PROXY protocol is the client IP address, the proxy server IP address, and both port numbers.
Using this data, NGINX can get the originating IP address of the client in several ways:
With the
$proxy_protocol_addr
and$proxy_protocol_port
variables which capture the original client IP address and port. The$remote_addr
and$remote_port
variables capture the IP address and port of the load balancer.With theRealIP module which rewrites the values in the
$remote_addr
and$remote_port
variables, replacing the IP address and port of the load balancer with the original client IP address and port. The$realip_remote_addr
and$realip_remote_port
variables retain the address and port of the load balancer, and the$proxy_protocol_addr
and$proxy_protocol_port
variables retain the original client IP address and port anyway.
To accept the PROXY protocol v2, NGINX PlusR16 and later or NGINX Open Source1.13.11 and later
To accept the PROXY protocol for HTTP, NGINX PlusR3 and later or NGINX Open Source1.5.12 and later
For TCP client‑side PROXY protocol support, NGINX PlusR7 and later or NGINX Open Source1.9.3 and later
To accept the PROXY protocol for TCP, NGINX PlusR11 and later or NGINX Open Source1.11.4 and later
The Real‑IP modules forHTTP andStream TCP are not included in NGINX Open Source by default; seeInstalling NGINX Open Source for details. No extra steps are required for NGINX Plus.
To configure NGINX to accept PROXY protocol headers, add theproxy_protocol
parameter to thelisten
directive in aserver
block in thehttp {}
orstream {}
block.
http{#...server{listen80proxy_protocol;listen443sslproxy_protocol;#...}}stream{#...server{listen12345proxy_protocol;#...}}
http{#...server{listen80proxy_protocol;listen443sslproxy_protocol;#...}}stream{#...server{listen12345proxy_protocol;#...}}
Now you can use the$proxy_protocol_addr
and$proxy_protocol_port
variables for the client IP address and port and additionally configure theHTTP andstream
RealIP modules to replace the IP address of the load balancer in the$remote_addr
and$remote_port
variables with the IP address and port of the client.
You can replace the address of the load balancer or TCP proxy with the client IP address received from the PROXY protocol. This can be done with theHTTP andstream
RealIP modules. With these modules, the$remote_addr
and$remote_port
variables retain the real IP address and port of the client, while the$realip_remote_addr
and$realip_remote_port
variables retain the IP address and port of the load balancer.
To change the IP address from the load balancer’s IP address to the client’s IP address:
Make sure you’ve configured NGINX to accept the PROXY protocol headers. SeeConfiguring NGINX to Accept the PROXY Protocol.
Make sure that your NGINX installation includes theHTTP andStream Real‑IP modules:
shellnginx -V 2>&1| grep --'http_realip_module'nginx -V 2>&1| grep --'stream_realip_module'
nginx -V 2>&1| grep --'http_realip_module'nginx -V 2>&1| grep --'stream_realip_module'
If not, recompile NGINX with these modules. SeeInstalling NGINX Open Source for details. No extra steps are required for NGINX Plus.
In the
set_real_ip_from
directive forHTTP,Stream, or both, specify the IP address or the CIDR range of addresses of the TCP proxy or load balancer:nginxserver{#...set_real_ip_from192.168.1.0/24;#...}
server{#...set_real_ip_from192.168.1.0/24;#...}
In the
http {}
context, change the IP address of the load balancer to the IP address of the client received from the PROXY protocol header, by specifying theproxy_protocol
parameter to thereal_ip_header
directive:nginxhttp{server{#...real_ip_headerproxy_protocol;}}
http{server{#...real_ip_headerproxy_protocol;}}
When you know the original IP address of the client, you can configure the correct logging:
For HTTP, configure NGINX to pass the client IP address to upstream servers using the
$proxy_protocol_addr
variable with theproxy_set_header
directive:nginxhttp{proxy_set_headerX-Real-IP$proxy_protocol_addr;proxy_set_headerX-Forwarded-For$proxy_protocol_addr;}
http{proxy_set_headerX-Real-IP$proxy_protocol_addr;proxy_set_headerX-Forwarded-For$proxy_protocol_addr;}
Add the
$proxy_protocol_addr
variable to thelog_format
directive (HTTP orStream):In the
http
block:nginxhttp{#...log_formatcombined'$proxy_protocol_addr-$remote_user[$time_local]''"$request"$status$body_bytes_sent''"$http_referer""$http_user_agent"';}
http{#...log_formatcombined'$proxy_protocol_addr-$remote_user[$time_local]''"$request"$status$body_bytes_sent''"$http_referer""$http_user_agent"';}
In the
stream
block:nginxstream{#...log_formatbasic'$proxy_protocol_addr-$remote_user[$time_local]''$protocol$status$bytes_sent$bytes_received''$session_time';}
stream{#...log_formatbasic'$proxy_protocol_addr-$remote_user[$time_local]''$protocol$status$bytes_sent$bytes_received''$session_time';}
For a TCP stream, the PROXY protocol can be enabled for connections between NGINX and an upstream server. To enable the PROXY protocol, include theproxy_protocol
directive in aserver
block at thestream {}
level:
stream{server{listen12345;proxy_passexample.com:12345;proxy_protocolon;}}
stream{server{listen12345;proxy_passexample.com:12345;proxy_protocolon;}}
http{log_formatcombined'$proxy_protocol_addr-$remote_user[$time_local]''"$request"$status$body_bytes_sent''"$http_referer""$http_user_agent"';#...server{server_namelocalhost;listen80proxy_protocol;listen443sslproxy_protocol;ssl_certificate/etc/nginx/ssl/public.example.com.pem;ssl_certificate_key/etc/nginx/ssl/public.example.com.key;location/app/{proxy_passhttp://backend1;proxy_set_headerHost$host;proxy_set_headerX-Real-IP$proxy_protocol_addr;proxy_set_headerX-Forwarded-For$proxy_protocol_addr;}}}stream{log_formatbasic'$proxy_protocol_addr-$remote_user[$time_local]''$protocol$status$bytes_sent$bytes_received''$session_time';#...server{listen12345sslproxy_protocol;ssl_certificate/etc/nginx/ssl/cert.pem;ssl_certificate_key/etc/nginx/ssl/cert.key;proxy_passbackend.example.com:12345;proxy_protocolon;}}
http{log_formatcombined'$proxy_protocol_addr-$remote_user[$time_local]''"$request"$status$body_bytes_sent''"$http_referer""$http_user_agent"';#...server{server_namelocalhost;listen80proxy_protocol;listen443sslproxy_protocol;ssl_certificate/etc/nginx/ssl/public.example.com.pem;ssl_certificate_key/etc/nginx/ssl/public.example.com.key;location/app/{proxy_passhttp://backend1;proxy_set_headerHost$host;proxy_set_headerX-Real-IP$proxy_protocol_addr;proxy_set_headerX-Forwarded-For$proxy_protocol_addr;}}}stream{log_formatbasic'$proxy_protocol_addr-$remote_user[$time_local]''$protocol$status$bytes_sent$bytes_received''$session_time';#...server{listen12345sslproxy_protocol;ssl_certificate/etc/nginx/ssl/cert.pem;ssl_certificate_key/etc/nginx/ssl/cert.key;proxy_passbackend.example.com:12345;proxy_protocolon;}}
The example assumes that there is a load balancer in front of NGINX to handle all incoming HTTPS traffic, for example Amazon ELB. NGINX accepts HTTPS traffic on port 443 (listen 443 ssl;
), TCP traffic on port 12345, and accepts the client’s IP address passed from the load balancer via the PROXY protocol as well (theproxy_protocol
parameter to thelisten
directive in both thehttp {}
andstream {}
blocks.
NGINX terminates HTTPS traffic (thessl_certificate
andssl_certificate_key
directives) and proxies the decrypted data to a backend server:
- For HTTP:
proxy_pass http://backend1;
- For TCP:
proxy_pass backend.example.com:12345
It includes the client IP address and port with theproxy_set_header
directives.
The$proxy_protocol_addr
variable specified in thelog_format
directive also passes the client’s IP address to the log for both HTTP and TCP.
Additionally, a TCP server (thestream {}
block) sends its own PROXY protocol data to its backend servers (theproxy_protocol on
directive).