Adding SSL with Let's Encrypt

    Adding SSL with Let's Encrypt

    Let's encrypt is a new Cer­tifi­cate Authority, started by Mozilla, EFF and University of Michigan, that will offer free SSL cer­tifi­cates, with an easy setup.

    I had an attempt previously to set up SSL for my website, from StartSSL, but I... ac­ci­den­tal­ly overwrote my private key when unzipping it, so... it became quite useless, and to delete it, I would have to pay. So I put the project on hold for a while.

    Yesterday, while reading news, I saw that Let's Encrypt finally entered public beta. They promise super easy setup, but for now they don't have out of the box support for nginx, which I use, so I had to scrape together the in­for­ma­tion from several tutorials to get it to work on my server.

    First, you have to install it on the server, together with git, if you don't have it already:

    sudo apt-get update
    sudo apt-get install git
    git clone https://github.com/letsencrypt/letsencrypt
    cd letsencrypt
    export DIR=/tmp/letsencrypt-auto
    mkdir -p $DIR

    The way this works (if I understood it correctly), is that when the Let's Encrypt client contacts the Cer­tifi­cate Authority, it receives a cryp­to­graph­ic challenge that it has to write into a folder, which is accesible from the internet, to prove that it really has control of the domain that it is trying to get a cer­tifi­cate for.

    Now, our folder is not accesible to the Internet (unless for some weird reason you are serving out of /tmp), so we have to tell nginx to do that, by adding the following to our con­fig­u­ra­tion, in the section that listens to port 80:

    location '/.well-known/acme-challenge' {
        default_type "text/plain";
        root        /tmp/letsencrypt-auto;
    }

    This will tell nginx to serve all URLs that start with '/.well-known/acme-challenge' from that folder in /tmp/. After this we have to reload nginx. Normally this is done with the following command on Ubuntu:

    sudo service nginx reload

    But I en­coun­tered some problems with it. For some reason the old version of nginx wouldn't die, so it would keep the 80 port occupied, and then the new version could not start. The solution I found after some Googling, was to forcefully kill the process that was using port 80.

    sudo fuser -k 80/tcp
    sudo service nginx start

    Then we have to create the folder to hold the challenge issued by ACME (no, not the Road Runner one) and run the script provided by them:

    ./letsencrypt-auto certonly --server \
        https://acme-v01.api.letsencrypt.org/directory -a webroot \
        --webroot-path=$DIR -d rolisz.ro

    After this we will have the encryption keys in /etc/letsen­crypt/live/rolisz.ro. Now we need to tell nginx to start using them and to redirect all HTTP traffic to HTTPS. This means another change to config file. First we move all the con­fig­u­ra­tion that we have for the server that listens on port 80 to a new one that listens on 443 (where are files located, what charset, what cache-ing strategy to use for static assets, etc) and add to the 80 one the following:

        location / {
          return              301 https://$server_name$request_uri;
        }
    

    This will tell nginx that when it is accessed using HTTP, it should issue a 301 redirect to the HTTPS version. This is the best way to do this redirect.

    The bare minimum needed to make the HTTPS server work is the following:

    server {
        listen 443 ssl;
    
        root /where/my/files/are;
    
        ssl_certificate     /etc/letsencrypt/live/rolisz.ro/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/rolisz.ro/privkey.pem;
    }

    However, you can do several more things to make things even more secure, by telling nginx not to use unsafe protocols or cyphers, to use HSTS, OCSP and some other options about which I don't know anything. Mozilla has a nice tool for generating these options. One thing to be careful with, is that the modern con­fig­u­ra­tion disables TLS v1, which is required for com­pat­i­bil­i­ty with Android versions before Lollipop (5) and which are still a sizeable share of the market.

    If you use the whole config from Mozilla, you will also need to generate the Diffie-Hellman keys:

    cd /etc/nginx/
    openssl dhparam -out dhparam.pem 2048
    

    And then change the ss­l_dh­param in the config to point to the above file.

    Normally, this is it. You should be able to restart the nginx server and then look at your site, enjoying the green lock in the top right corner and knowing that your readers will really read only your content, without in­ter­fer­ence from pesky hax0rz.

    In my case, I had to do some more things. One was to do the exact same thing for my subdomain which hosts my comments. Not a big deal. Then I had to change the links for the fonts I was using to also use HTTPS. Then I also had to change Isso (the comment server) to know that it's serving for HTTPS (by just updating the URL in the config file).

    The last thing I did was to update the nginx version I had. By default Ubuntu has a pretty old version (1.6), while the latest stable is 1.8.

    sudo add-apt-repository ppa:nginx/stable
    sudo apt-get update
    sudo apt-get upgrade nginx

    Hopefully, 1.9 will be stable soon, and then I can enable HTTP2 also :D:D (one of the main reasons I added SSL to my site).

    And now, it's time to check my site with Qualys SSL Labs and enjoy the A+ that I get for security. :D