I’ve replaced the certificate on this site with one issued by Let’s Encrypt and plan to do so for all clients (or enable SSL in the first place) as their domains come up for renewal, or other maintenance work is contracted. The big downside is a 90 day expiry time, which requires a service nginx reload
at least that often.
I had no end of issues using the official client as it wouldn’t create the .well-known/acme-challenge
files necessary to get the domain to validate (yes, I checked directory permissions.) Instead, Vincent Composieux has some excellent instructions on just using the certonly
parameter inside a script.
Rundown, including my changes in case the article disappears:
- clone letsencrypt repository to
/opt/letsencrypt
- create
/usr/local/etc/le-example.com-webroot.ini
:
# We use a 4096 bit RSA key instead of 2048 rsa-key-size = 4096 email = email@example.org domains = example.com, www.example.com authenticator = webroot # This is the webroot directory of your domain in which # letsencrypt will write a hash in /.well-known/acme-challenge directory. webroot-path = /var/www/example.com/
- Update the separate
ssl.conf
that gets included as part of my nginx site template (and referenced by webcreate.sh) to reference the acme-challenge directory. This is/etc/nginx/global/ssl.conf
:
ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:50m; ssl_dhparam /etc/ssl/dhparams.pem; 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'; if ($myroot = false) { set $myroot $realpath_root; } location '/.well-known/acme-challenge' { root $myroot/; try_files $uri /$1; }
- For each site in
/etc/nginx/sites-enabled
, update the SSL definition to store the webroot in the$myroot
variable, then have the root directive (andssl.conf
) reference it:
server { listen 443 ssl; server_name example.com www.example.com; # [...] set $myroot /var/www/example.com; root $myroot; include global/ssl.conf; # [...] }
- Create the certificate:
sudo /opt/letsencrypt/letsencrypt-auto certonly --config /usr/local/etc/le-example.com-webroot.ini
- Add the certificate paths to each site in
sites-enabled
:
server { # [...] include global/ssl.conf; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # [...] }
service nginx reload
- Ensure ‘bc’ is installed on the system (
apt-get install
…) - Create and
chmod +x /usr/local/bin/renew-certificates.sh
(this file properly belongs in/usr/local/bin
) from original post or https://github.com/jbillo/scripts/blob/master/renew-certificates.sh
- To automatically renew certificates 30 days before expiry, checking each day:
ln -snf /usr/local/bin/renew-certificates.sh /etc/cron.daily/renew-certificates.sh
Some adjustments are obviously necessary for multiple sites but this got me past the point where site validation failed.