Software Engineer, builder of webapps

Using SSL/HTTPS with HAProxy

Update (6/27/2014) - On June 19th, 2014, HAProxy 1.5.x was released and is now considered stable.

Last time I posted about HAProxy, I walked you through how to support domain access control lists (also known as "vitual hosts" for those of you using Apache and Nginx) so that you can route to different applications based on the incoming domain name. Since then, Ive had a few requests on how to support SSL and HTTPS with HAProxy since its not the most obvious thing.

The reason its not obvious is because its not "officially" supported yet in the current stable release (1.4) but it is available in the current 1.5 dev branch. If you intend to use this in a production setting, proceed with caution. As of June 19th, 2014, the 1.5.x branch is considered stable

Compiling

For this example, we'll be using Ubunut 12.04 LTS as our base operating system and will be building HAProxy from source. Before we start to build it, we need to make sure we have the dependencies installed

sudo aptitude update
sudo aptitude install build-essential make g++ libssl-dev

Next, let's download the latest version of HAProxy and compile it with the SSL option.

wget http://haproxy.1wt.eu/download/1.5/src/devel/haproxy-1.5-dev21.tar.gz
tar -xzf haproxy-1.5-dev21.tar.gz
cd haproxy-1.5-dev21make USE_OPENSSL=1sudo make install

Setup

Cool, now we have HAProxy installed and its time to setup our config file. In the following example config, we will setup HAProxy to accept connections on a single domain, but it will force redirect to the secure connection.

globallog 127.0.0.1    local0log 127.0.0.1    local1 noticemaxconn 4096user haproxygroup haproxydaemondefaultslog    globalmode    httpoption    httplogoption    dontlognulloption forwardforoption http-server-closestats enablestats auth someuser:somepasswordstats uri /haproxyStatsfrontend http-inbind *:80reqadd X-Forwarded-Proto:\ httpdefault_backend application-backendfrontend https-inbind *:443 ssl crt /etc/ssl/*your ssl key*reqadd X-Forwarded-Proto:\ httpsdefault_backend application-backendbackend application-backendredirect scheme https if !{ ssl_fc }balance leastconnoption httpcloseoption forwardforcookie JSESSIONID prefix
    #enter the IP of your application hereserver node1 10.0.0.1 cookie A check 

A lot of the stuff at the top of the config is fairly basic boiler-plate things. We want to pay attention to is everything below the defaults. As you can see, we're telling HAProxy to listen on both ports 80 and 443 (HTTP and HTTPS respectively) and each uses the backend "application-backend" as the default.

A side note here real quick; the things we learned in the previous post on access control lists can be directly applied to this situation.

The new section here is the additional https-in section. This tells HAProxy to listen on port 443 (the default port for HTTPS) and specifies the SSL certificate to use. Generating SSL certificates can be a huge pain in the ass and sometimes depends on the authority that is issuing it. The one thing to know though is that the certificate (unless it's a wildcard cert) MUST be issused for the domain that you are sending through HAProxy.

Now, in our backend definition, the first line is really the only thing thats different. This tells HAProxy that if the incoming request (since we're using the same backend for both HTTP and HTTPS) is not secured over SSL, to redirect to the same route using HTTPS if ssl is available (thats the !{ssl_fc}).

Wrap-up

That pretty much does it. It's not all that different from the config in the previous exercise, but it can be a little tricky to setup and configure, especially if your cert isnt configured correctly or doesnt have the correct permissions.