Docker Multiple websites/domains on single ip/host tutorial using a HAproxy as reverse proxy
Mon 07 July 2014 | Last updated on Tue 06 December 2022This 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.
Picture drawn with draw.io.
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 (test1.domain.com)
$ docker run -d tutum/hello-world
01ec10276761
$ docker inspect -f "{{.NetworkSettings.IPAddress}}" 01ec10276761
172.17.0.26
$ # Run wordpress container (test2.domain.com)
$ docker run -d tutum/wordpress
4d23f10f6b35
$ docker inspect -f "{{.NetworkSettings.IPAddress}}" 4d23f10f6b35
172.17.0.25
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
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
user haproxy
group haproxy
# daemon
defaults
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 test1.domain.com
acl host_test2 hdr(host) -i test2.domain.com
## figure out backend to use based on domainname
use_backend test1 if host_test1
use_backend test2 if host_test2
backend test1 # test1.domain.com container
balance roundrobin
option httpclose
option forwardfor
server s2 172.17.0.26:80 # This ip should be the ip of hello-world container
backend test2 # test2.domain.com container
balance roundrobin
option httpclose
option forwardfor
server s1 172.17.0.26:80 # 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.