Adam O'Grady

HAProxy: HTTP And HTTPS For Multiple Domains And Backends

If you’ve got a single ingress IP, perhaps a NAT situation with various services behind a router on a private network, and you want to route different domains to different backends, you can do it with HAProxy. If you want to use HTTP and HTTPS without using SSL termination on the HAProxy host that’s possible too and what we’ll explore here.

What you will need is:

  • One host with HAProxy, with all TCP traffic on ports 80 and 443 being routed to it.
  • Multiple backend services on your private network.

On the HAProxy server we’ll need to edit the config file, this is often /etc/haproxy/haproxy.cfg on *nix machines.

You can usually leave the global and defaults section as they start, or make sane adjustments as required. What matters next is the latter sections, which we’ll describe after displaying:

frontend http_frontend
    mode http
    option httplog
    bind *:80       
    option forwardfor
    acl host_www hdr(host) -i example.com
    acl host_www hdr(host) -i www.example.com
    acl host_wiki hdr(host) -i wiki.example.com

    use_backend http_www if host_www
    use_backend http_wiki if host_wiki

backend http_www
    mode http
    option httplog
    option forwardfor
    server www 192.168.1.10:80

backend http_wiki
    mode http
    option httplog
    option forwardfor
    server wiki 192.168.1.12:80

frontend https_frontend
    mode tcp
    option tcplog
    bind *:443
    acl tls req.ssl_hello_type 1
    tcp-request inspect-delay 5s
    tcp-request content accept if tls
    
    acl host_www req.ssl_sni -i example.com
    acl host_www req.ssl_sni -i www.example.com
    acl host_wiki req.ssl_sni -i wiki.example.com

    use_backend https_www if host_www
    use_backend https_wiki if host_wiki

backend https_www
    mode tcp
    option tcplog
    option ssl-hello-chk
    server www 192.168.1.10:443

backend https_wiki
    mode tcp
    option tcplog
    option ssl-hello-chk
    server wiki 192.168.1.12:443

Let’s start by inspecting the HTTP section, the first half. In our frontend block, which we label http_frontne for descriptive purposes, we set the mode, bind the port, and set options. The major part comes next though:

    acl host_www hdr(host) -i example.com
    acl host_www hdr(host) -i www.example.com
    acl host_wiki hdr(host) -i wiki.example.com

Here we set up what domains in the HTTP request will route to what host, with the next two lines providing the backends in the config for each HTTP host:

    use_backend http_www if host_www
    use_backend http_wiki if host_wiki

The backend section is pretty similar, we’re using descriptive names, setting modes and options, and then telling it which IP address to go to (using a descriptive server name as well):

backend http_www
    mode http
    option httplog
    option forwardfor
    server www 192.168.1.10:80

We do similar for the HTTPS, the main different is we’re forwarding at the TCP level, but doing some health-checks and testing the server name indication (SNI) to work out which domain was requested and which host to route it too.

This should get you all up and running but don’t forget to restart the HAProxy service after you’ve changed the configuration. That always gets me.