Automating Let's Encrypt with Nginx
Recently I’ve been messing around with Let’s Encrypt and have found a simple way to auto-renew SSL certs without requiring the nginx beta plugin. Let’s Encrypt is a new Certificate Authority which provides free, simple to obtain SSL certificates for your website(s). The entire process and client is open source and is audited by professionals all around the world. As of writing this post, the client is still in public beta, hence the lack of support for true Nginx support.
This guide aims to teach you how to automate the SSL renewal process even though Let’s Encrypt doesn’t fully support Nginx in this way, yet. It will take about 1/2hr if you don’t already have Nginx setup and your initial certificates generated, otherwise it should only take a couple of minutes!
This guide is based off of my Raspberry Pi 2, which is running raspbain jessie lite. Before following this guide you will need to have Nginx setup, along with you initial certificates generated (follow steps 1-3, this guide serves as a modification of step 4).
At the time of writing this post, SSL certificates generated by Let’s encrypt are only valid for a short period of 90 days. They do this since the renewal process should be automatic, and if one of your certificates is compromised then it will only be valid for a short period of time instead of multiple years. To automate the process I chose to use the webroot authentication method with a simple cronjob to renew my scripts.
To take advantage of automatic renewals with Nginx, we will be using the webroot feature of Let’s Encrypt which allows us to specify a directory which the Let’s Encrypt client can tell their server to look for a specific hidden file to verify your domain. You can read their official documentation on webroot authentication & renewals here. The reason we choose to use the webroot plugin instead of the standalone option is so that we don’t need to stop the nginx service to renew the certificates.
Before we can renew our SSL certificates we must prepare Nginx to serve up a special location. To do this we will make a special Nginx configuration which will ensure Let’s Encrypt has access to the
/.well-known/acme-challenge/ directory on your server, for each of your domains. A special configuration has been created for this so all you need to do is add
include letsencrypt-acme-challenge.conf; to your ssl server block of each domain/subdomain you wish to have SSL auto renew on.
Special thanks to renchap for this configuration:
# Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
Now that you have included that configuration in each of your server blocks, we must create the directory which will serve as the webroot for our
well-known directory. In my case I created the directory
/etc/nginx/renew-ssl/www/. Note that line 17 of the configuration also points to this directory, you must modify that if you change the location!
To ensure that all of your configurations are valid run
sudo nginx -t if everything checks out you can reload nginx with
sudo service nginx reload.
The configuration files will tell Let’s Encrypt which domains it should attempt to renew. First we must create a directory to store the configurations, to keep everything together I put them in
/etc/nginx/renew-ssl/ssl-available. Create an individual configuration for each of your SSL certificates each ending in
.ini and place them in the
ssl-available directory created earlier.
rsa-key-size = 4096
By default the renewal script, as seen below, will look in
/etc/nginx/renew-ssl/ssl-enabled for the configuration files to provide to Let’s Encrypt. I chose to use the same concept as
sites-avalaible which Nginx uses so that you can easily enable and disable configurations by linking and unlinking them. To link your SSL configurations run
sudo link -s ../ssl-avaliable/example.com.ini where example.com.ini is your Let’s Encrypt configuration ini. To disable a configuration just run
sudo unlink example.com.ini where example.com.ini is the Let’s Encrypt config you wish to disable.
I have created a modified version of the renewal script provided at Digital Ocean’s tutorials. This simple shell script will verify that the SSL certificates will be expiring in less than 60 days, and if they are then it will automatically run the renew command by passing in the configurations you created earlier. We will schedule this script to run once a week via a cron job so that you can guarantee that your certificates will renew before they expire. Save the following script to
Next make the script executable by running
sudo chmod +x /usr/local/sbin/renew-ssl. Make sure the configuration on lines 4-8 matches your setup. You can now manually renew your certs by running
Analyzing file: /etc/nginx/renew-ssl/ssl-enabled/blog.fletchto99.com
The last step of the renewal process is automating the script, which is where a cron job comes into play. To add the cron job run
sudo crontab -e to edit your crontab. Include the following snippet at the bottom of your crontab:
30 2 * * 1 /usr/local/sbin/ssl-renew >> /var/log/ssl-renewal.log
Save and exit the crontab. This will create a new cron job which will run the
renew ssl command every Monday at 2:30 am. The output of the command will be logged to a file located at
/var/log/ssl-renew. Now you can sit back and watch your SSL certificates renew themselves with out any work required!
In the future when you want to add a new domain/subdomain to the automatic renewal process all you need to do is create a new configuration file for it!
I hope this short guide has inspired you to use SSL with your Nginx configuration. This was my first time messing arounnd with SSL/Let’s Encrypt and it has been a great learning experience!
This guide wouldn’t have been possible without the help of these resources:
- How to Secure Nginx with Let’s Encrypt on Ubuntu 14.04
- How to setup a web server with Nginx/PHP on Raspberry Pi