Nginx and Let’s Encrypt with Docker in Less Than 5 Minutes

Getting Nginx to run with Let’s Encrypt in a docker-compose environment is trickier than you’d think …

Quick Reminder: What is docker-compose?

docker-compose is a tool for defining containers and running them. It’s a great choice when you have multiple interdependent containers but you don’t need a full-blown container cluster like Kubernetes.

With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration

This guide requires docker-compose. If you don’t have it yet, take a look at the installation instructions and get it.
Hint: If you’re installing docker-compose on CoreOS, it needs to go into /opt/bin instead of /usr/local/bin.

The Setup

Official images of nginx and an automated build of certbot, the EFF’s tool for obtaining Let’s Encrypt certificates, are available in the Docker library.

version: '3'
services:
nginx:
image: nginx:1.15-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./data/nginx:/etc/nginx/conf.d
certbot:
image: certbot/certbot
server {
listen 80;
server_name example.org;
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name example.org;

location / {
proxy_pass http://example.org; #for demo purposes
}
}

Linking up nginx and certbot

Let’s Encrypt performs domain validation by requesting a well-known URL from a domain. If it receives a certain response (the “challenge”), the domain is considered validated. This is similar to how Google Search Console establishes ownership of a website. The response data is provided by certbot, so we need a way for the nginx container to serve files from certbot.

- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

The Chicken or the Egg?

Now for the tricky part. We need nginx to perform the Let’s Encrypt validation But nginx won’t start if the certificates are missing.

curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh > init-letsencrypt.sh

Automatic Certificate Renewal

Last but not least, we need to make sure our certificate is renewed when it’s about to expire. The certbot image doesn’t do that automatically but we can change that!

entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

Docker-compose Me Up!

Everything is in place now. The initial certificates have been obtained and our containers are ready to launch. Simply run docker-compose up and enjoy your HTTPS-secured website or app.

Are you interested in best practices for application deployment? Make sure to subscribe to my newsletter!

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Philipp

I make software. Passionate about Elixir. User of C++, Ruby & JavaScript. Current project: https://www.dblsqd.com