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 black@scene-si.org \
-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 www.scene-si.org
and scene-si.org
, as defined with -d
.
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 /etc/letsencrypt/live/
.
I’m resolving the symlinks with the readlink
command, as I need to copy these generated files to my location under $DESTINATION/nginx/cert
.
dhparams.pem
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.
nginx configuration
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;
Closing words
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 serverricharvey/nginx-php-fpm
- for serving dynamic web pages (back-end)percona
- a higher-performance fork of mysql with some added featuresnazarpc/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 appssimplyintricate/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:
- Go with Databases
- Advent of Go Microservices
- API Foundations in Go
- 12 Factor Apps with Docker and Go
Feel free to send me an email if you want to book my time for consultancy/freelance services. I'm great at APIs, Go, Docker, VueJS and scaling services, among many other things.
Want to stay up to date with new posts?
Stay up to date with new posts about Docker, Go, JavaScript and my thoughts on Technology. I post about twice per month, and notify you when I post. You can also follow me on my Twitter if you prefer.