Let’s Encrypt SSL Certificates and Nginx

Using the Let's Encrypt beta client for certificate generation with Nginx.

HTTPS and Encryption by Default

Encryption by default has become the new standard for web applications and many of the world’s top busiest sites have already made the switch to serving content via HTTPS. Google is no stranger to encryption, having made HTTPS the default for many of their apps long before it was cool, and just last year announcing the use of HTTPS as a rankings signal. Over the past few years, organizations like Facebook, Wikipedia, and the Federal CIO Council have shown that properly switching to HTTPS is no longer the performance hit it used to be, with many taking the next step by implementing HTTP Strict Transport Security (HSTS).

Barriers to HTTPS: Certificate Authorities

Until relatively recently, implementing HTTPS without subjecting users to browser warnings meant having to to pay a certificate authority (CA) to formally issue a certificate. With the cost of these certificates easily exceeding what many individuals would pay for domain registration and hosting, the likelihood of widespread adoption plummets. Lately SSL certificates have become much more affordable, and class 1 certificates could be obtained free of charge from StartCom provided you were willing to navigate their awkward interface and validation process.

Let’s Encrypt

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. I’ve been following their progress eagerly, and just last week I received an invitation to their closed beta, allowing me to finally issue trusted certificates for a handful of domains they whitelisted for me.

Let’s Encrypt SSL Certificates and Nginx
Client Installation

Based on my initial experience with the Let’s Encrypt Client, it seems there is still a lot of work to be done in order to achieve the goal of validating, issuing, and installing certificates in 30 seconds. The client works well for validating and issuing certificates once you understand the assumptions made. The Nginx installer is flagged as under development, and within the client you are warned that it does not work yet. If you have a non-standard Nginx configuration, you may end up with a jumbled mess by using the installer. 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 https://github.com/letsencrypt/letsencrypt
cd letsencrypt

From here you can run letsencrypt-auto, a wrapper that handles OS-specific dependencies in a Python virtual environment. Rather than running the command with sudo, run it with your normal permissions. It will prompt you when it needs additional permissions. By default, the server is set to the staging/testing URL, but in this example I’m using production. Including auth causes the client to obtain the certificate but not install it.

Production Client

./letsencrypt-auto --agree-dev-preview --server \
    https://acme-v01.api.letsencrypt.org/directory auth


Using beta of letsencrypt-auto on Ubuntu.
Account Email


Account Email

The client then starts to install dependencies and set up the environment. If all goes well, you’re asked for an email address for notices and key recovery. There didn’t seem to be any email validation when I used it, but I’d suggest using a real address. I’m assuming they’ll add some sort of validation in the future to deter abuse.


Using beta of letsencrypt-auto on Ubuntu.
Terms of Service



Terms of Service

You’ll be prompted to review the Terms of Service. A link to the terms you’re agreeing to is added to your account metadata in /etc/letsencrypt/accounts/.



Using beta of letsencrypt-auto on Ubuntu.
Specify Domains



Specify Domains

Since we’re not using an installer, you’re prompted to enter the domains you’d like to use by hand separated by commas or spaces. Domains can also be specified from the command in with -d DOMAIN.


Automation isn’t there yet

Let’s Encrypt strongly recommends using the letsencrypt-auto method, but as of version 0.0.0.dev20151030 (on Ubuntu 14.04.3 with Nginx 1.8.0), it requires a bit of manual intervention. After specifying your domains, Let’s Encrypt attempts to authenticate by using listening on port 80 which is almost certainly in use.

The program nginx (process ID 1196) is already listening on TCP port 80. This will prevent us from binding to that port. Please stop the nginx program temporarily and then try again.

At least one of the (possibly) required ports is already taken.

I’m sure this could fixed by editing the client settings or choosing a particular authenticator. But after digging through the GitHub issues for a while, it doesn’t seem like the creators know what the “right way” should be. Since these certificates are only good for three months, and the automated renewal process isn’t quite there given that this is beta, stopping Nginx temporarily isn’t a big deal this time if it means getting certificates issued.

sudo service nginx stop
./letsencrypt-auto --agree-dev-preview --server \
    https://acme-v01.api.letsencrypt.org/directory auth

This time the certificate was successfully created and placed in /etc/nginx/live/example.com/

– Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/rudeotter.com/fullchain.pem. Your cert
will expire on 2016-01-31. To obtain a new version of the
certificate in the future, simply run Let’s Encrypt again.

For now, the Nginx server blocks can just be configured manually. Go ahead and restart Nginx.

sudo service nginx start

