This protocol is especially useful when balancing SSL traffic where it is impossible to modify headers. The best solution is to configure haproxy in passthrough mode, terminating the SSL tunnel on the web server but passing the origin IP information through the proxy protocol. This way, the web server receives the client’s IP.
The information provided by the proxy protocol is the same as that obtained using getsockname() and getpeername():
- Address type (AF_INET - IPv4, AF_INET6 - IPv6, AF_UNIX)
- Socket protocol (SOCK_STREAM - TCP, SOCK_DGRAM - UDP)
- Source and destination address
- Source and destination port
Using the proxy protocol allows us to chain multiple balancers/proxies without losing the source IP address at any time. The protocol simply consists of inserting an easily parseable header at the beginning of the connection.
The protocol supports two header formats:
- send-proxy: V1 easily readable by humans
- send-proxy-v2: V2 binary format
Both protocols have been designed to work with the minimum TCP segment size (576 - 40 = 536 bytes), which ensures that the entire header will always be delivered in a single transaction.
The protocol can be applied to a multitude of services:
- HTTP
- SSL
- FTP
- SMTP
- POP
- IMAP
- LDAP
- SSH
- RDP
Does this mean that if you jump from server to server via SSH, you can know the source IP?
No, it means that if we balance SSH traffic through Haproxy, the final SSH server will receive the client’s source IP and not that of the balancer, since the openssh server is capable of interpreting the proxy-protocol information sent by Haproxy. However, the SSH server does not natively support such functionality.
http://jonnyzzz.com/blog/2017/05/24/ssh-haproxy/
Haproxy allows both receiving and emitting information.
Server-side: “accept-proxy” must be configured in the “bind” line, useful if multiple balancers are chained.
frontend web-ssl
bind *:443 accept-proxy
mode tcp
default_backend nodes-ssl
Client-side: “send-proxy” must be configured in the “server” line.
backend nodes-ssl
balance roundrobin
mode tcp
server SRV1 X.X.X.X:443 check send-proxy
server SRV2 Y.Y.Y.Y:443 check send-proxy
NOTE: For debugging, we leave send-proxy, for production send-proxy-v2.
To make the destination web server read the proxy protocol information, we must follow certain steps depending on the web server used.
To make Apache read the proxy protocol info:
cd mod-proxy-protocol/
make
cp .libs/mod_proxy_protocol.so /usr/lib/apache2/modules/
LoadModule proxy_protocol_module modules/mod_proxy_protocol.so
In the config of the vhost in question:
CustomLog ${APACHE_LOG_DIR}/access.log "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\""
For nginx it would be:
https://docs.nginx.com/nginx/admin-guide/load-balancer/using-proxy-protocol/
The proxy protocol allows us to make very advanced configurations, such as balancing mysql traffic and configuring user permissions based on the client’s source IP:
https://www.haproxy.com/blog/using-haproxy-with-the-proxy-protocol-to-better-secure-your-database/