Home

Setting up a Let's Encrypt Certificate

Raspbian 8 (Debian Jessie) and nginx

Let's Encrypt is a "free, automated, and open certificate authority (CA), run for the public’s benefit" with the goal of enabling "HTTPS (SSL/TLS) for websites, for free, in the most user-friendly way."

I've been wanting to set my site up with SSL for a long time and with Let's Encrypt I finally can with ease. This post covers the steps I took to get it working on my Raspberry Pi with Raspbian 8 (Debian Jessie).

I followed the guide by Digital Ocean so this is more of a record of my experience setting this up, rather than a general tutorial covering different situations.

Installing and Setting up Certbot

Certbot wasn't available when Jessie was released so first I had to enable the Jessie backports repository to install the new package.

$ echo 'deb http://ftp.debian.org/debian jessie-backports main' | sudo tee /etc/apt/sources.list.d/backports.list

$ sudo apt-get update

Running the previous command returned:

W: GPG error: ftp://ftp.nl.debian.org jessie-backports InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 8B48AD6246925553 NO_PUBKEY 7638D0442B90D010

I had to add the GPG keys to be able to verify packages.

$ gpg --keyserver pgpkeys.mit.edu --recv-key 8B48AD6246925553

$ gpg --keyserver pgpkeys.mit.edu --recv-key 7638D0442B90D010

I can finally install certbot.

$ sudo apt-get install certbot -t jessie-backports

Obtaining the SSL Certificate

I used the Webroot plugin to get the SSL Certificate. The plugin places a special file in the /.well-known directory of the web server which is accessible by the Let's Encrypt service for validation.

I edited the nginx configuration to make sure the /.well-known folder would be accessible. The following was added to the server block.

$ sudo vim /etc/nginx/sites-available/imadm.ca

location ~ /.well-known {
	allow all;
}

Then test the config with

$ sudo nginx -t

If the configuration is okay, restart nginx with

$ sudo service nginx restart

The next command will start the process for obtaining the certificate. Two things need to be known, first is the web root, which in my case is /home/pi/www/imadm.ca, and the domain names I want to get certificates for, which in this case are imadm.ca, www.imadm.ca, and git.imadm.ca.

$ sudo certbot certonly -a webroot --webroot-path=/home/pi/www/imadm.ca -d imadm.ca -d www.imadm.ca -d git.imadm.ca

The previous command will produce four certificate files in /etc/letsencrypt/archive with symlinks pointing to them from /etc/letsencrypt/live/imadm.ca. These files are:

Next a strong Diffie-Hellman group is generated to increase security.

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

Configuring nginx

I made a couple of snippets to keep the ssl configuration neat and modular. One snippet, ssl-imadm.ca.conf, will set the ssl_certificate directives. The second, ssl-params.conf will set the ssl configuration.

$ sudo vim /etc/nginx/snippets/ssl-imadm.ca.conf

ssl_certificate /etc/letsencrypt/live/imadm.ca/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/imadm.ca/privkey.pem;

$ sudo vim /etc/nginx/snippets/ssl-params.conf

# 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 preloading HSTS for now.  You can use the commented out header line that includes
# the "preload" directive if you understand the implications.
#add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
add_header Strict-Transport-Security "max-age=63072000; includeSubdomains";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

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

Finally, the nginx configuration file for the domain is updated to have HTTP redirect to HTTPS and an SSL server block is added.

$ sudo vim /etc/nginx/sites-available/imadm.ca

server {
  listen *:80;
  listen [::]:80;
  server_name imadm.ca www.imadm.ca;
  return 301 https://$server_name$request_uri;
  root /home/pi/www/imadm.ca;
  index index.html;

  location ~ /.well-known {
	allow all;
  }
}

server {
  # SSL configuration

  listen 443 ssl default_server;
  listen [::]:443 ssl default_server;
  include snippets/ssl-imadm.ca.conf;
  include snippets/ssl-params.conf;

  server_name imadm.ca www.imadm.ca;
  root /home/pi/www/imadm.ca;
  index index.html;

  location ~ /.well-known {
	allow all;
  }
}

Auto-renew Certificate

These certificates are valid for one month. Let's Encrypt will send a renewal reminder email to the email provided in the certbot step. But it's also possible to just have the renewal command run often and automatically renew when needed.

$ sudo crontab -e

30 2 * * * /usr/bin/certbot renew --noninteractive --renew-hook "/bin/systemctl reload nginx" >> /var/log/le-renew.log

This line will run the certbot renewal command at 2:30 am daily and will reload nginx if renewed.