HTTP/2, Let’s Encrypt & Dokku: How to Do All Three
Cool stuff on the web is happening. Makers of low-level web tech handed out end of 2015 webdev Christmas gifts recently, with the arrival of HTTP/2 in NGINX and the public beta of Let’s Encrypt. This is how I embraced both in about 25 minutes.
If you’re not familiar with HTTP/2 or Let’s Encrypt, then I suggest reading up on them from a more informed source than I. But if you wanted the TL;DR, the following might suffice…
HTTP/2 is a super fast protocol for connecting to sites. Faster than plain ol’ HTTP, and faster than SPDY which was a SSL-compliant half step kicking around the last few years. Want to know how much faster? Well for some reason there are numerous sites in the wild loading in tiny images on an HTTP and then HTTP/2 connection to show you the difference. Like… loads of sites are doing this. Weird test, but a neat visual short-cut to see the difference. Check out Cloudflare’s demo or loadimpact.com.
Let’s Encrypt is a group backed by Mozilla, Akamai, and Facebook amongst others, that looked at SSLs and secure connections — the little green HTTPs at the top of the address bar. Though if you need that technical point-of-information, then maybe stop reading after this paragraph. It will only get more technical — they looked at them and said: “huh… why is this expensive and complicated?”
Well since they asked that question SSLs have got cheaper. They can be attained for as low as $10 a year per domain. But you know what’s cheaper than $10 per domain? $Free per domain! So that’s what Let’s Encrypt have done. They've started issuing free SSLs, that work everywhere you need them (including Android, with IE6 I believe to be the only sticky point).
Let’s Encrypt aren’t just supplying SSLs that work for free, their second party trick is building a fairly innocuous but genius client to automate the whole process. Really. If you have a vanilla setup (say NGINX or Apache serving your sites) and no Dokku shenanigans getting in the way, then follow their guide. Clone down the client. Run the client. Answer two questions. That’s it.
Now to Put it All Together With Dokku
So… HTTP/2 plus Let’s Encrypt plus Dokku. Let me preface this by saying I'm standing on the shoulders of giants, here; and I've linked my sources where appropriate.
Assume we have the following:
- 1x domain that runs under both www and non-www. Call it mydomain.com.
- A functioning and running Dokku application called myappname that is currently being served at mydomain.com.
- mydomain.com is currently live and running under an insecure http:// protocol.
- You will likely have to preface all the following commands with sudo or run as root. You’re going to be messing with your /etc/ directory.
That’s exactly where I was with mxbry.com before I started this process.
Step 1: Securing our Site
Download the Let’s Encrypt application. Here I've cloned it in to a /etc/letsencrpyt/ directory purely to keep everything neat. Clone the repo anywhere you don’t mind storing it permanently.
git clone https://github.com/letsencrypt/letsencrypt /etc/letsencrypt/
hakobaito.co.uk sets up the next few steps quite well, and the only complicated step worth understanding is why NGINX requires stopping. Dokku is hogging ports 80 and 443. Let’s Encrypt requires these ports to authenticate the certificate it is generating. Both happening at the same time? No dice right now. So NGINX needs to be stopped, and restarted when the process is over. It shouldn’t be more than 2 minutes downtime for your site. Let’s stop NGINX and then generate our certificate using the Let’s Encrypt CLI:
service nginx stop
/etc/letsencrypt/letsencrypt-auto certonly -d mydomain.com -d www.mydomain.com -m email@example.com auth
Few things to cover here:
- -d allows you to specify which domain(s) this certificate will be valid for. I added both the non-www and www versions of my site. I don’t know if you need to. Better safe than sorry.
- -m allows you to specify a contact email for recovering the SSL secret, in case it all goes wrong. If you don’t add this option in as a command line option, you will be prompted for it in the form of a wizard.
- certonly is because we don’t need all the self-installing wizardry that Let’s Encrypt will offer. We’re going to integrate this with NGINX ourselves.
The certificate parts have been generated. You need to combine them in a .tar and feed them to our NGINX configuration using the Dokku certs plugin that ships with Dokku as standard. I don’t want to bite the work of hakobaito.co.uk too much, but their next steps explain themselves:
cat /etc/letsencrypt/live/mydomain.com/fullchain.pem > /tmp/server.crt
cat /etc/letsencrypt/live/mydomain.com/privkey.pem > /tmp/server.key
tar cvf /tmp/certs.tar /tmp/server.crt /tmp/server.key
dokku certs:add myappname < /tmp/certs.tar
Here we’re stuffing the chain and key in the tmp directory (delete these once you’re done) for convenience.
Now just start NGINX and you should be good.
service restart nginx
www.mydomain.com and mydomain.com should both forward to HTTPS, where they will be running happily and securely.
Step 2: Making our Secure Site Fast
Let’s make our secure site modern by rolling in our new friend HTTP/2. Alas, problems:
- Dokku by default ships with NGINX 1.4.2. HTTP/2 support was added to NGINX in 1.9.5. That’s going to be trouble.
- The standard Dokku NGINX SSL conf template allows us to run a site under SPDY, but not HTTP/2. So we’re going to have to make an amend to that SSL NGINX conf template.
Two things to do: 1) upgrade NGINX, 2) edit the NGINX template.
Let’s upgrade NGINX. Digital Ocean provide a great guide on how to do this, but we need to make a small amend. Where they have set the PPA target as…
sudo add-apt-repository ppa:nginx/stable
… we will need to change this to…
sudo add-apt-repository ppa:nginx/development
We’re using the development branch, because currently 1.9.x is on NGINX’s “mainline” branch whilst stable is capped at 1.8.x. I’m not going to make any assurances about what you’re gaining and losing by jumping from 1.4.2 to 1.9.5, but it all seems fine to me so far.
With that amend in place, follow the rest of Digital Ocean’s guide.
Now we can support HTTP/2, let’s make sure our site uses it. To do this we need to change the template Dokku uses to generate out the NGINX conf file. Luckily Dokku makes adapting this template easy, without having to dig in to Dokku’s internal files. Dokku’s documentation on this subject outlines two different ways of doing this: either placing our new NGINX template in the root of our Dokku project, or by changing the template on the server.
I prefer the former; it’s cleaner. So in the root of our project’s repository let’s recreate the existing Dokku NGINX template line-for-line, except for a small little edit (in bold):
return 301 https://\$host:$NGINX_SSL_PORT\$request_uri;
listen [::]:$NGINX_SSL_PORT ssl http2;
listen $NGINX_SSL_PORT ssl http2;
Note how in the original Dokku template had spdy as a “listen” protocol. Well now we’ve replaced it with http2 , in two places within the file. If you want to see the full template, either copy the original from Dokku’s repo and make the changes yourself or see what I have committed to my mxbry.com repo.
Commit that file back to your repo, push that repo back up to your server (the ol’ git push dokku master), and you’re done.
mydomain.com running under an SSL on HTTP/2. Easy.
Two things to do now:
- Note that the Let’s Encrypt certs expire after 90 days. So 90 days from the day you generate the certs you will have to run all of those Let’s Encrypt and .tar balling commands again, otherwise visitors to your site will be met with a nasty insecure message. Alternatively, you can set up a CRON to do all this for you and never think about SSLs again.
2. You can test your SSL and shiny HTTP/2 status at the following sites: