Automating Let's Encrypt Certificates for Nginx

Posted on Mon 07 December 2015 in misc

The Let's Encrypt public beta is here, which means you can get free 90-day SSL certificates for as many domains as you'd like, absolutely free. The 90 day certs are designed to encourage automation, and the client even includes support for updating your certs non-interactively from the command line. Basic configuration of virtual hosts with Let's Encrypt generated certificates and nginx is covered well here.

Free auto-renewing SSL certificates are awesome, but right now the only httpd supported by the letsencrypt tool itself is Apache. The letsencrypt client's webroot option (verifying the certificate by writing to the domain's root directory) works for nginx, but that requires the root of the virtual host be a place where static files are served. This doesn't work if you're using nginx as a reverse proxy for an application server, like an IPFS gateway. Instead, we need to use the standalone method which actually binds to ports 80 and 443.

Unfortunately, the need to stop and start the webserver manually pretty much precludes running letsencrypt as a non-root user, unless you feel like giving another user the ability to run init scripts as sudo without a password. This means that we need to write a script to run as root and put it in root's crontab. To avoid cluttering up /root, I suggest cloning the Let's Encrypt github repository to /usr/src. Here's a script to automatically update the certificates for any Linux distribution with systemd. If you care enough about init systems to use something else, I'm sure you can adapt it yourself.

1
2
3
4
5
6
#!/bin/sh
systemctl stop nginx
sleep 5
/usr/src/letsencrypt/letsencrypt-auto certonly --renew-by-default --standalone \
 --email ayy@lm.ao -d ayy.lm.ao > /dev/null
systemctl start nginx

The --email flag is the email that Let's Encrypt will send messages to, and the -d flag is the domain for which you're requesting a certificate. sleep 5 is just a precaution to allow running nginx workers to finish.

Once that script is saved to root's $PATH and set executable, add it to crontab at some interval less than 90 days to avoid renewal problems. I have it set to run on the first day of every other month, for example.