Using Let's Encrypt With NGINX
Setting up NGINX to use SSL certificates from Let’s Encrypt isn’t as automated as the Apache tooling, at least, not right now. That said, with a bit of setup, we can configure this to work with NGINX very easily.
Here’s what the entire setup process looks like:
- Install the Let’s Encrypt client
- Create a Let’s Encrypt configuration file for the domain
- Add an NGINX server block to allow Let’s Encrypt to verify the domain
- Verify the domain and generate SSL certificates
- Set up NGINX to serve using our new SSL certificates
A Note About File Permissions
There are a few gotchas that may sneak up on you while working through this guide. The main thing that I ran into is that Let’s Encrypt and NGINX will need read and write access to specific files and directories on your system. I’m not going to get into file permissions in this article, but I will mention where/when this will be necessary.
Let’s get started!
Install the Let’s Encrypt Client
The Let’s Encrypt client is available on github. We’ll
clone it to our user’s home directory. In this instance, the username is
deployer
. After this, running letsencrypt-auto
will install Let’s Encrypt’s
dependencies using apt-get
or yum
.
cd /home/deployer
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto
For more information about this, read the official Let’s Encrypt installation docs.
Create the Let’s Encrypt Configuration File
To issue an SSL certificate, Let’s Encrypt requires a few piece of information
which we’re going to store in a configuration file for easy reuse later. Write
this information to /etc/letsencrypt/cli.ini
– both your user, and the user
that runs NGINX will need read and write access to this directory and its
children as it’s also where the SSL certificates will be stored.
# /etc/letsencrypt/cli.ini
rsa-key-size = 4096
email = youremail@address.com
domains = yourdomain.com, www.yourdomain.com
text = True
authenticator = webroot
standalone-supported-challenges = tls-sni-01
webroot-path = /tmp/letsencrypt
There are more details in the documentation for a Let’s Encrypt configuration file.
Configuring NGINX for Webroot Authentication
We’re going to use webroot authentication in the Let’s Encrypt client to obtain our SSL certificates. So, add this configuration option to your domain’s NGINX server block:
server {
listen 80;
server_name yourdomain.com
# other NGINX config for your domain
location '/.well-known/acme-challenge' {
default_type "text/plain";
root /tmp/letsencrypt;
autoindex on;
}
}
Once you’ve added this to your server block, tell NGINX to reload the config
files sudo nginx -s reload
.
What we’re doing here is telling NGINX to statically serve any requests to
yourdomain.com/.well-known/acme-challenge and its subdirectories from the
/tmp/letsencrypt/
directory on your server for the webroot authenticator. For
this to work, NGINX will need permission to read from the /tmp/letsencrypt
directory.
In the next step, I’ll explain why, and how this works.
Verifying the Domain and Receiving SSL Certificates
Now that this is set up, we need to request the certificates from Let’s Encrypt. Here’s how:
mkdir -p /tmp/letsencrypt
/home/deployer/letsencrypt/letsencrypt-auto certonly \
--server https://acme-v01.api.letsencrypt.org/directory \
--agree-dev-preview \
--config /etc/letsencrypt/cli.ini
sudo nginx -s reload
To break down what happens:
-
The Let’s Encrypt client creates a file in
/tmp/letsencrypt
containing a token. -
Then, the client tells the Let’s Encrypt server that it can verify the
domain by requesting the file it has created with a request to
yourdomain.com/.well-known/acme-challenge/token-filename
-
If the file is present, Let’s Encrypt will generate SSL certificates for the
domain and copy them to
/etc/letsencrypt/live/yourdomain.com/
-
The Let’s Encrypt client cleans up the file from
/tmp/letsencrypt
And that’s it, you’re ready to set up NGINX to use your brand new SSL certificates.
Configuring NGINX to Serve via SSL
This is a complete NGINX server block – with these certificates, it receives an A on the Qualys SSL Labs Scanner but won’t support older versions of Android devices or Internet Explorer. Disclaimer – these configurations come from the Mozilla SSL Configuration Generator and an NGINX example config from the Let’s Encrypt forums. You may want different options based on browser support.
To use it, there’s one additional step. You’ll need to generate a dhparam.pem
file in /etc/nginx
by running:
openssl dhparam -out /etc/nginx/dhparam.pem 2048
Finally, here is the NGINX config – replace yourdomain.com
in this file with
your own domain name, tell NGINX where the project root is, and everything
should work.
server {
root /home/deployer/webroot-path;
listen 443 ssl;
server_name yourdomain.com;
ssl on;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
# Generate with:
# `openssl dhparam -out /etc/nginx/dhparam.pem 2048`
ssl_dhparam /etc/nginx/dhparam.pem;
# modern configuration. tweak to your needs.
ssl_protocols TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK';
ssl_prefer_server_ciphers on;
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
add_header Strict-Transport-Security max-age=15768000;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
## verify chain of trust of OCSP response using Root CA and Intermediate certs
ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
}
Renewing Certificates
The great thing about this process is that it is easy to schedule. Once you’ve gotten everything working, you can simply run the command to generate certificates when they are close to expiring, and it will generate new ones for you and symlink them into the same location. Once the new certificates have been generated, you need restart NGINX, and you’re done!