The HAProxy load balancer provides high-performance SSL termination, allowing you to encrypt and decrypt traffic. You can quickly and easily enable SSL/TLS encryption for your applications by using HAProxy SSL termination.
HAProxy is compiled with OpenSSL, which allows it to encrypt and decrypt traffic as it passes. In this blog post, you will learn how to set this up and why delegating this function to HAProxy simplifies your infrastructure.
The Benefits of SSL Termination
When you operate a farm of servers, it can be a tedious task maintaining SSL certificates. Even using a Let’s Encrypt Certbot to automatically update certificates has its challenges because, unless you have the ability to dynamically update DNS records as part of the certificate renewal process, it may necessitate making your web servers directly accessible from the Internet so that Let’s Encrypt servers can verify that you own your domain.
Enabling SSL on your web servers also costs more CPU usage, since those servers must become involved in encrypting and decrypting messages. That CPU time could otherwise have been used to do other meaningful work. Web servers can process requests more quickly if they’re not also crunching through encryption algorithms simultaneously.
The term SSL termination means that you are performing all encryption and decryption at the edge of your network, such as at the load balancer. The load balancer strips away the encryption and passes the messages in the clear to your servers. You might also hear this called SSL offloading.
SSL termination has many benefits. These include the following:
You can maintain certificates in fewer places, making your job easier.
You don’t need to expose your servers to the Internet for certificate renewal purposes.
Servers are unburdened from the task of processing encrypted messages, freeing up CPU time.
Enabling SSL with HAProxy
HAProxy version 1.5, which was released in 2016, introduced the ability to handle SSL encryption and decryption without any extra tools like Stunnel or Pound. Enable it by editing your HAProxy configuration file, adding the ssl
and crt
parameters to a bind
line in a frontend
section. Here’s an example:
frontend www.mysite.com | |
bind 10.0.0.3:80 | |
bind 10.0.0.3:443 ssl crt /etc/ssl/certs/mysite.pem | |
default_backend web_servers |
The ssl
parameter enables SSL termination for this listener. The crt
parameter identifies the location of the PEM-formatted SSL certificate. This certificate should contain both the public certificate and the private key. That’s it for turning on this feature. Once traffic is decrypted it can be inspected and modified by HAProxy, such as to alter HTTP headers, route based on the URL path or Host, and read cookies. The messages are also passed to backend servers with the encryption stripped away.
Although you lose some of the benefits of SSL termination by doing so, if you prefer to re-encrypt the data before relaying it, then you’d simply add an ssl
parameter to your server
lines in the backend
section. Here’s an example:
backend web_servers | |
balance roundrobin | |
server server1 10.0.1.3:443 check maxconn 20 ssl | |
server server2 10.0.1.4:443 check maxconn 20 ssl |
When HAProxy negotiates the connection with the server, it will verify whether it trusts that server’s SSL certificate. If the server is using a certificate that was signed by a private certificate authority, you can either ignore the verification by adding verify none
to the server
line or you can store the CA certificate on the load balancer and reference it with the ca-file
parameter. Here’s an example that references the CA PEM file:
backend web_servers | |
balance roundrobin | |
server server1 10.0.1.3:443 check maxconn 20 ssl ca-file /etc/ssl/certs/ca.pem | |
server server2 10.0.1.4:443 check maxconn 20 ssl ca-file /etc/ssl/certs/ca.pem |
If the certificate is self-signed, in which case it acts as its own CA, then you can reference it directly.
Redirecting From HTTP to HTTPS
When a person types your domain name into their address bar, more likely than not, they won’t include https://. So, they’ll be sent to the http:// version of your site. When you use HAProxy for SSL termination, you also get the ability to redirect any traffic that is received at HTTP port 80 to HTTPS port 443.
Add an http-request redirect scheme
line to route traffic from HTTP to HTTPS, like this:
frontend www.mysite.com | |
bind 10.0.0.3:80 | |
bind 10.0.0.3:443 ssl crt /etc/ssl/certs/mysite.pem | |
http-request redirect scheme https unless { ssl_fc } | |
default_backend web_servers |
This line uses the unless
keyword to check the ssl_fc
fetch method, which returns true unless the connection used SSL/TLS. If it wasn’t used, the request is redirected to the https scheme. Now, all traffic will end up using HTTPS.
This paves the way to adding an HSTS header, which tells a person’s browser to use HTTPS from the start the next time they visit your site. You can add an HSTS header by following the steps described in our blog post, HAProxy and HTTP Strict Transport Security (HSTS) Header in HTTP Redirects.
Limiting Supported Versions of SSL
As vulnerabilities are discovered in older versions of SSL and TLS, those versions are marked deprecated and should no longer be used. With HAProxy, you can allow only certain versions of SSL to be negotiated. Add an ssl-min-ver
directive to a frontend
, specifying the oldest version you want to support.
In the following example, only TLS version 1.2 and newer are allowed:
frontend www.mysite.com | |
bind 10.0.0.3:80 | |
bind 10.0.0.3:443 ssl crt /etc/ssl/certs/mysite.pem ssl-min-ver TLSv1.2 | |
http-request redirect scheme https unless { ssl_fc } | |
default_backend web_servers |
Today, possible values for this parameter are:
SSLv3
TLSv1.0
TLSv1.1
TLSv1.2
TLSv1.3
You can set this for all proxies by adding it to your global
section in the form of an ssl-default-bind-options
directive, as shown:
global | |
ssl-default-bind-options ssl-min-ver TLSv1.2 |
Limiting Supported Certificates
In addition to setting the allowed versions of SSL and TLS, you can also set the encryption ciphers that you’ll use by adding a ciphers
parameter to the bind
line. These are set in preferred order, with fallback algorithms bringing up the end of the list. HAProxy will select the first cipher that the client also supports unless the prefer-client-ciphers
parameter is present, in which case the client’s preferred cipher is selected.
It looks like this:
bind 10.0.0.3:443 ssl crt /etc/ssl/certs/mysite.pem ssl-min-ver TLSv1.2 ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 |
Consider using the Mozilla SSL Configuration Generator when deciding which ciphers to include.
You can also set a default value by adding an ssl-default-bind-ciphers
directive to your global
section, as shown:
global | |
ssl-default-bind-ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256 |
Choosing the Certificate With SNI
Server Name Indication (SNI) is a TLS extension that allows the browser to include the hostname of the site it is trying to reach in the TLS handshake information. You can use this to dynamically choose which certificate to serve.
Instead of setting the crt
parameter to the path to a single certificate file, specify a directory that contains multiple PEM files. HAProxy will find the correct one by checking for a matching common name or subject alternative name.
Here’s an example:
frontend www.mysite.com | |
bind 10.0.0.3:80 | |
bind 10.0.0.3:443 ssl crt /etc/ssl/certs/ | |
http-request redirect scheme https unless { ssl_fc } | |
default_backend web_servers |
If the client does not send SNI information, HAProxy uses the first file listed in the directory, sorted alphabetically. Therefore, it’s a good idea to name the PEM files so that the default certificate is listed first.
Supporting EC and RSA Certificates
HAProxy supports both Elliptic Curve (EC) and RSA certificates and will choose the one that the client supports. To enable this, store both certificates on the load balancer server, but name one with an .rsa extension and the other with an .ecdsa extension. For example, mycert.pem.rsa and mycert.pem.ecdsa. Then, in the HAProxy configuration, leave off the extension, like this:
bind 10.0.0.3:443 ssl crt /etc/ssl/certs/mycert.pem |
Client Certificates
You can restrict who can access your application by giving trusted clients a certificate that they must present when connecting. HAProxy will check for this if you add a verify required
parameter to the bind line, as shown:
bind 10.0.0.3:443 ssl crt /etc/ssl/certs/mysite.pem verify required ca-file /etc/ssl/certs/ca.pem crl-file /etc/ssl/certs/crl.pem |
In addition to verify required
, you can use ca-file
to set a path to a CA file in order to verify that the client’s certificate is signed and trusted. You can also include a crl-file
parameter to indicate a certificate revocation list.
Enabling SSL Termination: Final Word
In this blog post, you learned how to enable SSL termination with HAProxy. Allowing HAProxy to manage encryption and decryption has several benefits, including reducing work done on your backend servers, making certificate maintenance easier, and avoiding exposing your servers directly to the Internet for certificate renewal purposes.
Want to stay up to date on topics like this? Follow us on Twitter and subscribe to this blog! You can also join the conversation on Slack.
Explore the advanced features available in HAProxy Enterprise. Contact us to learn more and sign up for a free trial.
Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.