Setup Let's Encrypt with NGINX

Before we start setting things up, let’s first talk about scope.
This article isn’t trying to answer every single aspect of setting up a server
with NGINX and Let’s
Encrypt.
But it is trying to combine advice from a series of other guides in order to
give you a complete and somewhat more up-to-date guide on how to use these
technologies.

You won’t need to understand how all the pieces work to still get things
working.
And at the end, you’ll have a website that is secured with TLS.

Configuring Let’s Encrypt

First off, we need a configuration for generating our Let’s Encrypt certificate.
This sets up things like the domains we generate the certificate for, as well as
things like the certificate key size and method of authentication.
It’ll also let us figure out what we did later (something that I’ve found
incredibly useful in writing this blog post :)

# Domains to get the cert for, comma separated
domains = www.quine.space, quine.space
# Set the key size (2048 is the default, but this makes it explicit)
rsa-key-size = 2048
# The renewal reminder email will be sent here
email = you@your-domain.example.com
# ncurses is used by default, this turns it off
text = True
# The method of authentication
authenticator = webroot
webroot-path = /var/www/letsencrypt

You want to save this somewhere where you can find it again.
Either make a letsencrypt folder in your home directory, or make a configs
folder in /etc/letsencrypt/.
I personally saved the config above here:
/etc/letsencrypt/configs/quine.space.conf.

Now lemme say some stuff about the contents of this file.

The domains = ... section is a comma separated list of the domains you want
your certificate to cover.
Subdomains like www.example.com are different than just example.com, so you
need to list them all.

The email = ... doesn’t have anything to do with your key, but it will allow
Let’s Encrypt to email you when your certificate is expiring, if it hasn’t been
renewed yet.

text = True turns off the UI that Certbot has.
This only has an effect when creating the certificate initially, so setting it
is optional.

The authenticator = ... and webroot-path = ... are the method of
authentication used to prove that you have the domain.
The available methods are listed
here.
We’re going to use webroot because it can be used with any type of web server,
and doesn’t require either port 80 or 443 to be free.
I didn’t use the --nginx plugin because I couldn’t get it to work initially,
and “needed” to update my certificate quickly, as the previous one had expired.

Another key point about webroot-path is that this is the location that NGINX
will use to serve a file that it will use to authenticate our certificate.
So the www-data user will need access to this folder to serve the information.

Configuring NGINX

In order to authenticate our certificate, we need to modify the NGINX config to
allow Let’s Encrypt to access a temporary file.
This’ll involve an update to whatever NGINX configuration you have now.
For quine.space, I use NGINX only for the TLS termination,
and proxy the traffic locally.
So here’s a sample configuration with some explanation, but your config will
vary from what’s shown here.

# Lots of comments at the top of this file normally
# The part we care about starts with "server"
server {
listen 80;
server_name quine.space www.quine.space;
# The initial letsencrypt setup
location /.well-known/acme-challenge {
root /var/www/letsencrypt;
}
# Your config is down here, and might include one or both of the following:
#
# Regular proxy passing
location / {
proxy_pass http://127.0.0.1:3000;
}
#
# Maybe a rewrite to move people to https?
rewrite ^ https://$server_name$request_uri? permanent;
}

The key to this file is the initial Let’s Encrypt setup.

location /.well-known/acme-challenge {
root /var/www/letsencrypt;
}

You may remember /var/www/letsencrypt.
It was in our original Certbot config, and it’s the location from which Certbot
will check that we control this domain.

An aside: We currently have the check here, on port 80 and unencrypted,
because we don’t yet have a certificate.
Later, we can actually put this configuration in our TLS config (port 443), and
use our current certificate to secure the connection in checking for our new
one.

After you’ve setup NGINX, test the config with nginx -t and reload it with
nginx -s reload.
As always, you might need sudo for those.

Testing and running Certbot

Now that we have everything setup, we can do a test run of Certbot to make sure
it works before we actually run it to get our certificates!

If your dry run is successful, go ahead and run the same command without the
--dry-run.
If that works, you should see a message under IMPORTANT NOTES: that tells you
where your certificate was saved.
We’ll need that in a second.

Updating NGINX to use the generated certificate

Now that we have our certificates, we can setup NGINX to use them!

You probably want to change your server config for port 80 to no longer include
serving the challenge response, and to now forward traffic to port 443.

So remove:

location /.well-known/acme-challenge {
root /var/www/letsencrypt;
}

And maybe add something like:

rewrite ^ https://$server_name$request_uri? permanent;

Then add the ssl certificates to your 443 section, as well as the challenge
response url that used to be under the port 80 section.

where the ssl_certificate and ssl_certificate_key lines point to the
location you saw above under IMPORTANT NOTES:.
If you don’t remember where that was, don’t worry too much.
It’s probably in /etc/letsencrypt/live/<name_of_your_domain>/.

After all of that, test to make sure you can use the new configuration to renew
your certificates.
Do this by running certbot renew --dry-run.
If you eventually see part of a message say Congratulations, all renewals
succeeded., then you’re good to go.

Automating Certbot

Now that everything is setup properly, we need to automate the renewal process.

For Debian Jesse, this is super easy, as Certbot has already setup a cron for us
in /etc/cron.d/certbot.
If you look at that file, you’ll see it already has a cron command setup to run
twice a day.
We just need one little tweak to make things work for us.
That is, adding a --post-hook to the certbot renew command so that our
server reloads once we have the new certificates in place.
So add this to the end of the line after certbot renew: --post-hook "service
nginx reload".

Oh, and why run this command twice a day, when we only need to renew the
certificate once every three months?
Well, Let’s Encrypt actually suggests this.
Their API rate limit applies to the actual certificate generation, not to
attempts to renew it.
And the renewal only generates the new certificate if the current certificate
will expire in 30 days.
You could modify this timing if you want, but it’s no problem to leave it as it
is.

Maybe cron?

So this section exists because Certbot might not have setup a cron for you
already.
If that’s the case, you want your command to look something like this (all on
one line):

Also make sure you have perl installed.
But if you don’t, you can just remove the perl section: && perl -e 'sleep
int(rand(3600))'.

Checking later

Once you’ve got this all setup, you’ll want to make sure your certificate is
renewing properly.
Mark your calendar for 2 months and a couple days out from when you first did
this.
Then check your certificate in the web browser.
It should have a new “Begins On” date.

If it doesn’t, some debugging is in order.
You can see what cron issues you’re having by turning on cron
logging.
Remember, it’s fine to run the certbot renew command via cron every 5 minutes
or so while you’re debugging.
Just make sure to turn it back to twice a day or so once you’re done :)

Further Reading

All of the above is just the how of getting setup.
It is not the how of the way things work, nor the how of best
practices.

I don’t have a good source for learning how these things work.
But I do know at least one good source for checking best practices, and that’s
SSL Labs.
After going through this process myself, I used their SSL testing
tool to improve the configuration of my NGINX
server.
I recommend that you do too.
There is so much out there to know that it’s especially hard to know it all
yourself unless this is your full time job.

Sources

Here are some of the sources used to compile this information.
Some of them may have been linked in line, but all of them were used at one
point or another.