Routing HTTPS Traffic to Docker Containers with Different Web Servers on One Machine
How to Setup Nginx Reverse Proxy for Routing Incoming Traffic to Different Containers and Certbot for Auto-Renewing SSL Certificates
For small applications or test environments where separate machines for different web servers are cost prohibitive, one option is to have different servers run on the same machine in different Docker containers. Docker doesn’t support exposing the same port to multiple containers simultaneously (source). Still, we can install Nginx on the host machine and have it conditionally route the requests to the different containers.
The problem
After exposing port 80 to one container, if we try to have that port exposed to another container, we get the following error:
The solution: Reverse Proxy
In this example, we want to have one container to serve a Flask application for flaskapp.example.com and another container to serve a Node.js application for nodeapp.example.com; both from port 80 of the same machine.
We will set up a reverse proxy that routes the request for hosts to different containers:
1. Install Docker
There are plenty of tutorials out there for installing Docker, such as this one. This article will focus on the routing part.
2. Install Nginx on the host machine
Again, there are plenty of other good tutorials on this. Here is one. (You can also install Nginx in a separate container.)
3. Point your domains to the server
For our example, we would setup A records for flaskapp and nodeapp that point to the IP of the server in the DNS records of example.com.
4. Run the Docker containers with the web servers you need, but on ports other than 80 and 443
Say we have two Docker images already built or pulled: flaskApp and nodeApp. We can expose port 8080 for flaskApp and port 8081 for nodeApp:
At this point, you should be able to see your applications served at flaskapp.example.com:8080 and nodeapp.example.com:8081.
5. Configure Nginx reverse proxy
To serve both these apps on port 80, we will set up server blocks in the host machine.
Create the server block for flaskapp.example.com:
Paste the following in this file:
server {
listen 80;
server_name flaskapp.example.com; location / {
proxy_pass http://localhost:8080;
}
}
Create the server block for nodeapp.example.com:
Paste the following in this file:
server {
listen 80;
server_name nodeapp.example.com;
location / {
proxy_pass http://localhost:8080;
}
}
Create symlinks in the sites-enabled directory:
Ensure that the configuration we did is valid:
Restart Nginx:
6. Setup automatically renewing SSL certificates with Certbot
Install Certbot and its Nginx plugin.
Then generate certificates for your websites.
Now, if you look at the server blocks we’ve set up, you will see the new lines added for the SSL configuration automatically.
Of course, “-d www.flaskapp.example.com” is not necessary if you are not using the www version for the subdomain. After following the prompts, you will see a success message as below.
Requesting a certificate for flaskapp.example.comSuccessfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/flaskapp.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/flaskapp.example.com/privkey.pem
This certificate expires on 2022-10-25.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.Deploying certificate
Successfully deployed certificate for test4.cansin.net to /etc/nginx/sites-enabled/flaskapp.example.com
Congratulations! You have successfully enabled HTTPS on https://flaskapp.example.com
You can list your certificates with:
$ certbot certificates
… and delete them with:
$ sudo certbot delete --cert-name flaskapp.example.com
.. and delete the server blocks for that site:
$ sudo rm /etc/nginx/sites-enabled/flaskapp.example.com
$ sudo rm /etc/nginx/sites-available/flaskapp.example.com
Further reading:
- We’ve set this up in the host machine because it is not recommended to install Certbot inside the containers, as you can read more about it here.
- This article covers various methods of exposing multiple containers on the same port.
- The accepted answer to this question covers the same method described here.
- This page on Nginx website describes setting up certbot-nginx.