Tech Blog

Let's Encrypt with Alternative ACME Client

Let's Encrypt with Alternative ACME Client

Recently updated on

Let's Encrypt is a great solution for automating the process of issuing SSL certificates. On systems with older software packages, however, Let's Encrypt can be a pain to set up in the recommended way. The use of a pure shell implementation of the ACME protocol can alleviate that process.

I recently was tasked with installing Let’s Encrypt on a server running an old version of Debian (Squeeze) which was due to have its certificate expire. Unfortunately, this meant following the path of setting up certbot and a cron job as outlined in Let's Encrypt Quick Setup -- which basically follows the canonical recommended setup -- was problematic. An old version of Python and OpenSSL, stale repository packages, and an inability to do a distribution upgrade right away meant the certbot client would not build or install smoothly.

After a brief and unsuccessful attempt trying to install a couple packages from source, I decided to attempt a different route. The ACME protocol is the Let’s Encrypt standard domain verification protocol, of which there are many client implementations. Enter acme.sh (https://github.com/Neilpang/acme.sh), a pure shell based alternative to certbot that has no dependencies outside of OpenSSL. This circumvented the main problem with needing newer packages since it’s written in Bourne shell compatible code, which is ancient history in computer terms and is available on nearly every Linux distribution.

Here is a rundown of the setup process. This tutorial assumes you are working with a site served by nginx called ‘example’ with domains ‘example.com’ and ‘www.example.com’.

To get acme.sh, use the script hosted at http://get.acme.sh. You will need wget or curl to retrieve it. You don’t have to be root to do this, but it is recommended, in part because the user that executes commands via acme.sh will end up with a cron entry for automatic certificate renewal.

sudo -s
curl https://get.acme.sh | sh
OR
wget -O - https://get.acme.sh | sh

And that’s it! Acme.sh is installed. Now we just have to set up the site for certificate renewal.

Next, we create a directory for the Let’s Encrypt challenge file. Let’s Encrypt will use this directory to upload “challenge files” that it uses to validate that you own the domain.

cd /iscape/sites/example/htdocs/
mkdir letsencrypt

Then we create an nginx location to point to the so we can serve the location. You may need to create the locations.conf file if it doesn’t exist already.

# vim /iscape/sites/example/etc/nginx/locations.conf
# letsencrypt challenge directory
location /.well-known/acme-challenge {
  root /iscape/sites/example/htdocs/letsencrypt;
}

And then we include the the locations.conf file to our nginx configuration so it actually loads the location.

# vim /iscape/sites/example/etc/nginx/server.conf
# Nginx Server Config File
server {
  listen 80;
  server_name www.example.com example.com;
  # includes the above locations.conf file.
  include /iscape/sites/example/etc/nginx/locations.conf;
  ...
}

server {
  listen 443;
  server_name www.example.com example.com;
  # includes the above locations.conf file.
  include /iscape/sites/example/etc/nginx/locations.conf;
  ...
}

And then, we must restart nginx for the changes to take effect.

sudo nginx -tc /etc/nginx/nginx.conf && sudo supervisorctl restart nginx

Now we can issue the certificate and install it. Note we added a -d flag for every domain we want registered. The first flag entered is the central domain registered by Let’s Encrypt, so it is probably ideal to list the base domain (example.com) first.

acme.sh --issue -d example.com -d www.example.com -w /iscape/sites/example/htdocs/letsencrypt --nginx

Next we install the certificate and key in a location that makes sense. Note the -d flag here should point to the central domain, which was the first domain listed when issuing the certificate. This command will also setup the automatic cron job which will renew certificates automatically as needed, which is why we provide a reload command as well.

acme.sh --installcert -d example.com --fullchainpath /iscape/etc/ssl-keys/www.example.com.pem --keypath /iscape/etc/ssl-keys/www.example.com.key.pem --reloadcmd "supervisorctl restart nginx"

Finally make sure that nginx points to the paths you just chose for the certificate and key.

server {
  listen 443;   
  server_name www.example.com example.com;
  ssl on;
  ssl_certificate /iscape/etc/ssl-keys/www.example.com.pem;
  ssl_certificate_key /iscape/etc/ssl-keys/www.example.com.key.pem;
  ....
}
 
Again, remember to restart nginx to load the configuration change.
sudo nginx -tc /etc/nginx/nginx.conf && sudo supervisorctl restart nginx

Finally, verify that acme.sh added an entry to the crontab.

# crontab -e
5 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null

If you want you can run that command manually to check that it’s working. You may need to provide the --force flag to check that it will actually grab a new certificate properly.

And that’s it! You’ve just set up Let’s Encrypt without any funky dependencies, virtualenvs, source installs or anything. Again you’re probably better off using certbot, which is vetted by Let’s Encrypt itself, but if you’re running on an older system, this is a satisfactory alternative.  This write-up was based on a combination of the following tutorials, which you can check out for more details.

Comments

Comments are closed.