Christoph Lechner, 2026-Jan-21
Configuration of Apache2 to perform SSL termination for traffic going to another container. This was originally developed for a project requiring SSL termination for "streamlit". Therefore, two protocols are supported when connecting to the remote server: HTTP and WS.
Two versions of the image can be built:
apache2-revproxy: image contains neither SSL keys nor certs (they need to be provided in a directory mapped to path/ssl/). This is what most people want.apache2-revproxy-with-keys: image contains SSL key and certs (key is protected by passphrase to be provided as secret at run time)
For a quick demo, a configuration is available.
The file reverse-proxy.htpasswd in the repository contains an entry for user demo and password abc.
If you want to set your own passwords, you need the htpasswd utility. If you don't have it on your machine, install it using (here as example for Ubuntu Linux):
sudo apt-get install apache2-utils
Create a new password file with credentials for Apache2 user authentication (note that the "-c" switch truncates already existing files):
htpasswd -c reverse-proxy.htpasswd demo
New password:
Re-type new password:
Adding password for user demo
Then build the Docker image
sudo docker build -t apache2-revproxy:latest .
This image does not contain SSL keys or certificates. In the next step, we generate an image based on this image containing SSL keys and certificates.
Enter the directory docker_img_with_SSLkeys.
First, we create the file with the passphrase for the SSL key:
$ umask 0077
$ your_favorite_editor ssl.pwd
To create the self-signed certificates and key material for SSL operation (the CN field is the hostname we enter in the browser to access the demo server):
openssl req -new -newkey rsa:2048 -passout file:../ssl.pwd -subj "/CN=demo.localnet/" -keyout ssl.key -out ssl.csr
openssl x509 -req -days 365 -in ssl.csr -passin file:../ssl.pwd -signkey ssl.key -out ssl.crt
Note that this self-signed SSL key material is only for demo purposes. The private key is decrypted as Apache2 initializes using the passphrase passed to the container in a secret environment variable.
In the subdirectory docker_img_with_SSLkeys, run:
sudo docker build -t apache2-revproxy-with-keys:latest .
Now, let us test the Docker image. Remember that the following test must not be carried out with production keys and key passphrases as command line arguments are visible to other users on the system. In the actual deployment, the passphrase will loaded from a dedicated secrets storage.
sudo docker run --rm -it -p 8443:443 -e A2_PASSPHRASE=passw0rd -e A2_PROXYREMOTE=mystreamlit:8501 apache2-revproxy-with-keys:latest
Note that the container immediately exists if the passphrase provided in environment variable A2_PASSPHRASE is incorrect (try it!).
Point your web browser to https://localhost:8443/ (or whatever port you've configured). You should get a warning related to self-signed certificates (as expected). After accepting the risk, enter the credentials configured above using htpasswd.
Finally, you should see an error message generated by the Apache2 reverse proxy as it cannot resolve the hostname mystreamlit. The correct hostname and port for your set up is to be passed to the container using the A2_PROXYREMOTE environment variable in the format <host>:<port> (i.e. without http://).
In the doc/ directory, there is a Docker compose demonstration setup with nginx.
After bringing it up using docker compose up, the result looks like this:


