Using Let’s Encrypt SSL certificates to get an A+ rating with nginx

Recorded on December 7th, 2015

Browser makers and technology firms have increasingly focused on improving the encryption and privacy of communications on the Web. Google, for example, has turned HTTPS on by default, uses whether a site offers HTTPS as a positive signal for search ranking, and has started displaying error messages for sites that use older encryption standards for their certificates.

Lets Encrypt aims to remove the technical and financial hurdles for website administrators that continue to balk at offering secure HTTP for every site visitor. Even technically savvy workers who frequently manage websites have trouble configuring their servers to properly serve secure HTTP.

Last year, the Electronic Frontier Foundation, Mozilla, Cisco, Akamai, and IdenTrust announced the formation of Let’s Encrypt, a new certificate authority created to remove the barriers preventing widespread adoption of HTTPS. They hope to simplify the entire certificate process and reduce setup time to 20-30 seconds through their Let’s Encrypt Client, a tool that uses the ACME (Automated Certificate Management Environment) protocol.


The Let’s Encrypt client supports a number of different plugins that can be used to obtain and/or install certificates. Plugins that can obtain a cert are called “authenticators” and can be used with the “certonly” command. Plugins that can install a cert are called “installers”. Plugins that do both can be used with the “letsencrypt run” command, which is the default.

For example, there’s an Apache plugin that’ll both “authenticate” you as the holder of a specific domain as well as “install” the certificate in your Apache configuration files - effectively reducing the amount of effort you have to take to get SSL up and running to a few seconds at most.

The nginx plugin supports both authentication and installation, but it was a bit too beta for me to want to run it on my server. Instead I opted to go for the webroot plugin, which obtains a certificate by writing to the webroot directory of an already running webserver.

Installing the Let’s Encrypt client

Let’s Encrypt recommends cloning the client repository to get started. You’ll need to install git if you don’t have it already.

sudo apt-get update sudo apt-get install git git clone cd letsencrypt

You’re now ready to use letsencrypt-auto, which is the recommended method of running the Let’s Encrypt client beta releases on systems that don’t have a packaged version. There’s no need to run the command with sudo, instead just run it with your regular permissions. The client will prompt you when it needs additional permissions.

Getting our first certificate

If you’re running a webserver that you don’t want to stop to use standalone or you’re like me and you don’t quite trust the beta state of the automated nginx installation then you can use the webroot plugin to obtain a cert by including certonly and —webroot on the command line. In addition, you’ll need to specify —webroot-path or -w with the root directory of the files served by your webserver. For example, —webroot-path /var/www/html or —webroot-path /usr/share/nginx/html are two common webroot paths.

If you’re getting a certificate for many domains at once, each domain will use the most recent —webroot-path. Remember that wildcard certs are not supported by Let’s Encrypt, so get both the www and non-www certs for your domain.

letsencrypt certonly --webroot -w /var/www/sites/ -d -d

Setting up multiple domains at the same time is no problem with the Let’s Encrypt client, just format your command something like this:

letsencrypt certonly --webroot -w /var/www/example/ -d -d -w /var/www/eg -d -d

This would obtain a single certificate for all of those names, using the /var/www/example webroot directory for the first two, and /var/www/eg for the second two.

Note that to use the webroot plugin, your server must be configured to serve files from hidden directories. The client puts a file inside that hidden directory, which is used by the Let’s Encrypt platform to check if you’re in charge of the domain.

Let’s Encrypt will place symlinks to the certificate, chains, and private key in /etc/letsencrypt/live/ (where ‘’ is replaced with your domain, of course), ready to be included into your nginx configuration.

It’s important to remember that Let’s Encrypt CA issues short lived certificates (90 days), so make sure you renew the certificates at least once in 3 months.

Setting up nginx

If you’re starting from scratch, Mozilla has a great SSL configuration generator that should save you a ton of time. I’m using the following one in combination with the Let’s Encrypt certificate.

server { listen 443 ssl spdy; ssl_certificate /etc/letsencrypt/live/; ssl_certificate_key /etc/letsencrypt/live/; ssl_session_timeout 1d; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits # openssl dhparam -out dhparam.pem 2048 ssl_dhparam /etc/nginx/dhparam.pem; 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 --- 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/; resolver valid=86400; resolver_timeout 10; # Rest of your webserver configuration follows below here #... }

Is this thing still alive?

Recorded on November 29th, 2015

I do believe it’s about time to reactive this personal blog, after mostly sticking to Twitter and Facebook over the last couple of years.