Nginx – Issue with SSL using HAProxy and Nginx

haproxynginxssl

I'm building a highly available site using a multiple HAProxy load balancers, Nginx web serves, and MySQL servers. The site needs to be able to survive load balancer or web servers nodes going offline without any interruption of service to visitors. Currently, I have two boxes running HAProxy sharing a virtual IP using keepalived, which forward to two web servers running Nginx, which then tie into two MySQL boxes using MySQL replication and sharing a virtual IP using heartbeat. Everything is working correctly except for SSL traffic over HAProxy. I'm running version 1.5 dev12 with openssl support compiled in. When I try to navigate to the virtual IP for haproxy over https, I get the message: The plain HTTP request was sent to HTTPS port. Here's my haproxy.cfg so far, which was mainly assembled from other posts:

global
        log 127.0.0.1 local0
        log 127.0.0.1 local1 notice
        # log 127.0.0.1 local0
        user haproxy
        group haproxy
        daemon
        maxconn 20000

defaults
        log global
        option dontlognull
        balance leastconn
        clitimeout 60000
        srvtimeout 60000
        contimeout 5000
        retries 3
        option redispatch

listen front
        bind :80
        bind :443 ssl crt /etc/pki/tls/certs/cert.pem
        mode http
        option http-server-close
        option forwardfor
        reqadd X-Forwarded-Proto:\ https if { is_ssl }
        reqadd X-Proto:\ SSL if { is_ssl }
        server web01 192.168.25.34 check inter 1s
        server web02 192.168.25.32 check inter 1s
        stats enable
        stats uri /stats
        stats realm HAProxy\ Statistics
        stats auth admin:*********

Any idea why SSL traffic isn't being passed correctly? Also, any other changes you would recommend? I still need to configure logging, so don't worry about that section. Thanks in advance your help.

Best Answer

With ssl, you have to use frontend/backend, not listen. The reason is that with listen, a connection coming in to haproxy on one port goes to the server behind on that same port. So an SSL request on 443 gets decrypted by haproxy, but then sent on to the web server on port 443, which is expecting an SSL connection. (And that is how you get that error.) With frontend/backend, you get to tell haproxy to accept connections on one port on the frontend, but to complete the connection to a different port in the backend.

Alternatively, you could reconfigure your web server to accept http requests (not https requests) on port 443. Personally, I would don't that because that is pretty non-standard, whereas you would expect a load balancer doing SSL offload to accept a connection on 443 and complete it on port 80.