Docker Apache Proxy Setup

Written by Kevin Gimbel on , 🍿 5 min. read

In this post I'd like to detail how I am managing docker containers behind an apache2 proxy on a Ubuntu 18.04. server. I'm using one Apache server to route traffic from multiple sub-domains to docker containers all running with docker-compose. This setup is not automated and the containers do not need to interact with each other; It's just how I run software for my private usage.


Let's start with an overview image, because this can be quite confusing.

A diagram showing how traffic comes through Apache and is routed to different docker containers exposing services on different TCP ports
A diagram showing how traffic comes through Apache and is routed to different docker containers exposing services on different TCP ports

The diagram shows how traffic comes from the public internet and hits Apache. This happens for example when you type into your browser and hit enter. Apache then decides which service running should respond to the request, in most scenarios this will be some PHP code (like WordPress). When we want to use NodeJS or run software from docker we usually do not bind to port 80 (HTTP) or 443 (HTTPS) directly. Instead we need to proxy the request.

In order to make our services accessible without knowing the ports of each container we'll setup a virtual host in Apache.

The goal is:

  • Access each service through a nice domain (like instead of
  • Have SSL for every service
  • Get new certificates automatically

Starting services with docker-compose

We'll start with the docker service. As an example I'm using one of my projects, fakedata_server.

The docker compose file looks like this

version: "3"

image: kevingimbel/fakedata_server:latest
- 8085:8000
restart: unless-stopped

We can place this in some directory, I'm usually using $HOME/app-name, so for example /home/myuser/fakedata-server/docker-compose.yml. Then we can run docker-compose up -d. The service will now run and restart forever until it is stopped.

If we use curl we can reach the service.

$ curl -vL localhost:8085
curl -vL localhost:8085
* Rebuilt URL to: localhost:8085/
* Trying
* Connected to localhost ( port 8085 (#0)
> GET / HTTP/1.1
> Host: localhost:8085
> User-Agent: curl/7.58.0
> Accept: */*
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Server: Rocket
< Content-Length: 515
< Date: Tue, 05 May 2020 09:35:45 GMT

Welcome to the fakedata_generator example implementation as a web server

Available routes:



Specify input as comma-seperated strings, e.g.

Specify a corpora dataset, e.g.

* Connection #0 to host localhost left intact
$ curl localhost:8085/gen/email

The service is working. Yay! Off to the next topic!

Proxying with apache2

Now that we have a service running we want to make it accessible with a nice clean URL. We'll use for this purpose, because that's where the service is actually running:

First we need to create some apache files:

  • Virtual Host in /etc/apache2/sites-available/fakedata-server.conf
  • Generic Domain config in /etc/apache2/sites-available/domains.conf

Virtual Host

The virtual host only contains proxy commands and redirects. We want to redirect all HTTP traffic to HTTPS and all HTTPS traffic should be proxied to the port out service is running on (8085 in the example above).

The first part of the config is the redirect. Important here is the ServerName! This tells apache for which sub-domain this virtual host should be routed to!

<VirtualHost *:80>
Redirect permanent /

The next part is the SSL/HTTPS handler. After the redirect this handler will do the proxying.

  • ServerName tells apache which virtual host to use (if we have multiple)

  • SSLEngine On turns on SSL encryption

This is all that is needed in the virtual host for the auto-ssl feature! The rest of the config will be handled in the domains.conf as described below.

  • ProxyPreserveHost On passes on the Host header from the request (see documentation)

  • ProxyPass / - this tells apache to sent the traffic to port 8085 on localhost ( is always the IP of the local server)

  • ProxyPassReverse /

The last two lines just give some extra logs, it's always good to have them in case something doesn't work or if a tool like fail2ban should be used.

  • ErrorLog ${APACHE_LOG_DIR}/
  • CustomLog ${APACHE_LOG_DIR}/ combined
<VirtualHost *:443>

SSLEngine On

ProxyPreserveHost On

ProxyPass /
ProxyPassReverse /

CustomLog ${APACHE_LOG_DIR}/ combined

You can view the full apache2 configuration below.

Click to view file /etc/apache2/sites-available/fakedata-server.conf
<VirtualHost *:80>
	Redirect permanent /

<VirtualHost *:443> ServerName

SSLEngine On

ProxyPreserveHost On

ProxyPass /
ProxyPassReverse /

CustomLog ${APACHE_LOG_DIR}/ combined


The domains.conf is our SSL config. We will add all sub-domains we want to have covered by our SSL certificate to this configuration. The details on how to enable mod_md for automatic SSL certs with apache2 are written below, the config file looks like this:

MDCertificateAgreement accepted

<VirtualHost _default_:*>
DocumentRoot "/var/www/html/"

The above config will generate a SSL certificate valid for the domains:


I've written about Auto-SSL with Apache2 in the past and I'm using this feature for my docker containers, too. This way I can have free SSL certificates without the need to manage anything manually.

The Server must run Apache 2.4.30 or newer in order to use the Auto-SSL feature. Instructions on how to upgrade can be found in my article on Apache2 and Auto-SSL.

Once everything is setup we need to enable the configs.

$ sudo a2ensite fakedata-server.conf domains.conf

and then restart the apache2 server.

$ sudo systemctl restart apache2

It appears that apache needs to be restarted not just reloaded when a new subdomain is added to the certificate!

Now you should be able to access the docker container on a subdomain. For example,

Hi, I'm Kevin!

I'm a DevOps Engineer with a passion for on automation and monitoring. Before shifting into DevOps and cloud computing I worked as Front-End Developer, which is still a hobby and field of interest for me.

Picture of Kevin Gimbel, in a tiny mirror

I'm very passionated about a variety of games - digital, boardgames, and pen & paper; and also interested in Sci-Fi, Cyberpunk, and dystopian books. You can find out more on the about page.