You can use haproxy to load balance SSL connections to multiple backend servers, so the backend servers terminate SSL instead of haproxy. The only trick is to enable Proxy Protocol on both haproxy and your backend servers, so the user's real IP address is preserved.
For example, if you have two nginx app servers 10.0.0.11
and 10.0.0.12
and one haproxy load balancer 10.0.0.10
.
Edit /etc/haproxy/haproxy.cfg
adding these lines:
frontend https-in
bind *:443
default_backend https-servers
backend https-servers
mode tcp
balance roundrobin
server srv1 10.0.0.11:443 send-proxy
server srv2 10.0.0.12:443 send-proxy
With an nginx server config like:
server {
server_name example.com;
root /opt/example/current/app;
listen 443 ssl http2 proxy_protocol;
set_real_ip_from 10.0.0.10/32;
real_ip_header proxy_protocol;
ssl_certificate /etc/ssl/example/ssl.crt;
ssl_certificate_key /etc/ssl/example/ssl.key;
location / {
include uwsgi_params;
uwsgi_pass unix:/tmp/app.sock;
}
}
This tells haproxy to setup a Layer 4 proxy to forward all TCP connections unmodified to the two nginx servers using roundrobin to balance the connections.
The nginx app servers will share the load of negotiating SSL and parsing the HTTP requests. Proxy Protocol forwards the originating client's IP address from haproxy to nginx without having to modify the HTTP request headers.
Notice how we told nginx to trust the IP address of your haproxy load balancer 10.0.0.10
to give us the client's real IP.
SSL is distributed among your two nginx app servers, and your nginx log files show the correct client IP address for each request.
I wrote a blog post describing this:
https://wakatime.com/blog/34-how-to-scale-ssl-with-haproxy-and-nginx