How to use free LetsEncrypt SSL certificates with Docker and jwilder/nginx-proxy
In my last post, I talked a little bit about the magical ease-of-use that comes from Jason Wilder's nginx-proxy Docker container, which I use to route subdomains on sequentialread.com.
Well, today I finally got around to enabling HTTPS for the site using letsencrypt. letsencrypt is a really cool initiative to make trusted SSL certificates available for free. And not just free as in free beer, but free as in Libre as well.
I was shocked at how easy the process was. Here's exactly how it went down. First, I followed the instructions from the getting started page on letsencrypt.
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto --help
Then I decided I would use the certonly
method and --standalone
option because my web server configuration was complicated, and their plugins, for example for apache running on bare metal, didn't apply to my situation.
So I temporarily stopped my http server and crafted a long command line including each of my public subdomains:
./letsencrypt-auto certonly --standalone -d sequentialread.com -d git.sequentialread.com -d comments.sequentialread.com -d www.sequentialread.com -d www.git.sequentialread.com -d www.comments.sequentialread.com
At first, the tool failed: It explained that the letsencrypt server was unable to reach sequentialread.com on port 443. At first I was worried, but then remembered that I was behind a NAT, and I had forgotten to forward port 443 on my router.
After forwarding the port and retrying, the tool informed me that it had succeeded and dropped some certificates into the /etc/letsencrypt/live/sequentialread.com
directory. I checked to see what was there and saw:
ls /etc/letsencrypt/live/sequentialread.com
cert.pem chain.pem fullchain.pem privkey.pem
Then I checked the documentation for jwilder/nginx-proxy regarding SSL and saw that the tool expected certificates and private keys to appear in a certain place, either named according to the subdomain or via a CERT_NAME
environment variable. So I put CERT_NAME: letsencrypt
on all of my containers that are served publicly, mounted the /dockerdata/nginx/certs
directory at the correct place inside the jwilder/nginx-proxy
container, copied the files according to what nginx-proxy expects, and restarted docker-compose:
cp /etc/letsencrypt/live/sequentialread.com/fullchain.pem /dockerdata/nginx/certs/letsencrypt.crt
cp /etc/letsencrypt/live/sequentialread.com/privkey.pem /dockerdata/nginx/certs/letsencrypt.key
docker-compose -f /compose/docker-compose.yml stop
docker-compose -f /compose/docker-compose.yml up -d
I did run into a minor snag, where docker couldn't mount the certs
volume without re-creating the jwilder/nginx-proxy
container, but after that, it worked right away.
I was completely blown away by how easy it was. The whole process only took about a half an hour, while I was expecting to be debugging the setup all evening, or end up having to revert to a hard-coded nginx configuration.
I wouldn't use this setup without giving it more scrutiny if I was handling credit card data or other sensitive information, but for ease-of-use, it can't be beat.