A Simple Setup and Installation Script for Let's Encrypt SSL Certificates
The Let's Encrypt initiative is one of the reasons why nobody will ever have to spend a dime on an SSL certificate ever again. There is certainly a role in the marketplace for paid validation, via organizations that provide the service of verification of claims, alongside a way to establish just who has and has not been verified. That could overlap usefully with browser encryption on the web, but the way it worked out in practice is that none of the SSL certificate providers in fact deliver such a service. The only thing being verified to any meaningful degree is that someone at some point paid a small amount of money. Thus the time of paid SSL providers is done and over. It is important for online traffic to be encrypted to the greatest degree possible, and it is a good thing that certain organizations have taken it upon themselves to set up an SSL certificate service that operates at no cost to end users. Eventually the whole system will become distributed and certificate-based encryption will be simply another part of the common protocols.
Installing Certbot
Let's Encrypt is an API service at root, and those in charge recently passed off responsibility for the initial client implementation - now called Certbot - to the EFF. In effect Certbot is a couple of different applications mushed together into one, and still very much a work in progress: it incorporates an ncurses UI implementation, a more traditional CLI implementation, a core application that generates certificates, and then a bunch of cross-platform modules for editing configuration files in common certificate-using applications such as Apache. Certbot is new enough not be in the distribution package repositories yet, but is very easy to use. Install it and its dependencies as follows:
sudo su - wget https://dl.eff.org/certbot-auto chmod a+x certbot-auto mv certbot-auto /usr/local/bin certbot-auto --noninteractive --os-packages-only
The documentation is generally good for basic tasks, but otherwise lacking, and it took a little while to find out how to list all of the configuration options:
certbot-auto --help all
Generating a Certificate
You will certainly need to know the full set of options if you want to run Certbot in a bash script. The application defaults to the ncurses UI, which is a pain if wanting to script SSL certificate setup, and there are numerous distinct prompts that have to be suppressed with different options. Once you have all of the necessary options in hand, generating certificates is a one-line command, however. The examples below generate a single certificate for example.com
and www.example.com
, with the certificate, key, and chain files deposited into /etc/letsencrypt/live/example.com
, and use files served via a webserver to verify ownership of the domain:
# Use this command if a webserver is already running with the webroot # at /var/www/html. certbot-auto certonly \ --agree-tos \ --non-interactive \ --text \ --rsa-key-size 4096 \ --email admin@example.com \ --webroot-path /var/www/html \ --domains "example.com, www.example.com" # Use this command if no webserver is running. Certbot will launch its # own webserver during the generation process. certbot-auto certonly \ --standalone \ --agree-tos \ --non-interactive \ --text \ --rsa-key-size 4096 \ --email admin@example.com \ --domains "example.com, www.example.com"
Using a Configuration File
Rather than putting options into the command line, it is perhaps easier to create a configuration file. The standard location is /etc/letsencrypt/cli.ini
. Options in the configuration file have the same names as on the command line, with a few exceptions in which there are several ways in which options can be expressed. This example matches the command using an existing web server above:
# Use a 4096 bit RSA key instead of 2048. rsa-key-size = 4096 # Set email and domains. email = admin@example.com domains = example.com, www.example.com # Text interface. text = True # No prompts. non-interactive = True # Suppress the Terms of Service agreement interaction. agree-tos = True # Use the webroot authenticator. authenticator = webroot webroot-path = /var/www/html
Certificate generation can now run with the following short command, picking up all of the configuration from the file:
certbot-auto certonly
Certificate Renewal
Once a certificate has been granted, it is valid for 90 days. Running exactly the same command used to generate the certificate will renew the existing certificate if it is within 30 days of expiration. Running the command in a cron task on a daily basis is a good approach. So, for example, add the following to /etc/cron.daily/certbot-renewal
:
#!/bin/bash # # Renew the Let's Encrypt certificate if it is time. # # This reads the standard /etc/letsencrypt/cli.ini. # # When running as a cron task, HOME may or may not be set, and # Certbot drops stuff into ~/.local. export HOME="/root" # PATH is never what you want it it to be in a cron context, so # make absolutely sure of it. export PATH="\${PATH}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # Using --no-self-upgrade suppresses the automatic update check that # might not work in a cron context. certbot-auto --no-self-upgrade certonly # Update all of the services that might now need to be using the renewed # certificate. service apache2 reload
Setup and Certificate Generation in a Single Script
This example script assumes that the server has a running webserver, either Apache or Nginx. Since it doesn't use a package install for Certbot, this script should work on most Linux distributions. It installs Certbot, obtains the certificate, and sets up the cron task for renewal.
#!/bin/bash # # This sets up Let's Encrypt SSL certificates and automatic renewal # using certbot: https://certbot.eff.org # # - Run this script as root. # - A webserver must be up and running. # # Certificate files are placed into subdirectories under # /etc/letsencrypt/live/*. # # Configuration must then be updated for the systems using the # certificates. # # The certbot-auto program logs to /var/log/letsencrypt. # set -o nounset set -o errexit # May or may not have HOME set, and this drops stuff into ~/.local. export HOME="/root" export PATH="${PATH}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" # No package install yet. wget https://dl.eff.org/certbot-auto chmod a+x certbot-auto mv certbot-auto /usr/local/bin # Install the dependencies. certbot-auto --noninteractive --os-packages-only # Set up config file. mkdir -p /etc/letsencrypt cat > /etc/letsencrypt/cli.ini <<EOF # Uncomment to use the staging/testing server - avoids rate limiting. # server = https://acme-staging.api.letsencrypt.org/directory # Use a 4096 bit RSA key instead of 2048. rsa-key-size = 4096 # Set email and domains. email = admin@example.com domains = example.com, www.example.com # Text interface. text = True # No prompts. non-interactive = True # Suppress the Terms of Service agreement interaction. agree-tos = True # Use the webroot authenticator. authenticator = webroot webroot-path = /var/www/html EOF # Obtain cert. certbot-auto certonly # Set up daily cron job. CRON_SCRIPT="/etc/cron.daily/certbot-renew" cat > "${CRON_SCRIPT}" <<EOF #!/bin/bash # # Renew the Let's Encrypt certificate if it is time. It won't do anything if # not. # # This reads the standard /etc/letsencrypt/cli.ini. # # May or may not have HOME set, and this drops stuff into ~/.local. export HOME="/root" # PATH is never what you want it it to be in cron. export PATH="\${PATH}:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" certbot-auto --no-self-upgrade certonly # If the cert updated, we need to update the services using it. E.g.: if service --status-all | grep -Fq 'apache2'; then service apache2 reload fi if service --status-all | grep -Fq 'httpd'; then service httpd reload fi if service --status-all | grep -Fq 'nginx'; then service nginx reload fi EOF chmod a+x "${CRON_SCRIPT}"
Configure Applications by Hand
While I understand the intent behind Certbot including plugins that wrap the process of editing SSL certificate configuration in common applications, I think it is a mistake to rely upon them. All such configuration is pretty simple, and it is better both to know how to do it, and to know what exactly is in the configuration files used by important applications on your services.
Certbot generates a certificate, key, and chain file, and typical configuration is simply a matter of setting the values of three parameters to the paths to those three files. In Apache, for example, set the following in the SSL-enabled virtual host definition:
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem