Zac Fukuda
016

Let’s Encrypt - Ubuntu 14.04, Nginx, and the Standalone

Although the security is a vital issue for the website operation, it costs you so much. Well, it did once, but now it's free. About a month ago, I enabled HTTPS on my website using Let’s Encrypt.

This article is a note of the process I took to enable HTTPS with Let’s Encrypt. In order to let you know whether this note is for you, I'll give my whole situation first.

  • OS: Ubuntu 14.04
  • Server: Nginx
  • Running HHVM & Node apps, with different domain for each
  • Not mind if the sites being stopped for a few minutes while obtaining certificates.

Note: Since I didn't mind if the sites were stopped during the process, I used the standalone feature of Cerobt ACME client to get the certificates, whereas I guess most people use Webroot plugin. The whole processes are pretty much same for both cases. But if you are looking for the way in the case of Webroot, I recommend you to stop reading, or just pick the common processes and read them. If you also don't mind if your website will be stopped during the process, the standalone way is easier.

Resources

I represent the resources that I used on the process.

The Steps

  1. Open Firewall with iptables
  2. Install Cerbot & Obtain Certs
  3. Configure Nginx
  4. Automating Renewal

Open Firewall with iptables

The first thing to do is to open the Firewall port 80 & 443 so that Cerbot can obtain the certificates through those ports. Please execute the following commands in the bash:

sudo iptables -A INPUT -p tcp -m tcp --sport 80 -j ACCEPT
sudo iptables -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp -m tcp --sport 443 -j ACCEPT
sudo iptables -A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT

You can check whether the ports are successfully opened by doing sudo iptables -L command.

By default, the ports that you just opened will close again on reboot. So we need to add the start-up configuration. Let's save your current Firewall rules to a file:

sudo sh -c "iptables-save > /etc/iptables.rules"

Configuration on start-up:

sudo vi /etc/network/if-pre-up.d/iptablesload

Inside the iptablesload writes as follow:

#!/bin/sh
iptables-restore < /etc/iptables.rules
exit 0

Create one more file:

sudo vi /etc/network/if-post-down.d/iptablessave

Inside of iptablessave is as follow:

#!/bin/sh
iptables-save -c > /etc/iptables.rules
if [ -f /etc/iptables.downrules ]; then
   iptables-restore < /etc/iptables.downrules
fi
exit 0

Make sure to give the scripts the execute permissions:

sudo chmod +x /etc/network/if-post-down.d/iptablessave
sudo chmod +x /etc/network/if-pre-up.d/iptablesload

Install Cerbot & Obtain Certs

Installation

After opening the ports, you are ready to obtain certificates. Now let's install Cerbot client.

cd /usr/local/sbin
sudo wget https://dl.eff.org/certbot-auto
sudo chmod a+x /usr/local/sbin/certbot-auto

The commands above will install certbot-auto inside /usr/local/sbin so that we can access to it by simply typing certbot-auto.

Before going any further, don't forget to stop the webserver.

sudo service nginx stop
Obtain Certs

I needed to obtain two certificates for two different domains. If you also want two certificates, please execute the following commands:

certbot-auto certonly --standalone -d example.com -d www.example.com
certbot-auto certonly --standalone -d foobar.me -d www.foobar.me

The obtaining process may take 2–3 minutes and you have to fill in your contact information. If the process was successful, you get the output message.

Note: It is possible to obtain a certificate for two domains at once. Nevertheless, when I tried this, Cerbot combined the two domain certificates into one cert file with the name of the domain declared first in the command. So, if you want the certificates for two domains and to split them, I suggest you to do the command one by one.

You can see if the certs files are saved by:

sudo ls /etc/letsencrypt/live/

After obtaining the certificates, be quick to restart your webserver.

sudo service nginx start

Configure Nginx

Now it is time to enable the SSL on the server. Just in case, before redirecting all the traffic to https, let's first accept both accesses, and after you confirm that the https access is working properly, then redirect to https.

# conf files might be located in the different place in the other version.
sudo vi /etc/nginx/conf.d/example.conf

The beginning of the inside of server {} looks like this:

    listen 80;
    listen 443 ssl;
    server_name  www.example.com;

    # SSL
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    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:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

After saving the conf file, see if the configuration is correct.

sudo nginx -t

If there is no problem, restart the webserver.

sudo service nginx restart

If it is necessary to modify your web application to adapt https, do it this timing. If your application is now ready, let's redirect all traffic to https. In order to do that you have to create two server{} blocks. The conf file will look like this:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name  www.example.com;
    …
}

Now if you restart to the webserver, all traffics to your website will be via https.

Automating Renewal

The Cerbot comes with a very rich feature to renew your certificates automatically before they expire. Let's Encrypt certificates last for only 90 days. Hence we need to setup an automatic renewal. I'm going to show you how to renew your certificates every month, that said every first day of the month.

First, let's test automatic renewal for your certificates by running this command:

certbot-auto renew --dry-run

If that is appeared to be correct, now create an automatic renewal program by adding a cron job:

sudo crontab -e

Add the following lines and save:

30 2 1 * * /usr/local/sbin/certbot-auto renew >> /var/log/le-renew.log
35 2 1 * * /etc/init.d/nginx reload

The commands above will renew your certificates at 2:30 am on the first day of the month, and then reload Nginx configuration at 2:35 am. If you are interested in how to use cron, Digital Ocean has a nice tutorial for that.