HTTPS with Let’s Encrypt SSL and Nginx (using certbot)

A few days ago I enabled HTTPS and SSL/TLS on this blog. A big barrier to enabling SSL on your website is the cost of the SSL certificate and the maintenance overhead of having to constantly renew your certificate. You could already get free SSL certificates with StartSSL, but the process of obtaining the certificate is still a manual process. A few months ago Mozilla and a bunch of companies came together and created Letsencrypt, a service which issues free SSL certificates that are automatically generated with a command line tool. When set up correctly, it alleviates the need for manual intervention. As of the writing of this blog post, the service is still in beta and support for Nginx is minimal, but it’s not difficult to set up.

Since the software is still in beta, the only way to get it is via letsencrypt github. First we need to pull the repository:

Update 15/05/2016 – previously named letsencrypt-auto, the certificate utility is now called certbot-auto

$ wget https://dl.eff.org/certbot-auto
$ chmod a+x ./certbot-auto

We then get the certbot-auto executable. Running ./certbot-auto --help will give you the available commands. The current version has built in support for Apache, with nginx under testing. But as long as we get the certificate, we could install it to any software supported or not. I will illustrate the (initially) manual way of getting the certificate with nginx.

Obtaining the certificate from Let’s Encrypt

To obtain a certificate, ownership of the domain needs to be verified. Letsencrypt achieves this by checking for the contents of a file under http://www.example.com/.well-known/acme-challenge/. There are two ways given by certbot-auto to make this file available – by spawning a standalone server to listen on port 80 (--standalone), or by adding the files to the root folder of the web site (--webroot). The problem with standalone is that you have to stop your active web server on port 80, causing downtime, where as webroot allows your current server to continue operating. So webroot is the solution we will use.

Obtain a certificate with webroot, by calling this command (replacing example.com and /var/www/example obviously!). You can append more domains with -d.

./certbot-auto certonly --webroot -w /var/www/example -d example.com -d www.example.com

The above method requires you to have a physical root folder. If you are using nginx as a load balancer or reverse proxy (i.e. proxy_pass), you most likely won’t have a root for your domain. In those cases, you could add a location alias to your nginx.conf under the HTTP (port 80) server directive for the domain:

  location /.well-known {
    alias /var/www/html/.well-known;
  }

Then run:

./certbot-auto certonly --webroot -w /var/www/html -d example.com -d www.example.com

The first time you run certbot, it will ask you to agree to the TOS and register your email. After that, the operation is pretty much unattended.

After the command finishes, you should have your certificate at /etc/letsencrypt/live/example.com/fullchain.pem and private key at /etc/letsencrypt/live/example.com/privkey.pem

Install the certificate into nginx

Modify you nginx configuration file to enable SSL:

server {
        listen 443 ssl;
        server_name example.com;
        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}

You may also want to add Strict-Transport-Security (HSTS) to your config, such that any internal links that are not https will automatically be routed to the HTTPS version during a HTTPS session.

        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

Lastly, reload the nginx configuration:

sudo service nginx reload

Auto-renewing the certificate

Let’s Encrypt certificates are only valid for 3 months after issue. So every 3 months, renewal is required. Since the process of obtaining the certificate is through the command line, this process could be automated. We could set up a cron job which takes care of the renewal, like the below:

0 6 * * * /path/to/certbot/certbot-auto renew --text >> /path/to/certbot/certbot-cron.log && sudo service nginx reload

The above cron job is set up to run daily, but the certificate is only renewed if less than 30 days to expiry.

7 thoughts on “HTTPS with Let’s Encrypt SSL and Nginx (using certbot)

  1. Pingback: Update Letsencrypt to Certbot on Nginx and Ubuntu – nwlinux

  2. Matt Withoos

    Thanks for sharing this. It seems NGINX advocates are forced to take a backseat for a lot of web/open-source libraries/projects so this post was really useful. ?

  3. Francesco Vanduynslager

    Hi thnx for the tutorial. Is it me or “sudo service reload nginx” should be “sudo service nginx reload”? On my machine only the latter one works

  4. Loune Post author

    @Francesco thanks for picking that up. Yes it should be “sudo service nginx reload”. I’ve fixed it now.

  5. Pingback: Free HTTPS certificates with Let’s Encrypt on your Amazon EC2 NGINX box – Darurats

Leave a Reply

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