Skip to main content

acme.sh, cpanel, a2hosting

I've used a2hosting.com for many years with good results. This site lives there on an inexpensive shared hosting plan. I've been converting client sites to use Let's Encrypt (LE) and decided to do the same for my site. Here is how I automated LE SSL certificate renewal and installation using acme.sh, Cpanel, and a short python script.

Background

From what I can tell, the version of Cpanel provided with my hosting package does not support LE or any form of automated certificate renewal. The only option for using a LE certificate that I could find was to manually install it via Cpanel every 90 days. This was a non-starter.

If you want to know why I'm using acme.sh instead of certbot, refer to an earlier post of mine.

Install acme.sh

ssh into the server and install acme.sh. See my earlier notes on installing and using acme.sh on a standard host for more information on usage and options.

# install and create cron job
$ curl https://get.acme.sh | sh

# add my email address to the config
$ acme.sh --update-account --accountemail myemail@east.fm

# get LE staging cert from staging server
$ acme.sh --staging --debug --log --issue -d east.fm -w $HOME/public_html

# install in a well known location for later use
$ mkdir $HOME/LE_certs
$ acme.sh --debug --log --install-cert -d east.fm \
          --certpath      $HOME/LE_certs/cert.pem \
          --keypath       $HOME/LE_certs/key.pem \
          --capath        $HOME/LE_certs/ca.cer \
          --fullchainpath $HOME/LE_certs/fullchain.pem

When the above works properly, go ahead and get a live valid certificate.

# --force is needed due to unexpired staging cert issued in previous step
$ acme.sh --force --issue -d east.fm -w $HOME/public_html

# install in a well known location for later use
$ acme.sh --install-cert -d east.fm \
          --certpath      $HOME/LE_certs/cert.pem \
          --keypath       $HOME/LE_certs/key.pem \
          --capath        $HOME/LE_certs/ca.cer \
          --fullchainpath $HOME/LE_certs/fullchain.pem

There you have it - a newly issued 90 day certificate from Let's Encrypt is stored in ~/LE_certs. Time to put it to work by feeding it to Cpanel.

Cpanel

I discovered that Cpanel has an API along with command line access. Once I saw this, I knew I was only a matter of a short script away from full automation.

Initially, I was concerned that the PEM files might need to be encoded, so I implemented this as a Python script. It turns out that that was unnecessary. In hindsight, a bash script would have been easier, but this is finished and it works, so I'm using it.

To install it:

$ curl https://gist.githubusercontent.com/MaDeuce/c33a1e4240953a2e43300827783a7e99/raw > ~/bin/cpanel_ssl_install.py
$ chmod +x ~/bin/cpanel_ssl_install.py

The script takes a single argument - the domain name. In my case:

# Install previously obtained certificate
$ $HOME/bin/cpanel_ssl_install.py east.fm

When it runs, it will take the PEM files from the well known location that acme.sh was asked to 'install' them in and feed them in to the uapi install_ssh command. This will update various Cpanel files and eventually restart httpd. That's it.

I didn't want to do this every 90 days, so I re-ran the last acme.sh invocation with the --reloadcmd option as follows:

$ acme.sh --install-cert -d east.fm \
          --certpath      $HOME/LE_certs/cert.pem \
          --keypath       $HOME/LE_certs/key.pem \
          --capath        $HOME/LE_certs/ca.cer \
          --fullchainpath $HOME/LE_certs/fullchain.pem \
          --reloadcmd     "$HOME/bin/cpanel_ssl_install.py east.fm"

This tells acme.sh how to reload the SSL configuration after the certificate has been installed (i.e., placed in the specified location). In my case, I told it to run my script which loads the certificate into Cpanel.

acme.sh conveniently keeps both the install locations and the reloadcmd stored in a configuration file for each domain it manages. This allowed me to automate renewals using the following crontab entry

0 0 * * * "/home/kheast/.acme.sh/acme.sh" --cron --home "/home/kheast/.acme.sh" >> "/home/kheast/acme.sh.log"

This runs acme.sh on a daily basis. It checks to see if the certificate is less than 30 days away from expiration. If it is, it will renew the certificate and load it into Cpanel.

With this done, I can sit back and enjoy automated SSL renewals via Let's Encrypt.