How to master SSL termination in HAProxy: considerations and configurations

How to master SSL termination in HAProxy: considerations and configurations

How-Tos Published on 7 mins

SSL termination (or TLS if you prefer the newfangled term!) is a standard requirement these days. But how do you actually configure this on your HAProxy load balancer? And how does a 'listen' configuration differ from a 'frontend and backend' configuration?

Here's a simple introduction to SSL offload and SSL termination in HAProxy to get you started.

The basics of SSL/TLS connections

In today's security focussed world, SSL connections (alright, alright, TLS connections...) have quickly become not just the norm but a requirement. Almost all browsers attempt to upgrade connections to HTTPS, and plain old HTTP is getting the cold shoulder. However, this isn't just the case for HTTP connections. We're now seeing the majority of TCP load balancing also requiring SSL termination/offload in modern applications.

Yep, you read right. I just stuck SSL termination and offload together in the same sentence like they're the same; they're definitely not. They are however close enough to each other that we use them interchangeably quite often. Although we really shouldn't. So, what is the difference between the two?

What is SSL/TLS termination?

SSL termination is when the load balancer is terminating the SSL connection. That is, it is the end of the SSL connection and the onward connection to the back-end is conducted via unencrypted means.

What is SSL/TLS offload?

SSL offload is when the burden of SSL related functions pertaining to the connection is offloaded to the load balancer. This relieves the cryptographic strain from the real servers.

OK, that makes it simpler, right? Good. Now that we understand that, it's probably worth pointing out that SSL termination is a specific function of SSL offload. That means that all SSL termination is SSL offload but not all SSL offload is SSL termination.

Got it? Great! Moving on 🤪.

In this particular article we are going to cover the main features and functionality, as well as the configuration of SSL termination.

Why use SSL/TLS termination?

SSL termination is the most regularly implemented kind of SSL offload. As we have already covered it is terminating the SSL traffic at the load balancer and sending it on as plain text. As the real servers are not having to perform any cryptographic functions on top of whatever services they are providing, it reduces the burden upon them freeing up resources to better perform their intended function.

What are the benefits of SSL/TLS termination at the load balancer?

When you terminate SSL at your load balancer you also simplify your certificate management. Instead of having to create, update, and maintain certificates for all your real servers, you only have to do that work for the certificate(s) installed on the load balancer.

Centralising your SSL processing also allows you to manage your SSL policies from one place. You can define the permitted ciphers and cipher suites and ensure that your configuration is consistent amongst all backend servers.

If you are operating a microservices architecture on your backend servers or you require some advanced content switching to happen at the load balancer you will need to unencrypt that traffic first. Once the traffic is unencrypted it can be run through your ACLs (Access Control Lists) and sent on it's merry way.

How to configure SSL/TLS termination in HAProxy

There are two main way to go about configuring HAProxy for SSL termination:

  1. You can add it as a listen configuration; or
  2. You can split it into frontend and backend configurations.

Both are valid, but splitting into frontend and backend configurations allows for much more flexibility of implementation.

If you are just performing SSL termination for a single pool of web servers then this could be simply achieved with a listen configuration.

Listen configuration for SSL termination in HAProxy

Before you are able to start with any of this, you will of course need an SSL certificate to perform the encryption. We already have a blog post about that if you need some help with it, you can find that here: How to create an SSL certificate in Linux.

Here's what you need for a listen configuration:

listen SSL_Termination
    bind transparent ssl crt /etc/ssl/your_domain.pem
    mode http
    balance leastconn
    option http-keep-alive
    timeout http-request 5s
    option forwardfor
    timeout tunnel 1h
    option redispatch
    option abortonclose
    maxconn 40000
    option httplog
    server web-server-1 id 1 weight 100 check
    server web-server-2 id 2 weight 100 check

To take it back to absolute basics, this bit here is about as simple as you can make it whilst still being functional:

listen SSL_Termination
    bind ssl crt /etc/ssl/your_domain.pem
    server web-server-01

The above configuration will listen for requests coming in on, unencrypt that traffic, and pass it on to web-server-01 as plain HTTP.

Frontend and backend configuration for SSL/TLS termination in HAProxy

There is slightly more to do when you split the configuration into frontend and backend blocks, but this does offer some advantages over the simple listen block which make this approach worthwhile. Specifically, using frontends and backends allows for complex routing or content switching.

Using ACLs you are able to achieve some very clever setups and implementations of HAProxy. This is particularly useful in microservices architectures where different parts of a URL path may actually need to go to entirely different servers to form the complete response. This control can be extremely granular and ACLs are available to make direct requests in a myriad of ways.

So ultimately you achieve simplicity through complexity. I know this sounds like (and, ok, actually is) an oxymoron but the more complex your infrastructure and requirements, the simpler it becomes to administer by separating things out into different backend configuration blocks. In other words, you're able to structure your configuration so that it becomes obvious what config is performing what actions!

Here's what you need to do...

So, let's start with a simple version of a frontend backend configuration. And it really is pretty simple:

frontend SSL_Termination
    bind *:443 ssl crt /etc/ssl/your_domain.pem
    default_backend web_servers
backend web_servers
    server web_server_1

The frontend SSL_Termination has a bind that is listening on all IP addresses on port 443, and any matching traffic that comes into HAProxy is dealt with by this frontend.

There are no other rules or configurations in place so it needs a default to send all relevant traffic to. In this case, that is the web_servers backend. The default_backend web_servers receives the unencrypted traffic from the frontend and sends it to the configured web server.

Next, is a slightly more complex implementation where SNI (Server Name Identification) is being used. In this instance, requests will be sent to different backends based on the server name:

frontend SSL_Termination
    bind *:443 ssl crt /etc/ssl/your_domain.pem
    acl sni_website req_ssl_sni -i
    acl sni_docsite req_ssl_sni -i
    use_backend web_servers if sni_website
    use_backend doc_servers if sni_docsite
    default_backend default
backend web_servers
    server web_server_1
backend doc_servers
    server doc_server_1
backend default
    server default

So now we have some ACL rules that are going to do the traffic matching, and some additional rules that define where the traffic will go if an ACL match is made.

If a request for the website comes into HAProxy it is going to be handled by the frontend SSL_Termination and unencrypted. As the traffic is now unencrypted it can be parsed and routed based on things like the URL path.

In the above example, we are using the SNI information which does not need to be unencrypted to be parsed. HAProxy runs the request through its configuration and then we hit the first ACL rule sni_website . As the request is going to have an SNI value of, this will evaluate to TRUE.

As the request then runs through the rest of the configuration it hits the use_backend rule, which it matches as it passes the IF condition of sni_website being TRUE. The request is then passed on to the web_servers backend and sent onto the configured real server.

And there you have it. That's what the configuration looks like in HAProxy! It's pretty simple to configure, but it performs an increasingly necessary function.

How to configure SSL/TLS termination in Loadbalancer Enterprise

Want to make things even easier?

Whilst it is simple enough to configure SSL termination in HAProxy, it is however even easier to do this on your appliance, as you can see from this quick video which shows that this can be done in just a few clicks:

  1. Go to 'Cluster Configuration', then click 'Layer 7 - Virtual Services'.
  2. Click the 'Add a new Virtual Service' button.
  3. Add a label ('SSL_Termination'), the IP address, and your port.
  4. Click 'Advanced +' .
  5. In the Termination section, tick the 'Create SSL Termination' box and click 'Update'.
  6. On the left hand side, then click 'Layer 7 - Real Servers'.
  7. Click the 'Add a new Real Server' button.
  8. Add a label ('WebServer1'), add the web server IP address and click 'Update'.
  9. On the left hand side, then click on 'System Overview'
  10. Click the 'Reload HAProxy' button.

How easy was that?!!

What other types of SSL/TLS offload are there?

SSL termination is something that is pretty simple to implement both in HAProxy, and with Loadbalancer Enterprise. And, as the world moves to being HTTPS/SSL first, you should now have the information you need to move with this trend and keep your applications secured.

This has been a taster and an introduction to SSL offload, but there are many more things that can be achieved with SSL offload such as mTLS. If you'd like to know more about mTLS, check out the links below:

In the meantime, let me know in the comments below if there are any other topics you'd like me to do an explainer on.

Try SSL termination in 10 easy steps