Let’s Encrypt and Nginx


Let’s Encrypt is a relatively new Certificate Authority (CA) that provides free SSL certificates for your website. This is cool, but not ground-breaking (StartSSL has offered free SSL certificates for a long time). What is ground-breaking is that Let’s Encrypt uses the brand-new Automatic Certificate Management Environment (ACME) protocol to do this. ACME provides a means to request/renew/manage SSL certificates automatically, without human intervention. If you’ve ever had to renew an SSL certificate at the last minute, you’ll know what a pain it is to create the CSR, purchase the certificate, and implement the new certificate.

Co-founded by the EFF, Mozilla, Cisco, Akamai, and the University of Michigan, Let’s Encrypt is open source and is sponsored by some of the largest organizations in the world. Let’s Encrypt is on a mission to encrypt 100% of the web (no, really) and they are shaking up the badly-broken CA industry. Even Bruce Schneier is a fan! See below for a quick timeline of their milestones.

2014-11-18 – Let’s Encrypt is created
2015-09-14 – first certificate issued
2015-09-15 – limited beta
2015-10-19 – Let’s Encrypt signing certificate is trusted by all major browsers
2015-12-03 – public beta
2016-01-04 – 250k certificates issued
2016-02-03 – 500k certificates issued
2016-03-08 – one million certificates issued
2016-04-08 – WordPress.com announces it will secure 1.3+ million sites using Let’s Encrypt
2016-04-12 – leaving beta
2016-04-21 – two million certificates issued
2016-06-16 – five million certificates issued

Let’s Encrypt managed to do something amazing: they took a boring, mundane process and made it automatic, all while inspiring the masses to care about encryption. At the time of this writing, Let’s Encrypt has issued almost six million certificates. Check out their stats page for more cool graphs!


How it works

Let’s Encrypt uses an already-used process to verify domains, but does it automatically, without human intervention. First, the client proves to the CA that the web server controls a domain. Then, the agent can request, renew, and revoke certificates for that domain. The domain verification process is outlined below.

  1. The client sends a request for a certificate to the Let’s Encrypt CA. The CA does a lookup on the DNS name in the request, and matches it to an IP. If the request came from that IP, the request is allowed.
  2. The client creates a directory under the webroot called .well-known. It then places a file in this directory, that file is signed, and signatures are exchanged with the CA. The CA then reads that file, and if it reads as expected, the request is allowed.

Possible downsides

I see two possible downsides to Let’s Encrypt, as outlined below.

Founding members and sponsors

Let’s Encrypt was co-founded by US companies, and all it will take is one NSA security letter to undermine their progress. It would have been better if they were based outside the US.

In addition, Let’s Encrypt is sponsored mostly by businesses, since they’re the only organizations that can afford to donate large sums of money to Let’s Encrypt (to keep servers running, pay developers, etc…). In the future, it’s possible that Let’s Encrypt could become a tool of those organzations.

Validation types

To keep costs down (free, actually), Let’s Encrypt only offers Domain Validation (DV) certificates. There are 4 main types of validation:

  • Class 1 – Domain Validation (DV) – This verifies nothing more than you control a domain name. This typically means you have DNS setup to point a name (loganmarchione.com) to an IP (xx.xx.xx.xx) and have an email addressed tied to that domain.
  • Class 2 – Personal identity Validation (PV) – Class 1 validation, but also requires personal identification (usually a driver’s license or passport).
  • Class 3 – Organization Validation (OV) – Class 1 and 2 validation, but also verifies an organization exists against public records (websites, phone numbers, tax records, etc…). In addition, employees of CAs will contact multiple people in the organization to verify the organization is legitimate. This is the first level of validation that is hard to fake, and requires the CA to pay employees to follow-up on.
  • Class 4 – Organization Extended Validation (EV) – Class 1, 2, and 3 validation, but also verifies more information (signed copies of specific legal documents and agreements, contacting financial institutions, an organization’s Dun & Bradstreet number, a letter from a CPA, etc…). This provides the “green bar” in the browser.

Because Let’s Encrypt is trying to make certificates free, they can’t afford to pay employees to verify information. As stated above, this only allows Let’s Encrypt to offer DV certificates. While this isn’t a bad thing, the only thing needed to request a certificate is to prove you own a domain name. If your DNS provider gets hacked, this can be compromised.


StartSSL recently launched StartEncrypt, which is a competing product to Let’s Encrypt. StartSSL has always offered free Class 1 SSL certificates, while StartEncrypt offers automatic renewal of certificates. StartEncrypt has the following differences from Let’s Encrypt (taken from StartSSL’s marketing email):

  • Not just get the SSL certificate automatically, but install it automatically
  • Not just Encrypted, but also identity validated to display EV Green Bar and OV organization name in the certificate
  • Not just 90 days period certificate, but up to 39 months, more than 1180 days
  • Not just low assurance DV SSL certificate, but also high assurance OV SSL certificate and green bar EV SSL certificate
  • Not just for one domain, but up to 120 domains with wildcard support
  • All OV SSL certificate and EV SSL certificate are free, just make sure your StartSSL account is verified as Class 3 or Class 4 identity

