Back to Posts

Let's Encrypt for Rails on Ubuntu 16.04 with Nginx

Installing Let's Encrypt Certbot

1
2
3
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install certbot

Obtaining your SSL certificate with Webroot Plugin

With the Webroot plugin, we will need to have a public directory at yourdomain.com/.well-known

First go ahead and edit your nginx.conf file and add the following location block to your server block

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
  listen 80;
  listen [::]:80 ipv6only=on;

  server_name yourdomain.com;

  ...

  # You will want to add this location block
  location ~ /.well-known {
    allow all;
    root /usr/share/nginx/html;
  }
}

You will notice that /.well-known lives at Nginx' public root directory. This is to simply not create a custom route in Rails.

Run sudo nginx -t to test if your Nginx configuration has any errors.

If there are no errors, restart Nginx.

1
sudo service restart nginx

Create .well-known directory

1
mkdir /usr/share/nginx/html/.well-known

Generate your SSL certificate

1
sudo certbot certonly --webroot --webroot-path=/usr/share/nginx/html/ -d yourdomain.com -d www.yourdomain.com

We are also specifying the different domain names with the -d flag. So if you have domain name with an admin subdomain you would have the following -d example.com -d admin.example.com

Generate Strong Diffie-Hellman Group

1
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048

Configure SSL/TLS

Create a backup (recommended)

1
cp /etc/nginx/sites-available/your-site /etc/nginx/sites-available/your-site.bak

Edit your Nginx configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
server {
  listen 80;
  listen [::]:80 ipv6only=on;

  server_name your-domain.com;

  # You will want to redirect http traffic to https
  return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl default_server;
  listen [::]:443 ssl default_server;

  ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

  # from https://cipherli.st/
  # and https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html

  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
  ssl_ecdh_curve secp384r1;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off;
  ssl_stapling on;
  ssl_stapling_verify on;
  resolver 8.8.8.8 8.8.4.4 valid=300s;
  resolver_timeout 5s;
  # disable HSTS header for now
  #add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  ssl_dhparam /etc/ssl/certs/dhparam.pem;

  server_name yourdomain.com;

  ...
}

Save your changes and check your nginx configuration with:

1
sudo nginx -t

Restart nginx if there were no issues

1
sudo service restart nginx

Auto-renew Let's Encrypt Certificate

Because Let's Encrypt certificates only last for three months, we will setup a cron task that runs the renew task from certbot everyday.

1
sudo crontab -e

Add the following line at the end of your contrab file.

1
15 3 * * * /usr/bin/certbot renew --quiet --webroot-path=/usr/share/nginx/html/ --renew-hook "/bin/systemctl reload nginx"