SSL for free: Let's encrypt! (NGINX)


New Blog -> New Technology. Why not delivering the blog via SSL and give it a little bit more security?

SSL is used to encrypt the data between a webserver an his clients, so no unauthorized person is able to read/grap them.

Since nowdays it seems to be good form trying (at least) to encrypt the data on it's way.
But since today I failed to see spending money for encryption on a private project. Since the last years, prices for valid certificates have plummeted a lot. And now there is Let's Encrypt, who give certs away for free!

To receive this certs, you have to checkout their GitRepo and change to that directory.

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

After that, you just have to start the tool just with correct parameters:
(The script has to install all it's dependencies and compiles it's binaries on the first run.)

./letsencrypt-auto certonly --rsa-key-size 4096 -d flazer.de -d www.flazer.de

If you want to add more Domains, just use the param -d (the current maximum is about 100 domain per cert).

HINT: When Let's Encrypt checks, if the domain really points to the server the certificates should belong to, it starts a own small host, listening on port 80. This means NGINX must be switched off.

I had a problem when the script tried to compile Python, because there wasn't enough RAM and SWAP available on my tiny virtual server.
So let's have a look into this topic. Maybe there is somebody out there with similar problems:

sudo su
mkdir -p /var/cache/swap # create folder
dd if=/dev/zero of=/var/cache/swap/swap0 bs=1M count=4096 # create a 4Gb file 
chmod 0600 /var/cache/swap/swap0 # change rights: Nobody, except root
mkswap /var/cache/swap/swap0 # format swap
swapon /var/cache/swap/swap0 # mount swap
swapon -s # check swapfile

If everything went right, you will find four files in /etc/letsencrypt/live/_DOMAIN_NAME/:

  • cert.pem
  • chain.pem
  • fullchain.pem
  • privkey.pem

NGINX needs just two of these certificates (fullchain.pem & privkey.pem) in it's server-configuration-file.

server {
    listen 443 ssl default_server;
    server_name flazer.de;

    ssl_certificate /etc/letsencrypt/live/flazer.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/flazer.de/privkey.pem;

    ...
}

After these changes, the webserver has to be rebooted:

/etc/init.d/nginx restart

These Certificates are valid only for 90 days!
Now you don't want to request new certs every three month by yourself. So let's write some code to do it via cron:

#!/bin/sh
service nginx stop  # stop nginx
/opt/letsencrypt/letsencrypt-auto renew -nvv --standalone --agree-tos > /var/log/letsencrypt/renew.log 2>&1
LE_STATUS=$?
service nginx start # start nginx
if [ "$LE_STATUS" != 0 ]; then
    echo Automated renewal failed:
    cat /var/log/letsencrypt/renew.log
    exit 1
fi

You can save that script where ever you want to. I just placed it next to the other stuff in /opt/letsencrypt
When you want to test it, you should add --dry-run to the command. This will just simulate the creating of these certificates. To do this, the script will request data from Let's Encrypt and will not touch the existing certs.
Take all this stuff and put it into your crontab. Trigger the script every month. It will check independently, if a renewing is really necessary and will request a new one:

sudo su
crontab -e
0 0 1 * * /opt/letsencrypt/auto-renewal.sh

Update:

Daniel just told me, that i only achieve a B-Rating on SSLlabs with my SSL-config. Because he is a cool guy, he sent a nice Howto, to be able to achieve an "A":

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

Now adjust the configuration of your Nginx (/etc/nginx/nginx.conf):

# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE

ssl_prefer_server_ciphers on;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_dhparam /etc/nginx/dhparams.pem;

Don't forget to reboot Nginx, to activate the changes!

Everything is fine and we are happy!

Sources:
letsencrypt.org/getting-started
wiki.ubuntuusers.de/Swap/
weakdh.org/sysadmin.html