However, it’s important to keep in mind a few possible downsides of StartEncrypt:

  • In order to obtain higher levels of validation (i.e., class 2, 3, or 4), there is a cost required, then the certificates are included for free
  • StartSSL charges to revoke certificates
  • The StartEncrypt client is closed-source and requries root access
  • There is little documentation for StartEncrypt

That being said, there is nothing wrong with StartSSL, just be aware of what you’re getting into. They’ve had some known complaints in the past.

Certificate setup


There are many clients available, but I’m using the recommended certbot client. Specifically, I’m going to be using certbot-auto, which will work on operating systems that don’t have an up-to-date version of certbot. The certbot client can use a few plugins to generate/install certificates. However, there are some known issues with the Nginx plugin, so I’m going to be using the webroot plugin instead (since I already have a webserver running).

Follow the instructions on certbot website, but below is what I’m using for Nginx on Ubuntu 14.04.

sudo mkdir /usr/local/bin/certbot-auto
cd /usr/local/bin/certbot-auto
sudo wget https://dl.eff.org/certbot-auto
sudo wget -N https://dl.eff.org/certbot-auto.asc
gpg --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2 --keyserver
gpg --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc certbot-auto
sudo chmod a+x certbot-auto
sudo /usr/local/bin/certbot-auto/certbot-auto


I’m going to run the following command, once for each domain I run on my server.

sudo /usr/local/bin/certbot-auto/certbot-auto certonly --webroot -w /var/www/wordpress/loganmarchione/ -d loganmarchione.com,loganmarchione.com --staple-ocsp --hsts --rsa-key-size 4096 -m myemail@email.com

The options I used are explained below.

certonly = obtain cert, but do not install it (since we’ll edit the Nginx configuration file manually)

–webroot = obtain cert by placing temporary files in an existing webroot directory (e.g., /var/www/wordpress/loganmarchione./well-known/)

-w = webroot path (e.g., /var/www/wordpress/loganmarchione)

-d = domain name (loganmarchione.com is different from loganmarchione.com, I recommend using both)

–staple-ocsp = enables OCSP Stapling (a valid OCSP response is stapled to the certificate that the server offers during TLS)

–hsts = add the Strict-Transport-Security header to every HTTP response (forcing browser to use always use SSL for the domain)

–rsa-key-size  = sets RSA set size (2048 by default)

-m = email used for registration and recovery contact

See the full list of command line options here.

Possible errors

When I ran the command above, I received the error below.

To fix these errors, please make sure that your domain name was
entered correctly and the DNS A record(s) for that domain
contain(s) the right IP address. Additionally, please check that
your computer has a publicly routable IP address and that no
firewalls are preventing the server from communicating with the
client. If you're using the webroot plugin, you should also verify
that you are serving files from the webroot path you provided.

This is because I don’t have a location block for certbot-auto to place temporary files in. From the documentation page:

The webroot plugin works by creating a temporary file for each of your requested domains in ${webroot-path}/.well-known/acme-challenge. Then the Let’s Encrypt validation server makes HTTP requests to validate that the DNS for each requested domain resolves to the server running certbot.

This is easy enough to fix. Just add a location block for .well-known in your Nginx configuration, as shown below.

location ~ /.well-known {


Then, restart Nginx.

sudo service nginx restart

Run the command again, and it should work.

 - Congratulations! Your certificate and chain have been saved at


All certificates are stored in /etc/letsencrypt/live/<your_domain_name>. For Nginx, you’ll need the following files:

  • privkey.pem = for the parameter ssl_certificate_key
  • fullchain.pem = for the parameter ssl_certificate
  • chain.pem = for the parameter ssl_trusted_certificate (for OCSP stapling)

See here for more details.

Nginx configuration

Now, we need to update our Nginx configuration with the new certificates.

ssl on;
ssl_certificate /etc/letsencrypt/live/loganmarchione.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/loganmarchione.com/privkey.pem;
ssl_buffer_size 1400;

#Enable SSL stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/loganmarchione.com/chain.pem;
resolver valid=300s;
resolver_timeout 5s;

Then, restart Nginx.

sudo service nginx restart

Check the certificate on your website and it should be using the new Let’s Encrypt certificate!


Certificate renewal

Let’s Encrypt certificates expire in 90 days. This is a short time, but it’s short in order to move users towards using automatic renewal. Luckily, certbot-auto has a built-in function to renew certificates expiring in 30 days or less. It’s important to note that this will renew all certificates on this server, not just for a specific website, then reload Nginx to pickup the changes.

sudo /usr/local/bin/certbot-auto/certbot-auto renew --post-hook "sudo service nginx reload"

Since the entire point is to automate this process, it’s best to run this out of crontab. It’s suggested to run this once a day, and at a random minute in the hour, so the CA isn’t as busy. Add the line below to root’s crontab for a daily renewal check at 06:14am.

14 06 * * * /usr/local/bin/certbot-auto/certbot-auto renew --post-hook "sudo service nginx reload" --quiet >> /var/log/certbot.log

This process will also check for updates to certbot-auto. If you’re not interested in that, see the full list of command line options here.


That’s it! Hopefully you can find Let’s Encrypt useful. Let me know how you use it on your site!



Leave a Comment