Host Multiple Websites on Docker Containers

Docker is an extremely useful platform that enables developers to easily develop and deploy applications. In this article, we’ll look at how to use Docker containers to host multiple websites on a single server. One of the most significant benefits of using Docker containers is that they are lightweight, faster, and easier to manage.

This month, I moved two of my custom-built applications from two separate servers to a single server, each in its own Docker container. It’s easier to manage both applications, and it’s also reduced my production costs.

Each application is set up inside its own secure environment and accessible through a domain name. Before we move to the instructions, let us briefly discuss how it’ll work and what tools we’ll require to set everything up. So let’s start.

What do we want to setup?

We want to use Docker containers to set up a single server that can serve multiple applications or websites. When a user requests a URL for one of the hosted websites, the main server should proxy the request to the container, which should then serve the content.

We will need to set up a server to accomplish this. I’ve set up a server with a static IP address for this article. Check out MassiveGRID, DigitalOcean, or Vultr if you’re looking for a good cloud hosting service.

Second, we’ll create a proxy to route user requests to their appropriate containers. There are many tools available for this purpose, but I’ll use nginx-proxy because it’s extremely simple to set up and has almost all of the features we require. Finally, we’ll use Cloudflare as a DNS manager to point the domain name to the host server (IP address).

Once your server is up and running, ssh into the server and update it.

ssh username@ip-address

If you have setup ssh key to login, please use -i option in the ssh command to log in with the private ssh key.

ssh -i path-to-ssh-key username@ip-address

Prepare the server

On the host machine, I’m running Ubuntu 20.04. The instructions will be the same whether you’re using Debian or another debian-based distribution. For any other distribution, the only instructions for configuring docker will differ, and everything else will remain the same. Please follow this guide to install Docker on Ubuntu.

Using SSL certificate with nginx-proxy

The second step is to create a directory that will store the SSL certificates and keys for each domain. On the host server, create a directory in /etc/ directory. You can name this directory whatever you like. For this article, I am naming it cloudflare.

mkdir /etc/cloudflare

Later on, we will bind this directory with nginx-proxy to access SSL certificates and keys for each domain name.

Create docker network

We will also create a virtual network to which every docker container, including nginx-proxy, will connect.

docker network create nginx-proxy

Setup nginx-proxy

If we want, we can create a proxy to deal with such situations. Thankfully, nginx developers have built an entire Docker image that will keep track of all the containers and update as soon as any new container is created. To create nginx-proxy docker (with ssl in mind), please run the following command –

docker run -d –name nginx-proxy -p 80:80 -p 443:443 –net nginx-proxy -v /etc/cloudflare:/etc/nginx/certs -v /var/run/docker.sock:/tmp/docker.sock:ro nginxproxy/nginx-proxy

Let us break down the above command step by step.

  • run – This option will create the container.
  • -d – It enables debug mode. In case anything goes wrong, it will output the useful information to hunt down the issue.
  • –name – The name of the container.
  • -p 80:80 – It’s extremely important. The -p parameter binds the host port with the container port. On the left side of 80:80 is the host port and vice-versa.
  • –net – Connects newly created container with the nginx-proxy network.
  • -v /etc/cloudflare:/etc/nginx/certs – Necessary if you are going to use SSL on your websites. Binding the host directory with the nginx-proxy container’s directory where it stores the SSL certificates and keys.
  • -v /var/run/docker.sock:/tmp/docker.sock:ro – Attaching docker socket with the container to communicate with the docker daemon.
  • nginxproxy/nginx-proxy – The address of the nginx-proxy docker image hosted on hub.docker.com.

We’ve solved the game’s biggest puzzle once you’ve created the nginx-proxy container. It was very simple. Right? It’s all thanks to the nginx-proxy image; otherwise, we’d have to do everything manually.

Create container with VIRTUAL_HOST environment variable

The environment variable VIRTUAL HOST is used by nginx-proxy to determine which domain should be pointed to which server. Each time you create a new container, set the value of the VIRTUAL HOST variable to the domain name you want to point to this container.

docker run -it -d --name gaminggroup.online -h gaminggroup.online --expose 80 --net nginx-proxy -e VIRTUAL_HOST=gaminggroup.online -e VIRTUAL_HOST=www.gaminggroup.online httpd

Let us break down the above command step-by-step.

  • -h – sets the fully qualified domain name (set the domain name)
  • –expose – Exposes the port 80 to allow HTTP traffic
  • –net – Connect the newly created container to nginx-proxy network
  • VIRTUAL_HOST=domain.xyz – VIRTUAL_HOST variable is used by nginx-proxy to redirect users’ requests to their respective containers
  • httpd – Pull Apache server image from the docker hub

The command above will start the container with the popular web server Apache. Any request that reaches the host server is redirected to the nginx-proxy, which then forwards it to this container’s port 80.

Point domain to the server

Finally, configure the domain name to point to the host server. Create an A record with the name ‘@’ and IPv4 as the host server’s IP address. Wait for a while after you’ve finished. DNS propagation can take anywhere from a few minutes to several hours.

Once DNS propagation is completed, your domain name will point to the newly created container that hosts Apache web server. Now everything is setup. All you need to do is keep creating containers with VIRTUAL_HOST variable and nginx-proxy will properly redirect traffic to the container.

Using SSL/HTTPS within Docker

Because most of us prefer to serve content over HTTPS rather than insecure HTTP, nginx-proxy can easily handle it. We already passed the -v parameter with the directory /etc/cloudflare when we set up the nginx-proxy container. This directory is associated with the nginx-proxy directory /etc/nginx/certs.

Each SSL certificate and key must be stored in /etc/cloudflare with the proper name. The SSL certificates and keys should be renamed according to the domain name they are for. For instance, for the domain name, example.com, the SSL certificate must be renamed as example.com.crt and the key must be example.com.key.

Conclusion

The use of nginx-proxy has greatly simplified the process. Simply deploy a container that handles everything else. After this is done, you can deploy as many containers as you want without having to worry about too many configuration files. Containers are lightweight, but as traffic/workload increases, more resources will be required.

If you have had any difficulty following the above steps, let me know in the command section below or join our Discord server for quick help.

SHARE THIS POST

MassiveGRID Banner
4 Comments Text
  • Multiple SSL certificates in the same folder wont work 🙁 only one. Server only reads one by default. Can you help me get this right?

      • Thanks! Also, for anyone wlse having a problem with their domains redirection I updated the compose command for my apps to:

        docker run -d –name APPNAME -h APPDOMAIN –expose 80 –net nginx-proxy -v /opt/web-server/dani3/:/usr/local/apache2/htdocs/ -e VIRTUAL_HOST=APPNAME.com,www.APPNAME.com httpd

        using the comma instead of two separate uses of flag -e VIRTUAL_HOST

  • Hello!
    Good tutorial.
    Missed putting example in “Point domain to the server” and “Using SSL/HTTPS within Docker”. Without showing examples it is confusing for beginners.

  • Leave a Reply

    Your email address will not be published. Required fields are marked *