How to get SSL with HAProxy getting rid of stunnel, stud, nginx or pound

Update: HAProxy can now handle SSL client certificate: SSL Client certificate management at application level


HAProxy is well know for its performance as a reverse-proxy and load-balancer and is widely deployed on web platforms where performance matters. It is sometimes even used to replace hardware load-balancers such as F5 appliances.
When the platform requires SSL, it is common to use nginx, Pound or Recently, stud came in the dance with a major advantage over other software: support for HAProxy’s proxy protocol.

At HAProxy Technologies, we build our ALOHA load-balancers using HAProxy and we use stunnel as the SSL offloading software. Our clients wanted some new features on our SSL implementation we could not provide through stunnel.
By the way, you can find our stunnel patches here:
An other important thing to notice, is that stunnel does not scale very well: when managing a lot en encrypted connections, stud or nginx are far much better.
That’s why we decided to implement SSL directly in HAProxy. For now, it is still quite basic: SSL offloading with SNI support and wildcard certificates, ability to encrypt traffic to servers.
But at least, the performance are here!
We’ll keep on improving it later with new features, IE: client certificate management and some fun stuff with ACLs: stay tuned!

Remember that the job was done by HAProxy Technologies engineers.

Note that if you’re using the softwares listed above for other purpose than SSL, then you may still use them. For example, nginx performs very well on static content and on dynamic using php-fpm.

SSL offloading diagram

This is pretty simple, as shown on the picture below. The client will get connected on HAProxy using SSL, HAProxy will process SSL and get connected in clear to the server:
ssl offloading diagram

HAproxy installation

cd /usr/src
tar xzf haproxy-1.5-dev12.tar.gz
cd haproxy-1.5-dev12/
sudo make PREFIX=/opt/haproxy-ssl install

HAProxy configuration for SSL offloading

First of all, you have to generate a few keys and a certificates using openssl and concatenate them in a file, the certificate first, then the key.

HAProxy configuration, very basic, for test purpose, and just to let you know which lines are very important:

 log local0
 option tcplog

frontend ft_test
  mode http
  bind ssl crt ./haproxy.pem crt ./certs/ prefer-server-ciphers
  # other (self described) options are: [ciphers <suite>] [nosslv3] [notlsv1]
  use_backend bk_cert1 if { ssl_fc_sni cert1 } # content switching based on SNI
  use_backend bk_cert2 if { ssl_fc_sni cert2 } # content switching based on SNI

 mode http
 server srvxlc

backend bk_cert1
  mode http
  server srv1

backend bk_cert2
  mode http
  server srv2

As you can see, HAProxy load one cert haproxy.pem which will be default one, and all the certificates from the certs dir. Actually, I have only 2 for my tests: cert1 and cert2.

Running HAProxy

First, just test the configuration is valid:

/opt/haproxy-ssl/sbin/haproxy -c -f ./hassl.cfg 
[WARNING] 247/110924 (6497) : config : missing timeouts for frontend 'ft_test'.
   | While not properly invalid, you will certainly encounter various problems
   | with such a configuration. To fix this, please ensure that all following
   | timeouts are set to a non-zero value: 'client', 'connect', 'server'.
[WARNING] 247/110924 (6497) : config : missing timeouts for backend 'bk_test'.
   | While not properly invalid, you will certainly encounter various problems
   | with such a configuration. To fix this, please ensure that all following
   | timeouts are set to a non-zero value: 'client', 'connect', 'server'.
Configuration file is valid

Don’t worry about warnings, I purposely wrote a very basic configuration.

Now, you can run HAProxy:

/opt/haproxy-ssl/sbin/haproxy  -f ./ha.cfg

Testing SSL provided by HAProxy

Check the default certificate server name:

openssl s_client -connect -servername
Certificate chain
 0 s:/

HAProxy log line:

[...] ft_test [...]

Checking cert1, loaded from ./certs/ dir:

