Set up Let’s Encrypt with NGINX

This is a tutorial about getting your website setup to use TLS. TLS is important, and if you’re here you probably already know why. But here’s a wiki page about it just in case.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.

Installing Certbot

Certbot itself has really good installation docs. Just use the two provided drop down menus to find your software and system. For a complete example, I’m using NGINX on Debian Jesse, which links to these instructions.

The instructions tell me that I need to enable the Debian Jesse backports repository. Luckily, Certbot also links to the instructions for that. Long story short, add this line:

deb jessie-backports main

to your sources.list file located in /etc/apt/

Then run apt-get update (sudo may be required).

Finally, install Certbot by running apt-get install certbot -t jessie-backports(again sudo may be required). You should now have a certbot command.

Configuring Let’s Encrypt

The next couple of steps come from NGINX’s own wonderful docs on using Let’s Encrypt, as well as Certbot’s config docs.

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 🙂

My configuration for is documented and looks like this:

# Domains to get the cert for, comma separated
domains =,

# 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 =

# 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/

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 are different than just, so you need to list them all.

The rsa-key-size = ... is the length of the RSA key for your certificate. For now, you probably want the default of 2048, because it’s still considered secure, and it’s faster than larger keys. Additionally, key size doesn’t linearly add security, so a key of 4096 bits is only 16% more secure than a key of 2048 bits. Besides, not everything works with 4096 bit keys, and they’re slower.

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 listedhere. 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, 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;

  # 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 / {
  # 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!

Do this

certbot certonly --dry-run --config /location/of/config.conf

making sure to put the path to your config after the --config flag.

When you do that, the output should look something like this:

$ certbot certonly --dry-run --config /etc/letsencrypt/configs/quinespace.conf
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Starting new HTTPS connection (1):
Performing the following challenges:
http-01 challenge for
http-01 challenge for
Using the webroot path /var/www/letsencrypt for all unmatched domains.
Waiting for verification...
Cleaning up challenges
Generating key (2048 bits): /etc/letsencrypt/keys/0001_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0001_csr-certbot.pem

 - The dry run was successful.

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.

server {
  listen 443;

  ssl on;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_certificate /etc/letsencrypt/live/;
  ssl_certificate_key /etc/letsencrypt/live/;

  # Let's Encrypt challenge response route
  location /.well-known/acme-challenge {
          root /var/www/letsencrypt;

  # The rest of your config goes here:
  # ...

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//.

Don’t forget to reload the nginx configuration after you’ve changed your config.

nginx -t and nginx -s reload.

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):

0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot renew --post-hook "service nginx reload"

To ensure it’ll work, you’ll also want to setup a shell and path that’ll work. Earlier in the cron file (or crontab), include these:


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 🙂

1 Feb 2017



Full article:

Source: Setup Let’s Encrypt with NGINX · redlua

Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.