22 January 2020

Using Certbot –post-hook to configure Let’s Encrypt Certs for use by multiple services

Certbot discourages modifying files in /etc/letsencrypt/ as this can break things. However some services can not read the certificate and key files with their default permissions of being readable only by root. Also some services (e.g. Haproxy) can only use a combined pem file, and can not load individual cert, chain & key files. Rather than modify the files in /etc/letsencrypt/ I like to copy them to another location and set the specific permissions I need. In addition I combine the Full Chain and the Private Key in to one file. This makes for easier service configuration settings.

Start by creating this post-hook script in /etc/letsencrypt/renewal-hooks/post/

Set permissions to 750 (rwxr-x—):

The script will run automatically each time renewals are attempted. When creating new certs either run the command manually immediately after running certbot:

Or add the –post-hook option to your certbot command to have it run immediately after creating a new cert with something like this:

Now you can configure services to simply load the concatenated pem file instead of having to specify multiple files for the key, cert & chain. For example, an Apache configuration would look something like this:

Posted January 22, 2020 by msb in category "Let's Encrypt


  1. By mrjones on

    Hey Matthew,

    Great write up, thanks!

    I’m not sure if you’re keeping up with certbot, but it also (now?) offers the “–deploy-hook” option. This is run *per domain issued/renewed* and, critically, exposes a “$RENEWED_LINEAGE” variable to the script as a full path to the certs (eg “/etc/letsencrypt/live/example.com”) and also “$RENEWED_DOMAINS”.

    This means your script could avoid all the discovery-work of finding where the certs are “# get list of certs in SSL dir” and avoid some of your for loops. A naive version that doesn’t delete certs that LE has deleted and assumes a single domain, could then be just 7 lines (minus comments):

    # simplify var
    # safe to run always
    mkdir -p /etc/ssl/letsencrypt
    # we know we just got a new cert, let’s blindly wip what’s there and still ensure
    # cert is *never* world readable, not even for an instant.
    cat /dev/null > $FINAL_PEM
    chmod 640 $FINAL_PEM
    chown root:ssl-cert $FINAL_PEM
    cat $RENEWED_LINEAGE/fullchain.pem > $FINAL_PEM
    cat $RENEWED_LINEAGE/privkey.pem >> $FINAL_PEM

    1. By msb (Post author) on

      Yes, “–deploy-hook” is a useful alternative here. In fact I have a more complete set of Let’s Encrypt tools and configs here: https://git.stack-source.com/msb/letsencrypt-tools/
      Included in that repo is a “–deploy-hook” that is very similar to yours, with a little extra (probably unneeded) error checking:
      Thanks for pointing this out.

Comments are closed.