0

This is my first attempt at renewing Let's Encrypt certificates via Certbot. After carefully reading the Certbot user guide I created two post hook scripts like this:

root@pelargir:~# ls -l /etc/letsencrypt/renewal-hooks/post
total 8
-rwxr-xr-x 1 root root 697 Aug 29 16:35 10-setup-courier.sh
-rwxr-xr-x 1 root root 377 Aug 29 16:32 20-restart-services.sh

I then ran the renewal process manually on the command line (i.e. not via cron). This was successful in renewing the certificates, but it failed to execute the above post hook scripts. Here is the relevant output:

[...]
Running post-hook command: /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh
Hook command "/etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh" returned error code 127
Error output from 10-setup-courier.sh:
/bin/sh: /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh: not found

Running post-hook command: /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh
Hook command "/etc/letsencrypt/renewal-hooks/post/20-restart-services.sh" returned error code 127
Error output from 20-restart-services.sh:
/bin/sh: /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh: not found
[...]

I have no idea why this happens. I double-checked:

  • The script files exist
  • The script files are executable
  • I can run the scripts manually (with the environment variables RENEWED_DOMAINS and RENEWED_LINEAGE set and exported) and they do their job as expected

One other thing that I probably should mention is that I run Certbot within a Docker image because I am working with wildcard certificates. My DNS provider is Cloudflare. Here's the command line that I am using to start the renewal process:

docker run -it --rm --name certbot \
           -v "/etc/letsencrypt:/etc/letsencrypt" \
           -v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
           certbot/dns-cloudflare
           renew

The Docker image runs Certbot version 0.25.0. The system is Debian 9 (stretch), recently upgraded from Debian 8 (jessie).

Any clues what the problem could be?


EDIT: As requested, here is the content of the two files, slightly edited to replace my domain with "example.com":

root@pelargir:~# cat /etc/letsencrypt/renewal-hooks/post/10-setup-courier.sh 
#!/bin/bash

# Exit immediately if a command exits with non-zero status
set -e

case $RENEWED_DOMAINS in
  # Courier runs only under a example.com subdomain
  example.com)

    # We don't care about file permissions because we know that the
    # filesystem folder where we generate the file is not generally
    # accessible
    cat "$RENEWED_LINEAGE/fullchain.pem" "$RENEWED_LINEAGE/privkey.pem" >"$RENEWED_LINEAGE/courier.cert-and-key.unsecure"
    ;;
esac

root@pelargir:~# cat /etc/letsencrypt/renewal-hooks/post/20-restart-services.sh
#!/bin/bash

# Exit immediately if a command exits with non-zero status
set -e

case $RENEWED_DOMAINS in
  # Courier and Exim run only under a example.com subdomain
  *example.com*)
    systemctl restart courier-imap.service
    systemctl restart exim4.service
    systemctl restart apache2.service
    ;;

  # Apache has vhosts for all domains. Unfortunately the daemon is
  # restarted several times if several certificates are renewed.
  *)
    systemctl restart apache2.service
    ;;
esac
1

Your shell scripts use a shebang #!/bin/bash, meaning they are to be executed with that program, but the Docker container in which they run doesn't include bash. This is why /bin/sh reports the confusing not found error when calling these obviously present scripts. It is not the scripts that are not found, but the bash interpreter that you asked to run them with.

You can resolve the problem by changing the script interpreter to /bin/sh and removing any bash-isms from the scripts (probably quick and easy), or by installing bash in the container (probably messy).

  • sigh So obvious. After fixing the problem I now found out that, of course, I cannot restart system services from within the Docker container. I have to work more with Docker... – herzbube Aug 29 '18 at 17:33
  • A certbot container is useful for managing certificates for another related container, but it's probably not so useful if you're managing certificates for things running on the container host. – Michael Hampton Aug 29 '18 at 17:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.