Repository navigation
letsencrypt runbook
In this section I will explain how to setup and maintain (obtain and renew) SSL Certificates from Let's Encrypt, on my Raspberry Pi running Raspbian 8 (jessie) and Nginx 1.10.x .
Since LetsEncrypt has been launched its public beta in december 2015, many LetsEncrypt implementations of the ACME protocol have been developed and are now available to simplify the process.
Since I was using it from the beta, I started with the official letsencrypt client which became certbot, and does the job pretty well.
- nginx-runbook
- Update your DNS records (A or CNAME) to point to your raspberry pi public/nat IP address.
Since Certbot is packaged for debian 8 (jessie), all you'll need to do is apt-get the following packages.
First you'll have to follow the instructions here to enable the Jessie backports repo, if you have not already done so. Then run:
sudo apt-get install certbot -t jessie-backports
Since nginx plugin was not embeded before 0.9.0 version of Certbot, I used the Webroot plugin method which will process to the validation by making available ACME files to LetsEncrypt CA to confirm you are the owner of the website. This method is preferred to the standalone method server which requires you to temporarily stop nginx.
We assume we have already nginx webserver running.
I followed the documentation from Certbot with Webroot plugin and the nginx documentation from https://www.nginx.com/blog/free-certificates-lets-encrypt-and-nginx/, but with a few changes:
To obtain a cert using the "webroot" plugin, we will setup a server directory for nginx to serve the acme files.
In my installation I chose /web/letsencrypt/www.
$ cd /var/www
$ mkdir letsencrypt
$ sudo chgrp www-data letsencryptThen in theory requesting a certificate can be achieved through the command line:
sudo certbot certonly --webroot -w /web/letsencrypt/www -d mydomain.jp -d www.mydomain.jp
This command will obtain a single cert for mydomain.jp, www.mydomain.jp; it will place files below /web/letsencrypt/www to prove control of the domain.
HOWEVEVER, to use the webroot plugin, nginx server must be configured to serve files from hidden directories.
The Let’s Encrypt client (Certbot) creates a temporary file in webroot-path/.well-known/acme-challenge/ containing the token used by the Let’s Encrypt server to verify that you own the domain you are attempting to get a free ssl certificate for. The webroot‑path in my case is /web/letsencrypt/www.
This part slightly differs from the nginx documentation above and follow this on https://community.letsencrypt.org/t/how-to-nginx-configuration-to-enable-acme-challenge-support-on-all-http-virtual-hosts/5622/3
I created a global configuration file letsencrypt.conf which will be included in each server definition:
/etc/nginx/global/letsencrypt.conf
#############################################################################
# Configuration file for Let's Encrypt ACME Challenge location
# This file is already included in listen_xxx.conf files.
# Do NOT include it separately!
#############################################################################
#
# This config enables to access /.well-known/acme-challenge/xxxxxxxxxxx
# on all our sites (HTTP), including all subdomains.
# This is required by ACME Challenge (webroot authentication).
# You can check that this location is working by placing ping.txt here:
# /var/www/letsencrypt/.well-known/acme-challenge/ping.txt
# And pointing your browser to:
# http://xxx.domain.tld/.well-known/acme-challenge/ping.txt
#
# Sources:
# https://community.letsencrypt.org/t/howto-easy-cert-generation-and-renewal-with-nginx/3491
#
#############################################################################
# Rule for legitimate ACME Challenge requests (like /.well-known/acme-challenge/xxxxxxxxx)
# We use ^~ here, so that we don't check other regexes (for speed-up). We actually MUST cancel
# other regex checks, because in our other config files have regex rule that denies access to files with dotted names.
location ^~ /.well-known/acme-challenge/ {
# Set correct content type. According to this:
# https://community.letsencrypt.org/t/using-the-webroot-domain-verification-method/1445/29
# Current specification requires "text/plain" or no content header at all.
# It seems that "text/plain" is a safe option.
default_type "text/plain";
# This directory must be the same as in /etc/letsencrypt/cli.ini
# as "webroot-path" parameter. Also don't forget to set "authenticator" parameter
# there to "webroot".
# Do NOT use alias, use root! Target directory is located here:
# /var/www/common/letsencrypt/.well-known/acme-challenge/
root /var/www/letsencrypt;
}
# Hide /acme-challenge subdirectory and return 404 on all requests.
# It is somewhat more secure than letting Nginx return 403.
# Ending slash is important!
location = /.well-known/acme-challenge/ {
return 404;
}
and this configuration is included under each server section (domain and sub-domains) of my site: /etc/nginx/sites-available/chococlub.jp
Verify the configuration file is syntactically valid and restart NGINX:
$ sudo nginx -t && sudo nginx -s reload
As per the documentation I chose to create a template file with the values that Certbot needs to issue a certificate. With the template, we don't have to specify the values on the Certbot command line. Template file must be stored under /etc/letsencrypt/configs/ the filename must be mydomain.jp
The template file I used for my domain chococlub.jp : /etc/letsencrypt/configs/chococlub.jp
The template file I used for my domain severin.jp : /etc/letsencrypt/configs/severin.jp.jp
Now that everything is set up we request the certificate. The highlighted message confirms that we successfully obtained a certificate and associated files for NGINX, which Let’s Encrypt stores in /etc/letsencrypt/live/my-domain. The files of interest are fullchain.pem and privkey.pem.
$ sudo certbot certonly --config /etc/letsencrypt/configs/chococlub.jp
not tested yet.
To obtain a cert using a built-in “standalone” webserver (you may need to temporarily stop your existing webserver, if any) for example.com and www.example.com:
$ sudo certbot certonly --standalone -d example.com -d www.example.com
Add the certificate and key to the server block for HTTP traffic:
see /etc/nginx/sites-available/chococlub.jp
##
# Root Site : HTTPS : chococlub.jp
##
server {
listen 443; ## listen for ipv4; this line is default and implied
#listen [::]:443 default_server ipv6only=on; ## listen for ipv6
# Get SSL setup
ssl on;
ssl_certificate /etc/letsencrypt/live/chococlub.jp/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chococlub.jp/privkey.pem;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:50m;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
# Generate with:
# openssl dhparam -out /etc/nginx/dhparam.pem 2048
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
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:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-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:!KRB5-DES-CBC3-SHA';
ssl_prefer_server_ciphers on;
# Enable HSTS ( see http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security ) (ngx_http_headers_module is required) (15768000 seconds = 6 months)
add_header Strict-Transport-Security max-age=15768000;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/chococlub.jp/fullchain.pem;
resolver 8.8.8.8;
### NOW CONFIGURE YOUR SITE BELOW
...
}
Verify the configuration file is syntactically valid and restart NGINX to load the new certificates:
$ sudo nginx -t && sudo nginx -s reload
The Certbot packages on your system come with a cron job that will renew your certificates automatically before they expire. Since Let's Encrypt certificates last for 90 days, it's highly advisable to take advantage of this feature. You can test automatic renewal for your certificates by running this command:
sudo certbot renew --dry-run
If that appears to be working correctly, you can arrange for automatic renewal by adding a cron or systemd job which runs the following:
certbot renew
You will need to run renew with sudo/root privileges since the private keys are stored in protected location.
In my environment I am using the following script which is executed by cron job. it will reload nginx if renew is a success.
#!/bin/sh
cd /opt/letsencrypt/
./certbot renew --post-hook "service nginx reload"
if [ $? -ne 0 ]
then
ERRORLOG=`tail /var/log/letsencrypt/letsencrypt.log`
echo -e "The Let's Encrypt cert has not been renewed! \n \n" \
$ERRORLOG
fi
exit 0and the root user's crontab
sudo crontab -u root -l
will run every 7th day of the week at 3:30am
30 3 * * 7 /home/severin/cron/renew-letsencrypt.shI found that actually the certbot installation script configured automatically a cron task. so you might not have to do it by yourself.
$ cat /etc/cron.d/certbot
# /etc/cron.d/certbot: crontab entries for the certbot package
#
# Upstream recommends attempting renewal twice a day
#
# Eventually, this will be an opportunity to validate certificates
# haven't been revoked, etc. Renewal will only occur if expiration
# is within 30 days.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew