Multiple SSL Configurations in the Same IP/Port with HAProxy

How we used some clever TCP routing to overcome the HAProxy limitations regarding SSL configuration.

David Barral
Trabe
3 min readJun 29, 2020

--

Photo by Thomas Jensen on Unsplash

HAProxy is a free, very fast and reliable solution offering high availability, load balancing, and proxying for TCP and HTTP-based applications. It is particularly suited for very high traffic web sites and powers quite a number of the world’s most visited ones. Over the years it has become the de-facto standard opensource load balancer, is now shipped with most mainstream Linux distributions, and is often deployed by default in cloud platforms.

HAProxy, as many other proxy solutions (Pound, Apache or Nginx, to name a few), has support to handle SSL connections.

In this story we’ll see how to set up SSL with HAProxy for one or many domains listening on the same IP/port, and more specifically, when the SSL configuration differs from one domain to another. This is not for the faint of heart. Be aware.

HAProxy: layers, frontends, backends and ACLs. A very brief primer

If you are new to HAProxy, I would suggest reading this introduction. It explains concepts we will use in this tutorial:

  • Backends: set of servers that will handle the requests.
  • Frontends: entry points that define how requests are routed to backends.
  • ACLs (Access Control Lists): conditions to be tested. Based on those tests frontends will route requests to the different backends.
  • TCP layer (layer 4) and Application layer (layer 7) load balancing. Check the OSI model if you want to dig further on the theory side of things.

For the rest of this story I assume you have SSL certificates for your different domains. Check this tutorial if you want to use Let’s Encrypt certificates, which I strongly recommend. If you are just playing on your local machine, you can use self signed certificates.

Redirect all HTTP traffic to HTTPs

First things first. We need to redirect all incoming HTTP traffic (port 80) to HTTPS (port 443). To do that we define a frontend and use an ACL to detect the HTTP protocol and redirect using the http-request directive.

One domain, one certificate

The first scenario is the simplest one. We have one domain with its SSL certificate and we redirect all requests to a backend.

Two domains, one certificate

This a very similar scenario to the previous one. We still have one SSL config and we select different backends, using ACLs based on the requested domain. We just need to use a wildcard certificate or a certificate with several domain aliases.

Two domains, two certificates

There are three options here:

  • Uso two cert options when binding.
  • Concatenate multiple certs in just one PEM file.
  • Use cert with a path to a folder containing all the certs.

Two domains, two certificates with TCP proxying

There’s another way to achieve the same results that’s a bit tricky. It may seem overkill given the previous examples, but bear with me.

So, to allow different SSL configurations we can use the TCP routing capabilities of HAProxy:

  • The main frontend watches the TCP packages accepting incoming handshakes.
  • Given the domain for the handshake the request is proxied through an Unix socket (one per domain).
  • We bind two frontend to these sockets. Each frontend configures the SSL specifics of the domain and redirects to the backend.

Pretty tricky 😅. I recommend you to read the relevant bits of the HAProxy manual to truly understand the solution.

These may seem quite complicated when you can just use multiple certificates or a multi domain certificate, but what happens if you need different SSL configurations, not just different certificates.

A real world scenario

In a recent project we needed to serve two domains using SSL, and use certificate based authentication in only one of them. We used the proxy approach in order to set up one of the HTTPS frontends to also validate client certificates using a set of CA certificates (the ones used to issue the client certificates, in our case the Spanish FNMT ones).

Summing up

By leveraging the TCP routing capabilities of HAProxy and Unix sockets we can overcome the limitations imposed at the HTTP routing level.

My kudos to Lukas Tribus. Thanks to his comment in the HAproxy Discourse I was able to solve this conundrum.

--

--

David Barral
Trabe

Co-founder @Trabe. Developer drowning in a sea of pointless code.