This post will describe how to expose multiple docker containers running websites on port 80 using HAproxy as a reverse proxy. This makes it possible to run multiple websites on different domains on a single public ip of the host.

The basic setup is to create 1 container for haproxy which is exposed to the host on port 80. This HAproxy container will forward the incoming HTTP request to the correct container based on the domain name.

Reverse haproxy docker diagram
Picture drawn with

First launch the containers which run different websites. In our example we will use a hello-world php demo container and a wordpress site container.

$ # Run hello world php demo container (
$ docker run -d tutum/hello-world
$ docker inspect -f "{{.NetworkSettings.IPAddress}}" 01ec10276761

$ # Run wordpress container (
$ docker run -d tutum/wordpress
$ docker inspect -f "{{.NetworkSettings.IPAddress}}" 4d23f10f6b35

Now we need to create our haproxy configuration to configure HAproxy as reverse proxy for our docker containers. Because HAProxy is also running inside a container we need to be able to access the hello-world and wordpress container by their private ip accessible from all containers. We got this IP using the command: docker inspect -f "{{.NetworkSettings.IPAddress}}" $CONTAINERID. Make sure to note down these IPs as they will be used in the haproxy.cfg file.

$ # On the host(not container) create directory containing our haproxy config file
$ mkdir ~/haproxy-config

$ # Create ~/haproxy-config/haproxy.cfg
$ vim ~/haproxy-config/haproxy.cfg
        log   local0
        log   local1 notice
        user haproxy
        group haproxy
        # daemon

        log     global
        mode    http
        option  httplog
        option  dontlognull
        option forwardfor
        option http-server-close
        contimeout 5000
        clitimeout 50000
        srvtimeout 50000
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http
        stats enable
        stats auth username:password
        stats uri /haproxyStats

frontend http-in
        bind *:80

        # Define hosts based on domain names
        acl host_test1 hdr(host) -i
        acl host_test2 hdr(host) -i

        ## figure out backend to use based on domainname
        use_backend test1 if host_test1
        use_backend test2 if host_test2

backend test1 # container
    balance roundrobin
    option httpclose
    option forwardfor
    server s2 # This ip should be the ip of hello-world container

backend test2 # container
    balance roundrobin
    option httpclose
    option forwardfor
    server s1 # This ip should be ip of wordpress container

$ # Run haproxy and map the host directory ~/haproxy-config to /haproxy-override of the container
$ # See the image README and Dockerfile for info about this override behaviour.
$ # HAProxy is exposed on port 80 because all requests to the public ip should
$ # go to the HAProxy container.
$ docker run -d -p 80:80 -v ~/haproxy-config:/haproxy-override dockerfile/haproxy

The HAProxy configuration could be automated possibly with the use of etcd to store information about services or use a similar method to Automated nginx reverse proxy for docker. The automated nginx reverse proxy didn't work for me though.

Thanks to HAProxy as static reverse proxy for docker containers for the haproxy config file. Although I think it's better to run HAproxy in a container.


comments powered by Disqus