Let’s Encrypt placed symlinks to the certificate, chains, and private key in /etc/letsencrypt/live/rudeotter.com — cert.pem chain.pem fullchain.pem privkey.pem. These can be plugged directly into Nginx configuration.

If you’re starting from scratch, Mozilla has a great SSL configuration generator. Here’s one using the Let’s Encrypt certificate.

server {
    listen 443 ssl spdy;
    listen [::]:443 ssl spdy;
    ssl_certificate /etc/letsencrypt/live/rudeotter.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/rudeotter.com/privkey.pem;;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    # openssl dhparam -out dhparam.pem 2048
    ssl_dhparam /etc/nginx/dhparam.pem;

    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;

    add_header Strict-Transport-Security max-age=15768000;

    ssl_stapling on;
    ssl_stapling_verify on;

    ## verify chain of trust of OCSP response using Root CA and Intermediate certs
    #ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
    ssl_trusted_certificate /etc/letsencrypt/live/rudeotter.com/chain.pem;
    resolver valid=86400;
    resolver_timeout 10;

16 responses to “Let’s Encrypt SSL Certificates and Nginx”

    • You can actually just use /etc/letsencrypt/live/example.com/chain.pem. To test it, you can use openssl s_client -connect example.com:443 -servername example.com -status < /dev/null.

      The first SSL connection handled by each Nginx worker process won't have a OCSP response but just try again. You may have to try a few times depending on the value of worker_processes in nginx.conf.

  1. How do I navigate to or complete the last step to edit the Nginx configuration? Am I supposed to be SSH’d into my server?

    • The last step requires actually being able to edit the Nginx configuration files. This would generally be done via SSH. I’m assuming that’s how most people log in and do the initial steps as well.

      Depending on your version (and the package maintainers), the files you would want edit would be in /etc/nginx/sites-available/ or /etc/nginx/conf.d/.

  2. Hi, thanks for your post.
    I met the issue like following below:
    Failed authorization procedure. myurl.com (http-01): urn:acme:error:connection :: The server could not connect to the client for DV :: DNS query timed out

    What is DV and why DNS query timed out? I’m sure the DNS is fine. I have checked the DNS records from https://www.whatsmydns.net, all green.

    I’m using Azure now. I have already open 80 & 443 for http & https. Do I need to open another ports?

    • I believe DV is Domain Validation. I’d check to make sure the all domains you’re including resolve to the machine’s IP and try again.

      If you’re using CloudFlare or a similar CDN or firewall, you may need to turn it off in order to have a certificates issued.

    • Also, this post is referencing an older version of the beta client. It looks like this is now their suggested way to request using a standalone web server. They don’t appear to be suggesting the Nginx plugin or include it in letencrypt-auto.
      ./letsencrypt-auto certonly -a standalone -d example.com -d www.example.com

      This is still in beta and is actively being developed so things will continue to change for a while.

  3. Hello. Thanks for the post, also great Nginx conf!

    Is there a way to implement authority check without stopping Nginx? Can I implement that in my own app?

    Thanks in advance.

    • If you’re running a webserver that you don’t want to stop to use standalone, 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.


      I haven’t experimented with this myself yet.

  4. ” It’s alive it’s alive ”
    I can’t find words to thank you enough , you saved me hours and hours searching .
    even Letsencrypt didn’t helped me at all , they should reffere your tutorial on thier doc BTW .
    My certificate are running with no issue even IE accepted it .

  5. I cant figure this out (and now I feel dumb). I am running nginx on ubuntu 14.04 I am just using default for my conf since I only have one IP going to domain. Unfortunately I propagated first to cloudflare, I was able to create my certs and key, however, when I add this to the default file nothing happens. I even changed cloud flare to strict.. Still nothing… Please help Ive spent two days on this and I simply cant figure it out

  6. For newer versions of nginx (>1.9.x , e.g: Ubuntu nginx development ppa), it’s suggested to use “http2” instead of “spdy” in nginx configuration. With the word spdy it gave me error. Googling let me to use http2 word instead.

    So these lines:

    listen 443 ssl spdy;
    listen [::]:443 ssl spdy;

    should be

    listen 443 ssl http2;
    listen [::]:443 ssl http2;


    • I seem to recall Google saying SPDY was on the way out and wouldn’t be supported in newer Chrome versions. HTTP2 is definitely the way to go if you’re using a newer version of Nginx that supports it.

  7. […] Let’s Encrypt SSL Certificates and Nginx […]

Leave a Reply

Your email address will not be published. Required fields are marked *