6.12.2023

foto Petr Bravenec

Petr Bravenec
Twitter: @BravenecPetr
+420 777 566 384
petr.bravenec@hobrasoft.cz

Introduction

Encryption is required by many web sites and various network services (VPN, mail, cups, etc.) today. It's easy to issue a Let's Encrypt certificate using utilities like certbot or acme.sh. On many servers, we use the acme.sh utility, but it is essential problem with restarting servers after certificate renewal. It's not complicated, but it is poorly documented and no one really knows how to do it.

Brief how-to

Create a simple script to copy certificates, for example /usr/local/bin/certificates-changed:

#!/bin/bash

cp /root/.acme.sh/www.hobrasoft.cz/www.hobrasoft.cz.cer /etc/ssl/apache/www.hobrasoft.cz.crt
cp /root/.acme.sh/www.hobrasoft.cz/www.hobrasoft.cz.key /etc/ssl/apache/www.hobrasoft.cz.key
systemctl restart apache2

For your already issued certificates, add the Le_RenewHook parameter to the configuration file /root/.acme.sh/www.hobrasoft.cz/www.hobrasoft.cz.conf

Le_Domain='www.hobrasoft.cz'
Le_PreHook=''
Le_PostHook=''
Le_RenewHook='/usr/local/bin/certificates-changed'
...

The certificates should be renewed (usually without problem) and deployed automatically by a periodic invoking of the acme.sh with the --cron parameter. The acme.sh creates crontab record at the installation time:

0 0 * * * /root/.acme.sh/acme.sh --cron --home /root/.acme.sh

Detailed descripton

The help shows parameters --pre-hook <command> (command to be run before obtaining any certificates), --post-hook <command> (command to be run after attempting to obtain/renew certificates, runs regardless of whether obtain/renew succeeded or failed) and --renew-hook <command> (command to be run after each successfully renewed certificate), but any attempt to use them usually end in failure. This is because these parameters are active only when creating a new certificate. They do not invoke required hook, they only write required values to configuration file. When used in other actions (typically renew), these parameters are ignored.

The first call of acme.sh when new certificate is issued should look like this:

/root/.acme.sh/acme.sh --standalone --listen-v6 --issue --domain www.hobrasoft.cz \
    --pre-hook /usr/local/bin/certificates-changed-pre \
    --post-hook /usr/local/bin/certificates-changed-post \
    --renew-hook /usr/local/bin/certificates-changed 

It's pretty pointless trying to use the --deploy and --deploy-hook parameters - they don't work as you'd expect. When issuing a certificate for the first time, deploy the certificate manually. After the certificate is issued successfully, the configuration file /root/.acme.sh/www.hobrasoft.cz/www.hobrasoft.cz.conf should look like this:

Le_Domain='www.hobrasoft.cz'
Le_PreHook=''
Le_PostHook=''
Le_RenewHook='__ACME_BASE64__START_L3Vzci9sb2NhbC9iaW4vY2VydGlmaWNhdGVzLWNoYW5nZWQ=__ACME_BASE64__END_'
...

The string __ACME_BASE64... is nothing mysterious. It is base64 encoded string /usr/local/bin/certificates-changed and it works exactly as plain text.

The --pre-hook and --post-hook parameters are useful if you use certificates with haproxy, for example. It is convenient to stop haproxy before attempting to renew the certificate, then renew certificate (by calling acme.sh with --standalone parameter) and then start haproxy again. Without the temporary stop, both the haproxy and acme.sh try to bind port 80 and attempting to renew the certificate would fail.

Conlusion

Reliable automatic certificate renewal and deployment using acme.sh can sometimes take years because you only have 4 chances to try out annually.

There is very little information on the Internet. I have never found a reliable guide. This article therefore aspires to be the most cited text on automatic certificate renewal in the world.

Hobrasoft s.r.o. | Contact