Sunday, 1 February 2015

HAProxy balancing https backends

Recently I needed to configure load balancing in my environment, where I needed to balance between few https servers with sticky sessions enabled. I looked in the haproxy manual, I googled, I asked - and for days there was no making it work.

Most of the haproxy configuration examples out there are for the case when client connects to haproxy via https, and then haproxy decrypts it and balances requests between http backends. Few examples around https backends assumed that no sticky sessions are needed, so they all sit on top of tcp. To this day I have not found a guide or an example of how to configure what I need, so once I figured out how to do that, I thought I'd share.

So the way you do it is:
0) You need haproxy 1.5+. haproxy before that did not support https on its own.
1) A client connects to haproxy via https. There need to be a certificate+private key combination (that client would trust) on the haproxy server.
2) HAProxy decrypts the traffic and attaches a session cookie. If the cookie is already there, it knows where to send the request further.
3) HAProxy encrypts the traffic again before sending it to backend (where backend can decrypt it).
4) and the other way around.

And the configuration for that is:

  • For both backend and frontend you should have mode http.
  • In the bind line you need to add ssl cert <path to haproxy certificate + private key file>.
  • In the backend section you need to set load balancing algorithm - e.g. roundrobin or leastconn.
  • In the backend section you also need to set a cookie - e.g. cookie JSESSIONID insert indirect no cache.
  • For each server you need to say "ssl" after the ip, and then also set a cookie.
For me the one part I couldn't find in any guides was to put "ssl" in the server line (as well as in the bind line). I might have missed it somewhere in the not-so-helpful haproxy manual.

One thing I didn't go into was setting up a proper certificate on a backend servers in my environment, because of course in test environment they are self signed and all that. In order to work around it, just add another global setting to the haproxy settings: ssl-server-verify none.

And here's the example of the config file frontend & backend sections to make it work:

frontend  main
    mode http
    bind :443 ssl crt /etc/haproxy/cert.pem
    default_backend app

# round robin balancing between the various backends
backend app
    mode http
    balance     roundrobin
    option httpchk GET /concerto/Ping
    cookie JSESSIONID insert indirect nocache
    server  app1 ssl check cookie app1
    server  app2 ssl check cookie app2
    server  app3 ssl check cookie app3
    server  app4 ssl check cookie app4