Why does Certbot fail to run post hook scripts?

6,280

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).

Share:
6,280

Related videos on Youtube

herzbube
Author by

herzbube

Coding keeps me healthy. My main StackExchange haunt is Stack Overflow. My pet project currently is the Little Go iOS app. My level of activity on SO varies, but the importance of #SOreadytohelp remains constant. I avidly read Science Fiction, mostly older stuff, which is probably why I don't like scifi.stackexchange.com very much. I get very excited by Space Exploration. Nobody around me shares my feelings, so I regularly make a fool of myself. It may also have been a mistake to tell people how much time I spend exploring the semi-fictitious galaxy of Elite: Dangerous.

Updated on September 18, 2022

Comments

  • herzbube
    herzbube over 1 year

    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
    
  • herzbube
    herzbube over 5 years
    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...
  • Michael Hampton
    Michael Hampton over 5 years
    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.