Generate free SSL certificates with Docker and LetsEncrypt
It’s been more than a year in the waiting, after I found out that Mozilla Foundation, Akamai, Cisco, and a bunch of other big players put their support into LetsEncrypt, a free certificate authority. Back then (I’m speaking as if 2014 was still in the time of Yugoslavia or USSR), you would have to go trough several complicated steps for generating a SSL certificate for free (client certificates, issuing certificate signing requests, worrying about key size, key formats, validating your certificate via e-mail, …). I promise, the wait is over.
Today you can use letsencrypt to automatically generate the certificate for you. They are valid for 90 days, so technically, all you need to do is regenerate them within this period. Since the whole process can be automated, it’s much easier than remembering a year from now to renew your SSL certificate and how to actually do it.
As I’m in a “let’s use docker for everything” mood in the recent time. On the encouragement of @OmgImAlexis I was reminded of letsencrypt and finally decided to give it a run. It was just a matter of finding a correct docker image, which wouldn’t give me a complete server, but can somehow use my existing server to communicate with their service.
In the end, the whole thing was so surprisingly easy that I’m wasting more time blogging about it, than I actually did by generating the SSL certificate. I’m just going to share with you my approach and break it down so you understand it.
#!/bin/bash DESTINATION="/var/www/black-dev/scene-si.org/" DOCKERFILE="xataz/letsencrypt" ROOTPATH=$(dirname `pwd`); docker run -it --rm \ -v $ROOTPATH/conf:/etc/letsencrypt \ -v /var/www/black-dev:/var/www xataz/letsencrypt \ certonly --webroot --agree-tos -m email@example.com \ -w /var/www/scene-si.org/public_html -d www.scene-si.org -d scene-si.org SOURCE=$ROOTPATH/conf/live/www.scene-si.org/ KEY=$(readlink -f $SOURCE/privkey.pem) CHAIN=$(readlink -f $SOURCE/fullchain.pem) cp -f $KEY $DESTINATION/nginx/cert/server.key cp -f $CHAIN $DESTINATION/nginx/cert/server.pem if [ ! -f "$ROOTPATH/data/dhparams.pem" ]; then openssl dhparam -out $ROOTPATH/data/dhparams.pem 2048 fi mkdir $DESTINATION/nginx/cert -p cp -f $ROOTPATH/data/dhparams.pem $DESTINATION/nginx/cert/dhparams.pem
So, this is literally the way I generate the needed files for my nginx setup. I organize my docker scripts under
src, where I have
several folders, respectively
bin where I keep the above script,
conf for where I keep the container config volume,
data where I
keep any … well, data. There are basically a few important things about this script.
Using the docker image
I have chosen the
xataz/letsencrypt docker image because it was the first one which had a guide how to use it without the internal
web server, or without another web server packaged in the docker image. I’m already running a nginx instance, which I want to use when
generating the SSL certificate. You can visit the xataz/letsencrypt github page
if you want some additional instructions for the docker image.
I keep my certificates under
$DESTINATION in the folders
nginx/cert and my web root in
public_html. I’m mounting the webroot to the docker
container, and using it with the
-w option. I’m generating a SSL certificate for
scene-si.org, as defined with
The web root folder should be reachable from your web server, as the letsencrypt service verifies it by connecting to the domains you’re generating the SSL certificate for.
LetsEncrypt places the generated certificates in the
archive folder, and creates symlinks under
I’m resolving the symlinks with the
readlink command, as I need to copy these generated files to my location under
This is a file which improves your SSL security against the Logjam attack. Logjam is an attack against the Diffie-Helman key exchange which is used in the HTTPS protocol, as well as others. You can read more about it here: weakdh.org. There are a few other attacks which have been publicized in the last years (Heartbleed, Pooddle,…), so it’s good to check your server against those.
I’m using Qualys SSL Labs page to check the installation of my SSL certificate, to see if I’m reasonably secure. The “key exchange” is one of the tests being done, and a custom dhparams file solves this issue.
There is my configuration for nginx, which uses the key, the certificate chain, the dhparams, and configures some option to make the SSL termination as secure as possible at this time.
ssl_certificate /var/www/black-dev/scene-si.org/nginx/cert/server.pem; ssl_certificate_key /var/www/black-dev/scene-si.org/nginx/cert/server.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers 'AES128+EECDH:AES128+EDH'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_dhparam /var/www/black-dev/scene-si.org/nginx/cert/dhparams.pem;
SSL Certificates are still far from perfect when it comes to the issues of “Trust” versus the convenience of obtaining a SSL certificate with as little effort as possible. LetsEncrypt is not perfect for everyone - this is why we still need to use other SSL certificate authorities to provide Extended Validation (EV) certificates identifiying persons or companies, and also Wildcard certificates (for now?). LetsEncrypt is a nice step forward as it makes SSL encryption viable for anyone just by beeing free and simple to use. I am looking forward towards a safer web, even if as a programmer I understand the appeal (or is it lazyness factor) of simple text protocols like HTTP.
Docker in this case has again proved to be a viable
zero-touch alternative as opposed to installing and configuring software by hand.
A few days ago @drye asked me what I managed to run in docker on the Digital Ocean $10 VPS SSD instance, and I thought I’d just attach a list of it. These are the images I currently use, let me break them down as to what every one does:
xataz/letsencrypt- for generating SSL certificates for various web sites on the server
richarvey/nginx-php-fpm- for serving dynamic web pages (back-end)
percona- a higher-performance fork of mysql with some added features
nazarpc/phpmyadmin- a web server with phpmyadmin (i might get rid of this one because #2)
node- the node.js runtime, with npm. I use it for developing and running node.js apps
simplyintricate/hexo- hey, I run a blog. I also installed it with docker.
renoirb/nginx-http2-luajit- this is my front-end/reverse proxy. I use lua for some development purposes (CGI, kinda)
While I have you here...
It would be great if you buy one of my books:
Want to stay up to date with new posts?