Let’s Encrypt with Nginx

When I saw the first news of the Let’s Encrypt project several months ago I got pretty excited about it, mostly because I don’t like to use self-signed certificates and this blog didn’t seem worthwhile to pay for a proper certificate on.  Combined with the recent news of Google starting to shame sites not using SSL I figured I would give it a shot.  Here is a quick rundown of how I configured my nginx web server to use Let’s Encrypt SSL certificates.  The official documentation for Let’s Encrypt can be found here.

A few things to note at the start:

  • I did not use the nginx plugin, as that is very broken
  • I followed a fairly manual process using the “webroot” method thanks to this tutorial
  • My Linux distro is Arch Linux

This first thing you need to do is install/configure Let’s Encrypt. You can do this in any number of ways but the easiest way on Arch Linux is to install it via pacman

# pacman -Sy letsencrypt

You don’t need the optional packages as we won’t be using them. At this time of this writing the nginx plugin is pretty much completely broken.

The webroot method creates files in a hidden directory that the LE servers check against for validation and certificate generation.

My original Nginx configuration consisted of a default catch-all site listening on port 80 which would serve a static page to any domain not found with a valid vhost.  All of my site vhosts are configured in various config files separately.  To enable my server to have a nice integration with Let’s Encrypt I created a new configuration for the domains I want certificates for to listen on port 80 to enable the “acme-challenge” response for the domains I want certificates for.  For domains I do not want/need certificates for, they can still be served on port 80.

The configuration file I created for the acme-challenge webroot looks like this:

So this says that for the domains I want caught in this certificate, which all redirect to this site, respond to the LE “acme-challenge” on port 80, otherwise 301 redirect them to the SSL version of the site.  This enables easy renewal of the certificates.  You must restart nginx to reload the configuration.

Once I have nginx set up to respond in this manner I generated the certificates using a simple script (again, thanks to renchap):

In this script the DIR variable points to a temporary location LE will use to challenge against, as per the nginx config file above, the DOMAINS variable is a list of all the domains you want included in this certificate chain.

I then reconfigured this particular vhost to now be set up for SSL, the relevant lines to add/change in the server block are:

At this point you can restart nginx and you should be good to go.

Let’s Encrypt certificates must be renewed every 90 days, so I set up a systemd service and timer to handle the renewal automatically.

I made a simple shell script stored in /usr/local/letsencrypt.sh as follows:

Then, in /etc/systemd/system I created a service and timer file:

You can verify this service will work by manually triggering it (for example: systemctl start letsencrypt)

Enable and start the timer, and you should be all set!

Since this project is in beta and is still in very rapid development I expect this whole thing to break every now and then, I will update it as I need to fix things with the relevant changes!


Here is an example nginx configuration file for tighter security, but less compatibility, thanks to this post on the Let’s Encrypt community and examples from this github repo.

Create / edit the file /etc/letsencrypt/cli.ini and add the following:

Generate the DH key and ticket:

Modify your nginx config to look similar to the following:


Also published on Medium.

Leave a Reply