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.
links: https://loune.net/2016/01/https-with-lets-encrypt-ssl-and-nginx/