The Proxy Protocol is a network protocol that allows a proxy server, like a load balancer, to pass the original client’s IP address and other connection information to a backend server. This is crucial because, by default, when traffic goes through a load balancer, the backend server only sees the IP address of the load balancer itself, losing the client’s original IP.
Let’s see this in action.
Imagine a simple web server running on port 80. Without Proxy Protocol, if we send a request from 192.168.1.100 to a load balancer at 10.0.0.1, and the load balancer forwards it to our web server at 10.0.0.2, the web server’s access logs will show 10.0.0.1 as the source IP, not 192.168.1.100.
Now, let’s configure a load balancer and a backend server to use Proxy Protocol.
Load Balancer Configuration (AWS ELB Example - HTTP/HTTPS Listener):
For AWS Elastic Load Balancers (ELB/ALB/NLB), enabling Proxy Protocol is often a listener-level setting.
- Application Load Balancer (ALB): When creating or modifying an ALB listener, you’ll find an option under "Attributes" or "Advanced settings" for the listener. Enable "Proxy protocol" for the listener. This tells the ALB to prepend Proxy Protocol headers to traffic it sends to targets.
- Network Load Balancer (NLB): For NLB, Proxy Protocol is enabled directly on the listener. When configuring the listener, select "Proxy protocol" as the protocol version for the traffic forwarded to the target group.
Backend Server Configuration (Nginx Example):
Your backend application needs to be configured to understand and parse the Proxy Protocol header. For Nginx, this is typically done in the nginx.conf or a site-specific configuration file.
http {
# ... other http configurations ...
server {
listen 80 accept_proxy_protocol; # This is the key directive
server_name your_domain.com;
location / {
# ... your location configurations ...
proxy_pass http://backend_app; # If Nginx is a reverse proxy itself
# Or simply serve static files or run your application
root /var/www/html;
index index.html index.htm;
}
}
# ... other server blocks ...
}
The accept_proxy_protocol directive tells Nginx to expect and parse the Proxy Protocol header on incoming connections to port 80. When it receives this header, it will use the original client IP address provided in the header for logging and access control, rather than the IP of the load balancer.
Backend Server Configuration (HAProxy Example):
If you’re using HAProxy as your load balancer or as a reverse proxy in front of your application, you configure Proxy Protocol on the frontend that receives traffic from the upstream load balancer, and then tell HAProxy to send it on the backend to your application.
frontend http_in
bind *:80
mode http
option tcplog # To log the original IP
acl has_proxy_protocol dst_port 80 # Ensure we are on the correct port
http-request accept-proxy if has_proxy_protocol # Accept Proxy Protocol if present
default_backend web_servers
backend web_servers
mode http
balance roundrobin
option httpchk GET /health # Example health check
# This is where you tell HAProxy to *send* Proxy Protocol to the backend
# If your backend is also HAProxy, use 'send-proxy'
# If your backend is Nginx/Apache etc, use 'send-proxy-v2' (preferred) or 'send-proxy'
server app1 10.0.0.2:80 check send-proxy-v2
server app2 10.0.0.3:80 check send-proxy-v2
In this HAProxy example:
option tcploghelps ensure that the original client IP is logged.http-request accept-proxytells the frontend to process Proxy Protocol headers if they are present.send-proxy-v2on the backend server line tells HAProxy to prepend the Proxy Protocol v2 header (which is more robust and supports IPv6) to the traffic it sends toapp1andapp2.
The Mental Model:
Think of the Proxy Protocol as a special envelope for your data. When traffic hits the load balancer, instead of just passing the data, the load balancer opens the envelope, notes down the original sender’s address (the client’s IP), puts that address on the data itself (as a header), and then re-seals it with the load balancer’s own return address. When the data arrives at your backend server, your server is configured to look for that special note about the original sender’s address, reads it, and uses it. Without this configuration, your server just sees the load balancer’s return address.
The two main versions of Proxy Protocol are v1 (text-based) and v2 (binary-based). v2 is generally preferred due to its efficiency, robustness, and support for more metadata. Most modern load balancers and applications support v2.
One thing that often trips people up is the distinction between the load balancer accepting Proxy Protocol from an upstream source and sending Proxy Protocol to a downstream target. In a typical setup where a cloud load balancer sends to your backend servers, the cloud load balancer is configured to send Proxy Protocol, and your backend server is configured to accept it. If you have multiple layers of proxies (e.g., AWS ELB -> HAProxy -> Nginx), each proxy in the chain needs to be configured correctly to pass the protocol along. HAProxy, for instance, can be configured to accept-proxy on its frontend and send-proxy or send-proxy-v2 on its backend.
After successfully configuring Proxy Protocol, the next common hurdle is ensuring your application logs and analytics tools are correctly parsing and displaying the original client IP addresses.