Pass-through SSL with HAProxy and vhosts on same IP

Ralf Viellieber asked:

Can i pass-through SSL with HAProxy to a vhost that shares ip with other vhosts?

I try

frontend https
bind *:443 #ssl
mode tcp
default_backend port_443

backend port_443
mode tcp
server web42

But i see the default webserver, not

I could do SNI on frontend, but how to say to backend – this is for domain

My answer:

You can pass connections to whatever backend server/port you want.

But I see there is a bunch of stuff missing from your setup.

So this is from my own HAProxy setup, with which I forward https connections that must share a global IPv4 address, to backend servers which all have unique global IPv6 (and unique private IPv4).

frontend https
    bind :443
    mode tcp
    option tcplog
    tcp-request inspect-delay 5s
    tcp-request content accept if { req.ssl_hello_type 1 }

    use_backend spearhead_example_com if { req_ssl_sni -i }
    use_backend goren_example_com if { req_ssl_sni -i }
    use_backend goren_example_com if { req_ssl_sni -i }
    use_backend goren_example_com if { req_ssl_sni -i }
    use_backend redmine_example_com if { req_ssl_sni -i }

backend spearhead_example_com
    server spearhead send-proxy-v2

backend goren_example_com
    server goren send-proxy-v2

backend redmine_example_com
    server redmine send-proxy-v2

Note that I am doing SNI inspection here, and matching on the SNI hostname to determine which backend to send the connection to.

Then I use send-proxy-v2 which enables the PROXY protocol on the backend connection. This will let me tell the backend the IP address where the connection originated. We use this protocol because X-Forwarded-For is not possible in this setup.

But the PROXY protocol does require the backend server to be aware of it. To make that happen required a small change in my nginx setup, to wit:

listen 443 ssl http2 proxy_protocol;
listen [::]:443 ssl http2;
real_ip_header proxy_protocol;

By specifying proxy_protocol in listen and real_ip_header, nginx now knows to get the real IP address of the client via PROXY protocol. (And notice that I do not use it on the IPv6 listener, because I only proxy IPv4 connections via haproxy. IPv6 connections come in directly, and a proxy is not required. This is one big advantage of IPv6.)

Finally, older versions of nginx spoke version 1 of the PROXY protocol, so if send-proxy-v2 in haproxy.cfg doesn’t work, you’ll need to change it to send-proxy.

View the full question and any other answers on Server Fault.

Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.