Let's Encrypt with auto-renewal and nginx

I recently moved from using a wildcard certificate to using a bunch of certificates from Let's Encrypt. I was a bit hesitant in the beginning because it seemed like a lot of work and hassle to deal with auto-renewal every 90 days but as it turned out it's all really simple and free.

I'm just documenting this here so I can be lazy and just go back to this post in the future. As usual I'm using Gentoo and nginx here but this should work for almost every other configuration. This is the minimal nginx config I usually use that scores A+ on SSLLabs and works well for all my needs.

Let's Encrypt

To get the certificates I'm using the official tool that is now under the umbrella of the EFF: certbot

Install this tool on your system, stop your currently running web server to free up the port and then just run the tool:

$ certbot certonly

If you run it for the first time it'll ask you to accept some terms and to enter your email address. After that you'll see this screen:

how to authenticate

Selection option 2 here and continue, on the next screen just enter the domain you want to get your certificate for and press OK.

After that the certificate and private key will be generated and are located in /etc/letsencrypt/live/example.com/. I usually use this path directly in nginx so I don't have to copy around certificates once I renew them.


The nginx config is really basic and just looks like this. I split off the ssl.conf because it's the same for every domain's config and I didn't want to duplicate all that. That's why it's just imported and that way I don't have to update all configs if I update the cipherlist in the future.

server {
    listen      443 default_server ssl;
    server_name example.com;

    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/nginx/ssl.conf;

    error_log   /var/log/nginx/example.com.error.ssl.log;
    access_log  /var/log/nginx/example.com.access.ssl.log;

    root /var/www/example.com/;
    index index.html;

    location / {
        alias /var/www/example.com/example.com/;

server {
    listen      80;
    server_name example.com;
    return      301 https://$server_name$request_uri;

The ssl.conf looks like that right now, make sure you generated the dhparam.pem file with openssl and it's located in that directory.

ssl on;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_dhparam /etc/nginx/ssl/example.com/dhparam.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

ssl_stapling on;
ssl_stapling_verify on;
resolver valid=300s;
resolver_timeout 10s;


The Let's Encrypt certificates expire every 90 days right now (Reason). For that reason we have to set up a script to check if they are still valid every once in a while and if not, renew them. Luckily this is all really easy and we just have to add a new cronjob. For the tool to run we have to stop the web server again so it can use the included webserver to set up the endpoint to talk to the Let's Encrypt API. We can just do that with the --pre-hook and --post-hook parameters.

@weekly  /usr/bin/certbot renew --standalone --pre-hook "/etc/init.d/nginx stop" --post-hook "/etc/init.d/nginx st    art" --quiet

This also makes it very easy to just run shell scripts to do some more things in case of a renewal. For ZNC for example you can use a tiny script like that to update the certificates the web interface of the bouncer is using.

root@examplecom ~$ cat znc-ssl-update.sh
cat /etc/letsencrypt/live/example.com/{privkey,cert,chain}.pem > /home/dewey/.znc/znc.pem
chown dewey:dewey /home/dewey/.znc/znc.pem

Once this is all done just restart nginx and enjoy your free certificates.

If you want to support this organization please consider donating to the EFF: https://supporters.eff.org/donate/

Let's Encrypt with auto-renewal and nginx
Share this