Let's Encrypt TLS Certificates via Docker and Certbot

This tutorial outlines the steps necessary to obtain free Let's Encrypt certificates for TLS/SSL in a containerized infrastructure based on Docker. LE certificates are free of charge or any other cost.

Assumptions

This tutorial assumes that you have:

  • a public domain such as e.g. exampledomain1.com for which you want to use HTTPS (TLS/SSL) based on certificates signed by the Let's Encrypt Authority
  • a containerized infrastructure based on Docker

This tutorial also assumes that you would like to have:

This tutorial finally assumes that you would not like to have:

  • Docker host mounts in your internet-facing containers (such as load balancers or WAFs)

How-to

Create a volume:
sudo docker volume create --name le_vol

Create an nginx web server for the acme-challenge requests and mount the volume:
sudo docker run -itd -v /le_vol:/usr/share/nginx/html/le --net=<frontend_network_name> --ip=<frontend_container_ip> --name le_webserver nginx:stable

Connect to the container:
sudo docker exec -it le_webserver /bin/bash
Make the directory for the acme-challenge test files:
mkdir -p /usr/share/nginx/html/le/.well-known/acme-challenge
Edit the nginx configuration accordingly (also from within the container, e.g. via nano which you will need to install):
nano /etc/nginx/conf.d/default.conf
Add the following within a server{} directive and save it:
server { <...> location /.well-known/acme-challenge/ { root /usr/share/nginx/html/le/; default_type "text/plain"; allow all; } <...> }
Exit the container:
exit
Then restart it:
sudo docker restart le_webserver

Make sure that all load balancers, WAFs or other internet-facing containers (concerned with LE certificates) are correctly configured to process acme requests upstream to the above created le_webserver container. An example nginx upstream proxy directive might look like this:
server { <...> location /.well-known/acme-challenge/ { proxy_pass http://<frontend_le_webserver_ip>:80; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; } <...> }

Then finally run the certbot container itself:
sudo docker run -it --rm --name le_certbot \ -v /etc/letsencrypt:/etc/letsencrypt \ -v /var/lib/letsencrypt:/var/lib/letsencrypt \ --volumes-from le_webserver \ deliverous/certbot \ certonly --webroot -w /usr/share/nginx/html/le

Follow the instructions according to your needs. You can e.g. request one certificate for a domain and several subdomains/protocols by entering a comma-separated list when prompted for your domains:
exampledomain1.com,www.exampledomain1.com,subdomain1.exampledomain1.com,www.subdomain1.exampledomain1.com

If everything went well your shell screen will print several lines of log entries and "Congratulations! Your certificate and chain have been saved ..." followed by the path where your certificate has been saved. The directory should be /etc/letsencrypt/ (also on the docker host - thanks to docker host mount).

Further Information

https://letsencrypt.org
https://hub.docker.com/r/deliverous/certbot
https://hub.docker.com/r/deliverous/certbot/~/dockerfile
https://github.com/certbot/certbot