#!/bin/sh # The renewal loop: run a pass, sleep 12 hours, repeat. PID 1 of the container. # # Deliberately not `set -e`: a pass that fails — Let's Encrypt unreachable, # HAProxy refusing the certificate — must not end the loop, it must be retried # on the next one. # # The trap is not decoration. PID 1 has no default signal dispositions, so a # signal with no handler installed is ignored outright and `docker stop` would # always have to fall through to SIGKILL. # # `sleep &` followed by `wait`, rather than a plain `sleep`: a foreground # command keeps the shell from running a trap until it finishes, so a plain # sleep would leave the container deaf to SIGTERM for up to 12 hours. `wait` is # interruptible. Bare `wait` rather than `wait $(jobs -p)` — the command # substitution runs in a subshell that reports the parent's jobs in bash but # not in dash, and bare `wait` waits for every background job in either. # # One thing this cannot fix: a signal arriving while 1-renew-cert.sh is in the # foreground is deferred until that script returns, and an issuance talking to # Let's Encrypt can outlast docker's 10-second stop grace. Give the service a # longer `stop_grace_period` if that matters. trap 'exit 0' TERM INT while :; do /opt/scripts/1-renew-cert.sh \ || echo "entrypoint: renewal pass failed, retrying in 12h" >&2 sleep 12h & wait done