Made Tech Blog

Let’s Encrypt setup on Nginx

Let’s Encrypt is a new certificate authority which provides free and automated certificates. It’s sponsored by many of major players including the EFF, Mozilla and Google.

The service is now considered stable and just left beta recently. As I write these lines, over two million certificates have been issued in less than five months following an exponential growth. The statistics can openly be checked at

How does it work ?

The Let’s encrypt client is communicating to the certificate server through a protocol called ACME. This protocol is handling all the operations related to the certificate and is used by the letsencrypt client to register or revoke certificates.

Installing the client

I’m going to assume you are using Ubuntu here for the installation but it can be adapted really easily to other distributions / operating systems. Please run these commands as root (sudo su on Ubuntu).

# apt-get update
# apt-get -y install git
# git clone /opt/letsencrypt
# /opt/letsencrypt/letsencrypt-auto /usr/local/bin/letsencrypt-auto

The let’s encrypt command line tool can now be used! It probably still needs to install more dependencies to work properly, just call letsencrypt with the–help flag and it will install the remaining dependencies.

# letsencrypt-auto --help

Everything is now ready to get the certificate! I’m going to assume here the domain is already registered, if it’s not, just add it from your registrar.

Nginx configuration

Preparing for let’s encrypt
First, the dhparam.pem file needs to be generated. This file is used by the Diffie-Hellman key exchange algorithm in order to achieve Perfect Forward Secrecy. In other words, even if a third-party gets access to your private key in the future, no previous communication which used HTTPS can be decrypted.

The file can be generated by using this command (this can take a long time):

# openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Now we can create the Nginx configuration!

First we need to enable read access to the .well-known folder. This folder is used by let’s encrypt to verify that you have ownership of the domain and that you are not generating a certificate for someone else. Let’s encrypt is going to create a file in this directory with a secret and verify its access before creating the certificate.

The configuration is normally located in /etc/nginx/site-enabled/

server {
       # this is the basic nginx configuration for a static site
       # you might have more depending on your site!
       listen 80;
       location / { autoindex on; }

       root /var/www/;

       # enabling access to Let's encrypt
       # this is the line we need to add
       location ~ /.well-known { allow all; }

Then Nginx should be reloaded to take into account those changes. With systemd, this is how you do it:

# systemctl reload nginx

If you are not using systemd, you might use service nginx reload or /etc/init.d/nginx reload to achieve the same effect.

Generating the certificate

Everything is ready to get the certificate! Now let’s encrypt should be called to verify the domain and retrieve the certificate for us.

# letsencrypt-auto certonly -a webroot --agree-tos --renew-by-default --webroot-path=/var/www/ -d

If everything is configured properly, this is what should appear on the screen:

Requesting root privileges to run with virtualenv: /root/.local/share/letsencrypt/bin/letsencrypt certonly -a webroot --agree-tos --renew-by-default --webroot-path=/var/www/ -d

 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/ Your
   cert will expire on 2016-08-04. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - If you like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:
   Donating to EFF:          

The certificate has now been retrieved and can be seen in the /etc/letsencrypt/live/ folder.

# ls -l /etc/letsencrypt/live/
total 0l
rwxrwxrwx 1 root root 45 May  6 09:20 cert.pem -> ../../archive/
rwxrwxrwx 1 root root 46 May  6 09:20 chain.pem -> ../../archive/
rwxrwxrwx 1 root root 50 May  6 09:20 fullchain.pem -> ../../archive/
rwxrwxrwx 1 root root 48 May  6 09:20 privkey.pem -> ../../archive/

HTTPS Configuration
Here is the configuration I use for HTTPS, I’ve added comments to the relevant sections. You can test if everything is configured properly by using the Qualys SSL Server Test, this Nginx configuration is normally getting A+.

The first part of the configuration is the same as the HTTP part, the HTTPS configuration can be added directly after the HTTP one in the exact same file.

server {
   listen 443;

   # This is copied from the HTTP section
   location / { autoindex on; }
   location ~ /.well-known { allow all; }
   root /var/www/;

   # ----- SSL configuration -------

   # certificate location
   ssl_certificate /etc/letsencrypt/live/;
   ssl_certificate_key /etc/letsencrypt/live/;

   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

   # cipher list
   ssl_prefer_server_ciphers on;
   ssl_session_cache shared:SSL:10m;
   ssl_dhparam /etc/ssl/certs/dhparam.pem;
   ssl_session_timeout 1d;
   ssl_session_tickets off;
   ssl_stapling on;
   ssl_stapling_verify on;

   # security HTTP headers
   add_header X-Frame-Options DENY;
   add_header Strict-Transport-Security max-age=15768000;
   add_header X-Xss-Protection "1; mode=block";
   add_header X-Content-Type-Options nosniff;

   # allowing lets encrypt to access the well-known folder
   location ~ /.well-known { allow all; }}

Everything is now ready to disable HTTP completely! The HTTP part of the configuration can now be changed to redirect any HTTP connection to HTTPS by doing a standard redirect.

location / { return 301$request_uri; }

Renewing the certificate
For security reasons, let’s encrypt certificates have a low validity duration, the certificate needs to be renewed regularly. To renew a certificate, the same command used to generate it in the first place can be executed:

# letsencrypt-auto certonly -a webroot --agree-tos --renew-by-default --webroot-path=/var/www/ -d

A crontab makes it easier to renew automatically the certificate:

# crontab -e
5 8 * * Sat letsencrypt-auto certonly -a webroot --agree-tos --renew-by-default --webroot-path=/var/www/ -d

In this case, the certificate gets renewed every week on Saturday morning. Because it’s easy to miss if a certificate is not renewed, SSL Catch is a small service which is going to send you an email if the certificate is about to expire, this is definitely going to save you some time if part of the configuration is wrong.


Even if the Nginx configuration is not built-in into the lets-encrypt client like Apache, the let’s encrypt tool makes it easy to create new new certificates. With over two million certificates already issued, the HTTPS web is growing stronger and stronger every month and making the web a more secure place.

About the Author

Avatar for Alex Minnette

Alex Minnette

Software Engineer at Made Tech