Deploying Let’s Encrypt with Nginx on Ubuntu 16.04
This post will (tersely) walk through the steps required to deploy Let’s Encrypt for TLS, including automatic renewals, on an Ubuntu 16.04 LTS1 server running Nginx. This will allow Let’s Encrypt to fetch and renew your certificates transparently, without interfering with whatever application you may be reverse-proxying with Nginx. We’ll use Let’s Encrypt’s webroot
verification method. The Nginx configurations included will work for a server listening on IPv4 and IPv6 and will support HTTP2.
Assumptions: I assume:
- you are fairly familiar with Nginx and Ubuntu
- you have a working Nginx server up and running
- you’re able to merge Nginx
server
configurations given in this post with whatever configuration is currently running your site/application
System Setup
Install Certbot:
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt update
$ sudo apt install python-certbot-nginx
Add the line 20 3 * * * certbot renew --quiet
to root
’s crontab via sudo crontab -e
. This will make Certbot check daily whether any certificates on this system are due to be renewed.
Updated May 2019: Adding a crontab entry to renew your certs isn’t necessary. Instead, verify that the certbot timer unit is loaded and active:
$ systemctl list-units --type timer | grep certbot
certbot.timer loaded active waiting Run certbot twice daily
If it’s not, enable it with sudo systemctl enable certbot.timer
.
Put the following script at /etc/letsencrypt/renewal-hooks/deploy/nginx
(you may need to sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
first). This script will reload Nginx after a certificate renewal completes.
#!/usr/bin/env bash
systemctl reload nginx
Finally, make the script executable via chmod +x /etc/letsencrypt/renewal-hooks/deploy/nginx
Nginx Integration
Place the following content in a new file, at /etc/nginx/snippets/letsencrypt.conf
. This will be included in the non-HTTPS configuration for your site, allowing Let’s Encrypt to verify domain ownership via the webroot
verification method:
location ^~ /.well-known/acme-challenge/ {
default_type "text/plain";
root /var/www/letsencrypt;
}
And create the directory referenced by that configuration file. This is where Certbot will place temporary domain verification files:
$ sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
Site Setup
Now that Let’s Encrypt/Certbot is set up on this system, we can start configuring your site/service. Integrate the following configuration in your HTTP server
block:
server {
# Listen on port 80 for [www.]domain.com, on IPv4 and IPv6:
server_name DOMAIN.com www.DOMAIN.com;
listen [::]:80;
listen 80;
# Route .well-known to the verification directory we’ll tell Let’s Encrypt to use:
include /etc/nginx/snippets/letsencrypt.conf;
# Redirect all requests to the HTTPS version of the site:
location / {
return 301 https://www.DOMAIN.com$request_uri;
}
}
sudo service nginx reload
to make those changes effective.
Don’t create an HTTPS server block just yet. Instead, we’ll tell Certbot to request a certificate from Let’s Encrypt:
sudo certbot certonly --webroot --agree-tos --no-eff-email --email ME@DOMAIN.COM -w /var/www/letsencrypt -d www.DOMAIN.com -d DOMAIN.com
Note the first domain passed is included in the filename for the resulting certificate, key, etc. on disk.
You should see a message like this:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator webroot, Installer None
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for www.DOMAIN.com
http-01 challenge for DOMAIN.com
Using the webroot path /var/www/letsencrypt for all unmatched domains.
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/www.DOMAIN.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/www.DOMAIN.com/privkey.pem
Your cert will expire on 2018-04-26. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
Now we can proceed to use that new certificate, configuring HTTPS server
blocks for our site in Nginx:
server {
# Listen for www.DOMAIN.com on port 443 on IPv4 and IPv6:
server_name www.DOMAIN.com;
listen [::]:443 ssl http2;
listen 443 ssl http2;
# SSL configuration:
ssl_certificate /etc/letsencrypt/live/www.DOMAIN.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.DOMAIN.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/www.DOMAIN.com/fullchain.pem;
include /etc/nginx/snippets/ssl.conf;
# Whatever configuration serves your site/application goes here.
}
server {
# Redirect non-www accesses to www.DOMAIN.com:
server_name DOMAIN.com;
listen [::]:443 ssl http2;
listen 443 ssl http2;
ssl_certificate /etc/letsencrypt/live/www.DOMAIN.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.DOMAIN.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/www.DOMAIN.com/fullchain.pem;
include /etc/nginx/snippets/ssl.conf;
location / {
return 301 https://www.DOMAIN.com$request_uri;
}
}
The ssl.conf
referenced above is posted in this Gist. It’s based on the “modern” configuration from the Mozilla SSL config generator; you may want to configure your service differently depending on your requirements.
sudo service nginx reload
, and you should now be able to access your service via HTTPS at https://www.DOMAIN.com
.
Housekeeping
You can test the renewal process with Certbot by running sudo certbot renew --dry-run
. This won’t fetch a new cert, but it will make sure all the requirements are in place for Certbot to automatically renew your certificates.
Sign up to monitor your domain with SSLMate CertSpotter and Facebook’s CT Monitoring tool. This will alert you when a new certificate is issued, and the resulting emails can serve as a reminder to go verify that Nginx is serving the new cert when Certbot renews it.
And finally, you can test your TLS configuration with SSLLabs.
1: These instructions may well apply to other versions or other similar operating systems.