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 www.example.com

But i see the default webserver, not www.example.com

I could do SNI on frontend, but how to say to backend – this is for domain www.example.com?

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 spearhead.example.com }
    use_backend goren_example_com if { req_ssl_sni -i awx.ioerror.us }
    use_backend goren_example_com if { req_ssl_sni -i goren.example.com }
    use_backend goren_example_com if { req_ssl_sni -i tower.example.com }
    use_backend redmine_example_com if { req_ssl_sni -i redmine.example.com }

backend spearhead_example_com
    server spearhead 192.168.101.64:443 send-proxy-v2

backend goren_example_com
    server goren 192.168.101.182:443 send-proxy-v2

backend redmine_example_com
    server redmine 192.168.101.241:443 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;
set_real_ip_from 192.168.101.1;
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.