openssl s_client -connect -servername cert1
Certificate chain
 0 s:/CN=cert1

HAProxy log line:

[...] ft_test bk_cert1/srv1 [...]

Checking cert2, loaded from ./certs/ dir:

openssl s_client -connect -servername cert2
Certificate chain
 0 s:/CN=cert2

HAProxy log line:

[...] ft_test bk_cert2/srv2 [...]

Checking with an unknown servername:

openssl s_client -connect -servername kemp
Certificate chain
 0 s:/

HAProxy log line:

[...] ft_test [...]

When the name is unknown, the failover is well done on the default certificate.

And voilà !!!
Since it has been released in the 1.5 branch, you can use it in production :)

Related articles


About these ads

About Baptiste Assmann

Aloha Product Manager
This entry was posted in HAProxy, layer7, ssl and tagged , , , , , , . Bookmark the permalink.

65 Responses to How to get SSL with HAProxy getting rid of stunnel, stud, nginx or pound

  1. Pingback: HOWTO SSL native in HAProxy | HAProxy Technologies – Aloha Load Balancer

  2. Baptiste, you’re becoming too much of a salesman :-)
    Well, the primary reason for native SSL in haproxy is to connect to servers via SSL, which was very difficult using a third-party component because it required as many stunnel/stud instances as servers, which was really not convenient. Also we wanted to improve the SSL listener to pass all client cert information to haproxy. When we managed to rework the connection layer, it was as easy to have SSL on both sides as it was to have it on one single side, so we did it. In the end, having everything in a single component is much simpler than multiple components. That said, I think we won’t observe the big rush you expect, because people who use stunnel don’t need performance, people who use stud have no reason not to be satisfied, and people who use nginx also use it for complementary features. The main benefit from having everything in haproxy is to have it at one place with SNI and wildcard support.

  3. buriwoy says:

    Hi guys!

    Thanks for long-waited ssl support!

    I’m getting this error
    and my conf is

    I’d appreciate if someone could direct me to correct direction. thanks!

    • wtarreau says:

      since haproxy is able to load certs from directories, it needs exactly one key+crt couple per file. In order to achieve this, you need to concatenate
      the .crt and the .key for each of your certs into a single file (call it .pem).

      • buriwoy says:

        Thanks for response!
        SSL company gave me three files: certificate, SSLCA and ExternalCARoot files. Where should I keep those two files? Concatenate together with .crt and .key?

  4. Flaming says:

    Hi Willy,
    Does SSL_SESSION_ID persistence (by using ACL and stick table) work fine with this SSL proxy mode? Previously I’m using it in TCP mode only.

    Best Regards

  5. mohamed says:

    Hi, thanks for this really good article :)

    i have tried differents configurations in my lab platform ( one linux haproxy and one back end web server IIS 7.5 )
    the problem i have is i can connect with a smartcard ( gemalto card )
    is haproxy can handle this case ? because in this case, we must forward the https to the back end server in https

  6. wtarreau says:

    Hi Mohamed,

    in fact it depends on the application. Many people are doing SSL offloading on front gateways and pass the client certificate information in HTTP headers to the application. That way client certs become compatible with SSL offloading, provided that the application is adapted to fetch the SSL information from HTTP headers instead of the SSL connection. It looks like the most common solution consists in building HTTP header names by appending the same names as the mod_ssl environment variables aftern an “X-” prefix. In general it’s not much work to be done in the application, but still some adaptations are required. We’re currently working on this at Exceliance for the ALOHA appliance, it’s not ready yet but would probably be by the end of the month. At least right now we’re able to verify client certificates in the lab :-)

  7. mohamed says:

    Hi Willy,

    Thanks for the answer and explanation.

    sorry for my ,’noob’ question, i have search on google and read docs/forums etc…
    In TCP mode, with services where the client IP needs to be retained for use with the application/logging, is HAProxy can be used ? ( it seems not )
    i really need to retain the client IP ( on the logs of the web server )

    maybe aloha products support this feature ?


  8. Joshua Sierles says:

    I get this error: parsing [/etc/haproxy/charm.cfg:29] : ‘bind’ : ‘ssl’ option not implemented.

    • Hi,

      Are you sure you have compiled HAProxy with USE_OPENSSL=yes and you’re running the HAProxy you’ve just compiled?
      Please check it by running “haproxy -vv”


      • Joshua Sierles says:

        USE_OPENSSL worked, I missed that from the post. Thanks. Lastly, is it OK to use a certificate with the chain certificates in the file, like those required for godaddy ssl certs?

      • Hi,

        Ye, as long a you reproduce the whole an full chain in your PEM file:
        intermediate cert #1
        intermediate cert #2

  9. buriwoy says:

    @joshua: Did it (concatenating cert, intermediate cert#1, intermediate cert#2, key) work for you?

    I can’t get them work. My browser still shows the site as unverified.


    • Hey,

      Did you concatenate them in the right order?


      • buriwoy says:

        Thanks for reply!

        I got three files from ssl provider: AddTrustExternalCARoot.crt, mysite_com.crt, PositiveSSLCA2.crt. I concatenated the files in two different orders:


        I tried both of’em. Still, my browser shows the site as unverified.


  10. buriwoy says:

    Finally! It’s working!
    Problem was in configuration. Thanks, guys!

  11. AndyH says:

    Hi Willy/Baptiste,

    Really excellent effort on bring SSL offloading to HAProxy – thank you! I’m really impressed with it, and am just fiddling with a setup now – believe I have it successfully compiled with OpenSSL 1.0.1b, and have a basic configuration running. Is there something preventing HAProxy allowing TLS1.2 from being used at this point? I can only get Opera 12.02 (with TLS1.2 protocol activated) to talk TLS1.0 to my test site, yet if I point the same browser to the same test site, but using an stunnel SSL termination (also compiled with OpenSSL 1.0.1b) I can get TLS1.2.

    • wtarreau says:

      Hi AndyH,

      Emeric has just added new options “notlsv11″ and “notlsv12″ I believe, to disable newer versions. I’ll have to check. I haven’t merged the patches yet, but they should be merged into dev13 soon.

  12. Pingback: Benchmarking SSL performance | HAProxy tech – Aloha Load Balancer

  13. Pingback: SSL Client certificate management at application level | HAProxy tech – Aloha Load Balancer

  14. curious_John says:

    I have simple round robin load balancing setup which btw is working flawless,
    listen web-farm
    cookie SERVERID rewrite
    balance roundrobin
    server web1 cookie app1inst1 check inter 2000 rise 2 fall 5
    server web2 cookie app1inst2 check inter 2000 rise 2 fall 5

    How do I implement SSL? I need https to work. I am very new to this. Could you please give me an example?

  15. Christophe says:

    Hi Baptiste,
    Thanks for this great post.
    In waiting to buy a ALOHA load-balancers, I’ve just test this solution for SSL Offloading.
    But I have this error :
    Proxy ‘ft_test': file ‘./cert/server.pem’ : this version of openssl cannot load multiple SSL certificates in bind ‘′ at [haproxy-ssl.conf:22].
    Currently, I use openssl 0.9.8e.
    Which OpenSSL version may I have to use in order to use this functionality ?

    Best regards,

    • Hi Christophe,

      Unfortunately for you, it seems to be openssl version 0.9.8.f. That said, we recommand you to upgrade to the latest available 0.9.8 version. Latest version (1.0.1 something) have new TLS support and improve drastically performance (at least 50%).
      Note: you must compile openssl with TLS/SNI support.


      • Roshan says:

        Hi Baptiste,

        I am tried with latest openssl version also but getting same error.
        Its working fine with single ssl cert
        My config:

        [root@uat ~]# openssl version
        OpenSSL 1.0.1e 11 Feb 2013

        [root@uat ~]# /opt/haproxy-ssl/sbin/haproxy -v
        HA-Proxy version 1.5-dev19 2013/06/17

        [root@uat ~]# less /opt/haproxy-ssl/conf/haproxy.cfg | grep bind
        bind *:443 ssl crt /opt/haproxy-ssl/conf/ssl/

        [root@uat ~]# ll /opt/haproxy-ssl/conf/ssl/
        total 20
        -rw-r–r– 1 root root 4988 Aug 23 14:55 domain1.pem
        -rw-r–r– 1 root root 3554 Aug 23 14:54 domain2.pem

        Note: With single certificate its working fine,

        [root@uat ~]# /opt/haproxy-ssl/sbin/haproxy -f /opt/haproxy-ssl/conf/haproxy.cfg
        [ALERT] 235/015028 (29717) : parsing [/opt/haproxy-ssl/conf/haproxy.cfg:40] : ‘bind *:443′ : this version of openssl cannot load multiple SSL certificates.
        [ALERT] 235/015028 (29717) : Error(s) found in configuration file : /opt/haproxy-ssl/conf/haproxy.cfg
        [ALERT] 235/015034 (29717) : Fatal errors found in configuration.

        Please suggest.

  16. Baptiste/Willy,

    really quick question: I’ve successfully compiled the SSL-enabled HAProxy version, and it seems to be working fine. I’d like my clients to use HTTPS compulsory, i.e. whenever they connect to the website, they’re using HTTPS. I tried configuring a simple redirect using nginx:

    server {
    listen :80
    rewrite ^ https://$server_name$request_uri? permanent;

    That works initially, that is, the first connection is redirected by nginx and reaches HAProxy, which in turn forwards it to the webservers. However, the second action I try to take (a POST command with username/password) goes to nginx instead of HAProxy, going by Firefox’s “Although this page is encrypted, the information you have entered is to be sent over an unencrypted connection” alert, and the POST command never goes through.

    What is the correct way to arrange this HTTP > HTTPS redirect? This is my HAProxy configuration, if needed:

    listen wmc
    bind ssl crt /etc/haproxy/certs/wmc.cert prefer-server-ciphers
    reqadd X-Forwarded-Proto:\ https
    server ws1 cookie ws1 check inter 2000 rise 2 fall 5
    server ws2 cookie ws2 check inter 2000 rise 2 fall 5

    Regars and thanks in advance,

  17. Fafa says:

    Thanks for your great post.
    i have installed openssl with apt-get command. i try your suggested solution to ssl offloading but there is some errors when i run make command.


    root@debian:/usr/src/haproxy-1.5-dev12# make TARGET=linux2628 USE_OPENSSL=1
    In file included from include/types/global.h:30,
    from src/ev_poll.c:23:
    include/types/protocols.h:31:25: error: openssl/ssl.h: No such file or directory
    In file included from include/types/global.h:30,
    from src/ev_poll.c:23:
    include/types/protocols.h:104: error: expected specifier-qualifier-list before âSSL_CTXâ
    In file included from include/types/acl.h:33,
    from include/types/proxy.h:39,
    from include/types/global.h:31,
    from src/ev_poll.c:23:
    include/types/server.h:174: error: expected specifier-qualifier-list before âSSL_CTXâ
    make: *** [src/ev_poll.o] Error 1

  18. avzblog says:

    Fafa, propably, you need to install the openssl-devel package.

  19. Fafa says:

    I use following configuration to load balance https connections, using haproxy 1.4.8. SSL offloading is done by apache.

    listen ssl_to_waf
    mode tcp
    balance roundrobin
    option ssl-hello-chk
    #option forwardfor header X-Client-IP
    server wafA check

    listen ssl_from_waf
    balance roundrobin
    option forwardfor
    server webA check

    For HTTP requests this works great, requests are distributed to my Apache servers just fine. But for HTTPS request, I lose the “forwardfor” information. I need to save the client IP address. How can I use HAproxy to load balance across a number of SSL servers, allowing those servers to know the client’s IP address?

    • hel says:

      The x-forwarded-for allows you to keep the client IP trace in your apache or tomcat logs in w3c format.
      If you loose the https source ip, you probably have a plugin issue at the server level.

  20. Paulo Pires says:

    If one has a PEM protected with passphrase, how can one tell HAProxy to use that password?

  21. Paulo Pires says:

    Every time I start HAProxy?

  22. Paulo Pires says:

    Yeah, I did remove the passphrase and it works almost like a charm. Somehow, my website behind HAProxy is not providing the resources over HTTPS, therefore rendering my website unusable :-(

    Thanks anyway!

  23. Alex says:

    Thanks for sharing this HOWTO with us, just finished configuring and works fine.
    I still have some problems with HAproxy considering the load balanced servers as being down very ofter but I guess its not related to https/ssl

  24. NicolasG says:

    Hi all,

    I tried to run the configuration from this article and I got a Segmentation fault.
    I got this output with gdb:

    Program received signal SIGSEGV, Segmentation fault.
    0x000000000045ece0 in bind_parse_ssl (args=, cur_arg=, px=, conf=, err=) at src/ssl_sock.c:2566 2566 list_for_each_entry(l, &conf->listeners, by_bind)

    I compiled successfully with openssl and my version of ssl is 1.0.0. The version of HAProxy is 1.5.17.

  25. Django says:

    Hi there, I’ve really gotten into this haproxy, I’ve had enough of the quirks in nginx etc.

    But I’m having a problem with using ssl_sni

    This is the error I’m getting when running this command:
    #haproxy -f /etc/haproxy/haproxy.cfg

    [ALERT] 079/102538 (16735) : parsing [/etc/haproxy/haproxy.cfg:26] : error detected while parsing switching rule : unknown ACL keyword ‘ssl_sni’.
    [ALERT] 079/102538 (16735) : Error(s) found in configuration file : /etc/haproxy/haproxy.cfg
    [ALERT] 079/102538 (16735) : Fatal errors found in configuration.

    I built the package using:
    make TARGET=linux26 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 clean install

    No errors appeared in the build output. (I’m running a really hacked-up version of Centos 5.3, well one has to with this distro, everything on their damn repo’s is a hundred years old!), everything’s working fine though, trust me, well, apart from being able to get haproxy to do what I think its supposed to do. And yes haproxy does work if I just go for a straight forward SSL offload and backend server request setup, just doesnt seem to like this ‘ssl_sni’ syntax.

    When running the version command (haproxy -vv), I get this:

    HA-Proxy version 1.5-dev17 2012/12/28
    Copyright 2000-2012 Willy Tarreau

    Build options :
    TARGET = linux26
    CPU = generic
    CC = gcc
    CFLAGS = -O2 -g -fno-strict-aliasing

    Default settings :
    maxconn = 2000, bufsize = 16384, maxrewrite = 8192, maxpollevents = 200

    Encrypted password support via crypt(3): yes
    Built with zlib version : 1.2.3
    Compression algorithms supported : identity, deflate, gzip
    Built with OpenSSL version : OpenSSL 1.0.1e 11 Feb 2013
    OpenSSL library supports TLS extensions : yes
    OpenSSL library supports SNI : yes
    OpenSSL library supports prefer-server-ciphers : yes

    Available polling systems :
    epoll : pref=300, test result OK
    poll : pref=200, test result OK
    select : pref=150, test result OK
    Total: 3 (3 usable), will use epoll.

    And finally, my configuration is rather simple (haproxy.cfg):

    log local1 notice
    maxconn 4096
    user haproxy
    group haproxy
    ca-base /etc/ssl
    crt-base /etc/ssl

    log global
    maxconn 4096
    mode http
    # Add x-forwarded-for header.
    option forwardfor
    option http-server-close
    timeout connect 5s
    timeout client 30s
    timeout server 30s
    # Long timeout for WebSocket connections.
    timeout tunnel 1h

    frontend public
    mode http
    bind ssl crt test.crt
    use_backend server2 if { ssl_sni } # content switching based on SNI
    default_backend server1

    backend server2
    reqadd X-Forwarded-Proto:\ https
    server iis x.x.x.x:xxx

    backend server1
    reqadd X-Forwarded-Proto:\ https
    server reverseproxy x.x.x.x:xxx

    All in all, rather simple requirement, SSL offloading is haproxy’s job, if the http url requested is then send the victim to server2, all others go to the default server1.

    I really want this to work, been at it for 2 days, building different versions, etc etc (the joys of working in Linux hey hahaha)

    Any ideas??

  26. Django says:

    Ah it seems the syntax has changed, instead of ‘ssl_sni’ its now ‘ssl_fc_sni’ – works a treat :)

    If I can get this thing rolling and my bosses are happy with it, then I think a hardware version with support could well be on our list of things to buy!

  27. Christian Ruppert says:


    I tried your example with 2 Certs, /etc/haproxy/haproxy.pem and /etc/haproxy/ssl/.
    So the first one will be used by default and the certs from the dir are loaded/used when it matches the SNI, right?
    haproxy.pem has been created for and the second one is for
    So when I now connect, using openssl or a browser, I always get the first/default cert even though the ACL “use_backend test_cert2 if { ssl_fc_sni }” seems to work fine. I always get the correct backend, so test_cert2 when the SNI is and my default backend for anything else. I just wonder why I always get the default cert instead of the correct one, cert2.
    Any ideas what that may cause?
    haproxy 1.5-dev17

  28. Steve says:


    I’m trying to get haproxy 1.5-dev18 to work with SSL enable and i’m coming across an issue where my request gets pushed to the apache server but i end getting too many redirects. I’m assuming its my haproxy config. Can someone verify if this is correct?

  29. andmarinescu says:

    Hey guys,

    I’m trying to track down some errors that we’re seeing after enabling SSL termination on HAProxy. We’ve recently moved off AWS ELB to HAProxy, so I’m not sure if those errors are normal or if there’s something to be fixed in our configuration.
    I’m getting a relatively small number (about 2-3% of requests) of errors like: Connection closed during SSL handshake and Timeout during SSL handshake. Is this something you’ve run into in the past? Any way of debugging this?

    Thanks! (Sorry if this comment appears twice, logging in with Gravatar seemed to have cancelled my comment)

  30. Patrick says:

    I’m pretty confused about this concatenation…. after purchasing the SSL certificate, I now have the following:

    1. Root cert
    2. Chain cert
    3. Server cert
    and also
    4. A .csr file
    5. A .key file

    Do I just concatenate everything into a single file and call it “haproxy.pem”? Would really appreciate some help!

    • andmarinescu says:

      @patrick: You should concatenate the Chain, Server and key files. I never added the root cert, but I don’t think it can do any harm. Do not add the csr. Also, make sure that the private key is not password protected.

  31. I was getting this to work with a self signed key. I got it to work, but my order was RSA PRIVATE KEY section and then CERTIFICATE section.

    Also, in head, prefer-server-ciphers is now the default. It is an error to set it.

  32. Martin Zajíc says:

    Hi guys, it’s possible to configure ssl on each domain host??

    I have many domains some has SSL some have also websockets with ssl how can i configure HAproxy to server different certificates on each domain??

  33. The PROXY protocol looks quite promising. Any IETF RFC or community-driven adoption effort that started besides [great] specs published at ? A pointer would greatly help.

  34. Pingback: SSL Client certificate information in HTTP headers and logs | HAProxy Technologies – Aloha Load Balancer

  35. Pingback: SSL Client certificate management at application level | HAProxy Technologies – Aloha Load Balancer

  36. Pingback: Benchmarking SSL performance | HAProxy Technologies – Aloha Load Balancer

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s