Set up HAProxy HTTPS – Load balance Over HTTPS Connections
In our first guide on how to set up HAProxy, we were lazy. When we set up HAProxy we didn’t use any SSL Certificates and let CloudFlare do all of the work. You will want to deal with HTTPS connections over your HAproxy load balancer in some situations. HAProxy HTTPS provides two options to deal with secure connections.
* HAProxy SSL Passthrough
SSL Passthrough does what it says, it takes the connection and throws it to a backend server to decrypt. This could be considered faster but has many drawbacks like hiding the client’s true IP. That’s because we don’t decrypt the data as it passes through the load balancer.
* HAProxy SSL Termination
With SSL Termination, HAProxy decrypts the connection as it hits the load balancer and then either encrypts it again to send on to a backend server or just sends the data in an unencrypted fashion. This is considered the default choice but it depends on how you are using HAProxy with HTTPS connections.
Set up HAProxy SSL Termination
We have created this guide based on a specific use case. Our customer has a need for a High Availability MySQL Cluster. In a previous article, we created a network of MySQL servers. We have 5 servers in our cluster running Master-Master MySQL Replication. We now need to configure HAProxy to distribute the load over our cluster. This will provide High Availability. Because our cluster is using Cloudflare under “SSL Full” we installed a Cloudflare Origin certificate on our NGINX cluster. Now we are going to configure HAProxy to work with our Cloudflare Origin Certificate too.
HAProxy SSL Certificate
This next step assumes you have your Cloudflare Origin certificate or any other valid certificate on your server. We combined the origin certificate and private key into one file located at /etc/ssl/cert.pem. Open up the /etc/haproxy/haproxy.cfg file. Replace with the following.
frontend http_front
bind :80
bind :443 ssl crt /etc/ssl/cert.pem
default_backend be_d1
backend be_d1
balance leastconn
server S1FR xx.xx.xx.xx:443 check ssl verify none
server S2UK xx.xx.xx.xx:443 check ssl verify none
server S3DE xx.xx.xx.xx:443 check ssl verify none
server S4CA xx.xx.xx.xx:443 check ssl verify none
server S5USAW 1xx.xx.xx.xx:443 check ssl verify none
global
log /dev/log local0
log /dev/log local1 notice
# chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin
stats timeout 30s
user haproxy
group haproxy
# ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
# ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256
# ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
listen stats
bind xx.xx.xx.xx:1936 ssl crt /etc/ssl/cert.pem
mode http
stats enable
stats hide-version
stats show-node
stats realm Haproxy\ Statistics
stats uri /haproxy?stats
stats admin if TRUE
stats auth User:Pass
So, here we can see we are listening for connections on both port 80, insecure. But also on port 443, secure. Note, that we have specified our Cloudflare Origin certificate in the statement.
bind :443 ssl crt /etc/ssl/cert.pem
In the backend be_d1 block, we specify our backend servers. But notice how we append a secure port to the IPs.
backend be_d1
balance leastconn
server S1FR xx.xx.xx.xx:443 check ssl verify none
server S2UK xx.xx.xx.xx:443 check ssl verify none
server S3DE xx.xx.xx.xx:443 check ssl verify none
server S4CA xx.xx.xx.xx:443 check ssl verify none
server S5USAW 1xx.xx.xx.xx:443 check ssl verify none
HAProxy HTTPS SSL Certificate
The important bit here is the ssl verify none. Connections are encrypted again before being sent on to the backend servers. Without this, we would see an error about insecure connections being sent to a secure port. We are using the same certificate on HAProxy as on our cluster. Finally, restart the cluster.
systemctl restart haproxy
In this example, HAProxy statistics can be viewed at http://IPv4:1936/haproxy?stats. So if we take a look we can see HAProxy HTTPS is routing connections to our backend server.
We can further confirm this over https. Our HAProxy URL is https://dgb-ha.dev.gb.net. So, give it a try, you will be routed to one of the backend servers over a secure connection. Refresh the page after 30 seconds to be sent to a different backend server.
So, in our final guide, we will load balance MySQL connections using HAProxy. Once complete we will have a high availability cluster running MySQL, PHP, NGINX.