Let's Automate Let's Encrypt

Don't sweat the permissions for this directory; the certificates themselves will not be publicly accessible. Now you need to make a small change in your nginx configuration. Create a new file /etc/nginx/letsencrypt.inc with the following contents:

location ^~ /.well-known/acme-challenge/ {
    root /tmp/letsencrypt/www;

Then find your "server" section in the nginx configuration, and add the following line to each Web site you host:

include /etc/nginx/letsencrypt.inc;

So the final result will look like this:

server {
    listen 80;
    server_name example.com www.example.com;
        include /etc/nginx/letsencrypt.inc;

After saving both files, ask nginx to reload the configuration:

sudo /usr/sbin/nginx -t && sudo service nginx reload

Notice that you are only reloading the nginx configuration—and nginx knows very well how to do it without dropping connections.

Now, let's go get some certificates! Needless to say, all domain names for which you are going to issue certificates should resolve to your server IP address; otherwise, it would be possible to issue certificates for somebody else's domain and use those certificates for man-in-the-middle attacks.

The following will pull and start a new Docker image with the official Let's Encrypt client:

mkdir -p /tmp/letsencrypt/www

# make sure you have the latest version of this image,
# and not some pre-beta - those used to be notoriously buggy
docker pull quay.io/letsencrypt/letsencrypt:latest

docker run --rm -it --name letsencrypt \
-v /etc/letsencrypt:/etc/letsencrypt \                                                       
-v /tmp/letsencrypt/www:/var/www \
    quay.io/letsencrypt/letsencrypt:latest \
    auth --authenticator webroot \
    --webroot-path /var/www \
    --domain=example.com --domain=www.example.com \

As you can see, you share two data volumes between the host and the container:

  • /etc/letsencrypt for storing Let's Encrypt configuration, all certificates and chains.

  • /tmp/letsencrypt/www for communication between your server with Let's Encrypt servers.

The webroot plugin that runs inside the container will create a temporary challenge file for each of your domains, then Let's Encrypt validation servers will send an HTTP request to ensure that you are really controlling this domain and this server. These files are temporary and needed only during issuing or renewing a certificate.

You will need to agree on TOS by pressing a button, and after several seconds, your certificate is ready. If you have several subdomains, as in this example, you can enumerate all of them, which will result in one shared certificate issued for all of these subdomains. However, if you have several domains, it would be much more convenient to have a separate certificate for each of them—just repeat this last docker run ... command for each domain you have (and thank me later if someday you decide to move one of your domains to a different server).

As you can see, the procedure for obtaining certificates is painless and safe. Almost all the heavy work is done for you behind the scenes, and if you've ever had to deal with certificates using some other traditional certification authority, you will know exactly what I mean. Whatever runs inside the container can access only two directories on the server, and only while it runs.


Andrei Lukovenko is a longtime Linux user, command-line fanboy, automation aficionado.