Multiple Docker Containers on a Single Apache2 Host Using Reverse Proxy

Here’s a simple way to set up multiple Docker containers on a single host, with each container representing a unique domain, and each container protected with a LetsEncrypt SSL certificate. To achieve this we’ll meet the following requirments:

  • Host Ubuntu droplet with Apache manages SSL for three containers
  • Each container serves a separate application
  • Host Ubuntu Apache uses reverse proxy to serve each application

Host droplet VHOST configuration

The configuration in these examples (abc.com) is the same for all the domains:

abc.com.conf

<VirtualHost *:80>

        ServerName abc.com
        ServerAlias www.abc.ca
        ProxyPreserveHost On
        ProxyRequests Off
        ProxyPass / http://127.0.0.1:8080/
        ProxyPassReverse / http://127.0.0.1.1:8080/

</VirtualHost>

abc.com-le-ssl.conf

Note, you need mod_ssl and mod_proxy enabled in Apache for this to work.

Note, also, that the SSL certificates are all stored and managed on the Ubuntu host, not on the containers.

<IfModule mod_ssl.c>
<VirtualHost *:443>

        ServerName abc.com
        ServerAlias www.abc.com
        SSLProxyEngine On
        ProxyPreserveHost On
        ProxyRequests Off
        ProxyPass / http://127.0.0.1:8080/
        ProxyPassReverse / http://127.0.0.1:8080/

Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/abc.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/abc.com/privkey.pem

</VirtualHost>
</IfModule>

Container VHOST configuration

The configuration in this example (container #1, abc.com) is the same for all the containers:

Note, it is not necessary to set up SSL certs or SSL VHOST on the container.

000-default.conf

<VirtualHost *:80>

        ServerName localhost
        DocumentRoot /var/www/code/public

        <Directory /var/www/code/public>
                Options FollowSymLinks Indexes
                AllowOverride All
                Require all granted
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}.access.log combined

</VirtualHost>

Container docker-compose.yml configuration

The configuration in this example is the same for all the containers, with the exception of the forwarded port incrementing by one in each container. eg, 8080, 8081, 8082, etc:

services:
  httpd:
    image: "php:8.4.1-apache"
    restart: 'no'
    ports:
      - "8080:80"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - .:/var/www
      - ./config/sites-available:/etc/apache2/sites-available
      - ./config/php:/usr/local/etc
    build:
      context: .
      dockerfile: ./Dockerfile
networks:
  default:
    name: mysites

Conclusion

Obviously, this is a simplified setup in order to demonstrate the basic principles. This was quit easy to setup, once I figured it out. The host Ubuntu system was the cheapest droplet available on DigitalOcean, and it worked fine. The only software installed on it was apache2. The only ports open on the host firewall were 22, 80 and 443.