From 36b71a0ebbcf3eeb0a0e1c8e4eb4a0bbfc338885 Mon Sep 17 00:00:00 2001 From: MrMeeb Date: Sun, 9 Jul 2023 21:53:06 +0000 Subject: [PATCH 1/4] add standalone and webroot methods --- Dockerfile | 27 +++-- README.md | 67 ++++++++++-- root/certbot-prepare.sh | 223 +++++++++++++++++++++++++++++++--------- root/certbot-renew.sh | 16 +-- root/container-init.sh | 10 +- 5 files changed, 255 insertions(+), 88 deletions(-) diff --git a/Dockerfile b/Dockerfile index d7c1b83..3116ad7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,17 +11,30 @@ FROM base-${TARGETARCH}${TARGETVARIANT} ARG S6_OVERLAY_VERSION=3.1.5.0 -ENV DOMAINS= -ENV EMAIL= -ENV INTERVAL="0 */6 * * *" -ENV STAGING=false -ENV PROPOGATION_TIME=10 -ENV GENERATE_DHPARAM=true -ENV TZ=UTC +# Core variables ENV PUID=1000 ENV PGID=1000 +ENV TZ=UTC +ENV GENERATE_DHPARAM=true +ENV INTERVAL="0 */6 * * *" + +# Single domain +ENV DOMAINS= +ENV EMAIL= +ENV STAGING=false + +# Custom CA support +ENV CUSTOM_CA= +ENV CUSTOM_CA_SERVER= + +# Different plugin support (to support Cloudflare but also normal mode) +ENV PLUGIN=standalone +ENV PROPOGATION_TIME=10 ENV CLOUDFLARE_TOKEN= +## Multi-cert support +ENV CERT_COUNT=1 + #Get required packages RUN apk update && apk add curl bash python3 py3-virtualenv procps tzdata nano shadow xz busybox-suid openssl diff --git a/README.md b/README.md index c6cdc14..83b35fa 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![Drone (self-hosted) with branch](https://img.shields.io/drone/build/MrMeeb/certbot-cron-docker/master?label=latest&server=https%3A%2F%2Fdrone.mrmeeb.stream&style=for-the-badge) ![Drone (self-hosted) with branch](https://img.shields.io/drone/build/MrMeeb/certbot-cron-docker/develop?label=develop&server=https%3A%2F%2Fdrone.mrmeeb.stream&style=for-the-badge) -Dockerised Certbot that utilises cron to schedule creating and renewing SSL certificates. Uses Cloudflare for DNS-01 verification. Automatic renewal attempt happens every 6 hours by default. +Dockerised Certbot that utilises cron to schedule creating and renewing SSL certificates. Supports standalone, webroot or Cloudflare methods. Automatic renewal attempt happens every 6 hours by default. ## Tags @@ -18,8 +18,9 @@ Dockerised Certbot that utilises cron to schedule creating and renewing SSL cert docker run -d --name certbot \ -e EMAIL=admin@domain.com \ -e DOMAINS=domain.com \ + -e PLUGIN=cloudflare \ -e CLOUDFLARE_TOKEN=123abc - -v /docker/certbot-cron:/config \ + -v ./certbot-cron:/config \ git.mrmeeb.stream/mrmeeb/certbot-cron:latest ``` @@ -36,30 +37,78 @@ services: environment: - EMAIL=admin@domain.com - DOMAINS=domain.com,*.domain.com + - PLUGIN=cloudflare - CLOUDFLARE_TOKEN=123abc ``` ## Environment Variables: -| Variable | Default Value | Description | +### Core Options: + +Core options to the container + +| Variable | Default | Description | | --- | --- | --- | |PUID |int |1000 |Sets the UID of the user certbot runs under | |PGID |int |1000 |Sets the GID of the user certbot runs under | |TZ |[List of valid TZs](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List) |UTC |Sets the timezone of the container | +| GENERATE_DHPARAM | true (case-sensitive) | Generate Diffie-Hellman keys in /config/letsencrypt/keys | +| INTERVAL | 0 */6 * * * | How often certbot attempts to renew the certificate. Cron syntax | +| CERT_COUNT | 1 | How many certificates certbot will try to issue (more than 1 not yet implemented) | + +### Certificate Options + +These options apply when `CERT_COUNT` is `1` + +| Variable | Default | Description | +| --- | --- | --- | | EMAIL | None | Email address for renewal information & other communications | | DOMAINS | None | Domains to be included in the certificate. Comma separated list, no spaces. Wildcards supported | -| INTERVAL | 0 */6 * * * | How often certbot attempts to renew the certificate. Cron syntax | -| STAGING | false (case-sensitive) | Uses the LetsEncrypt staging endpoint for testing - avoids the aggressive rate-limiting of the production endpoint | +| STAGING | false (case-sensitive) | Uses the LetsEncrypt staging endpoint for testing - avoids the aggressive rate-limiting of the production endpoint. **Not supported when using a custom Certificate Authority.** | + +### Plugins + +Plugins that can used for issuing a certificate + +| Variable | Default | Description | +| --- | --- | --- | +| PLUGIN | standalone | Options are `webroot`, `standalone`, or `cloudflare` | + +- `webroot` - relies on a webserver running on the FQDN for which you're trying to issue a certificate to serve validation files + - Requires the webserver's root directory to be mounted to the container as `/config/webroot` +- `standalone` - certbot spawns a webserver on port 80 for validation + - Requires this container to be bound to port 80 on the host +- `cloudflare` - Creates a TXT record with Cloudflare pointing to the domain you're requesting a certificate for + - Requires the domain you're requesting a certificate for to be entered in Cloudflare + +#### Cloudflare Plugin + +Options that affect the behaviour of certbot running with the Cloudflare plugin + +| Variable | Default | Description | +| --- | --- | --- | | PROPOGATION_TIME | 10 | The amount of time (seconds) that certbot waits for the TXT records to propogate to Cloudflare before verifying - the more domains in the certificate, the longer you might need | -| GENERATE_DHPARAM | true (case-sensitive) | Generate Diffie-Hellman keys in /config/letsencrypt/keys | -| CLOUDFLARE_TOKEN | N/A | Cloudflare token for verification | +| CLOUDFLARE_TOKEN | null | Cloudflare token for verification | + +### Custom Certificate Authority + +Options to use a custom Certificate Authority, for example when issuing internal certificates + +| Variable | Default | Description | +| --- | --- | --- | +| CUSTOM_CA | null | Name of the root certificate Certbot/ACME will trust requesting the certificate, e.g `root.pem`. **Must be placed in `/config/custom_ca`** | +| CUSTOM_CA_SERVER | null | Custom server URL used by Certbot/ACME when requesting a certificate, e.g `https://ca.internal/acme/acme/directory` | ## Volumes | Docker path | Purpose | | --- | --- | | /config | Stores configs and LetsEncrypt output for mounting in other containers +| /config/custom_ca | Mountpoint for a custom Certificate Authority root certificate. **Required if `CUSTOM_CA` is set** +| /config/webroot | Mountpoint for the webroot of a separate webserver. **Required if `PLUGIN=webroot` is set** -## Other +## Ports -Thanks to [this guy](https://stackoverflow.com/questions/63447441/docker-stop-for-crond-times-out) for explaining how to make cron actually shutdown when stopping the container. \ No newline at end of file +| Port | Purpose | +| --- | --- | +| 80 | Used by ACME to verify domain ownership. **Required if `PLUGIN=standalone` is set** \ No newline at end of file diff --git a/root/certbot-prepare.sh b/root/certbot-prepare.sh index d7c6437..550aa66 100644 --- a/root/certbot-prepare.sh +++ b/root/certbot-prepare.sh @@ -32,54 +32,177 @@ then touch /config/.crontab.txt fi -if [ ! -f /config/.secrets/cloudflare.ini ] +#Cleanup renew list and create it fresh, ready for commands to be run and added +echo "#!/command/with-contenv bash" > /config/renew-list.sh +echo "" >> /config/.renew-list.sh + +function single_domain { + + if [ ! -z $CUSTOM_CA ] + then + + echo "Using a custom CA for issuing certificates" + + if [ ! -d /config/custom_ca ] + then + mkdir /config/custom_ca + echo "Please place your custom CA file into /config/custom_ca and restart the container" + exit 1 + fi + + if [ -z "$(ls -A /config/custom_ca)" ] + then + echo "The CUSTOM_CA option is populated, but the /config/custom_ca dir is empty. Please place your root certificate in this directory and restart the container" + exit 1 + fi + + if [ -z $CUSTOM_CA_SERVER ] + then + echo "CUSTOM_CA_SERVER has not been defined. It is required for using a custom CA to issue a certificate" + exit 1 + fi + + #REQUESTS_CA_BUNDLE=/config/custom_ca/$CUSTOM_CA + + CUSTOM_CA_PATH=/config/custom_ca/$CUSTOM_CA + CUSTOM_CA_SERVER_OPT="--server $CUSTOM_CA_SERVER" + + if [ $STAGING ] + then + + echo "Staging is not supported when using a custom CA, so overriding. To remove this alert, set staging to false." + + STAGING=false + + fi + + fi + + BASE_COMMAND=(certbot certonly --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos $CUSTOM_CA_SERVER_OPT --email $EMAIL -d $DOMAINS) + + ## Run with Cloudflare plugin + if [ $PLUGIN == "cloudflare" ] + then + + echo "Using Cloudflare plugin" + + if [ ! -f /config/.secrets/cloudflare.ini ] + then + touch /config/.secrets/cloudflare.ini + fi + + if [ -n "$CLOUDFLARE_TOKEN" ] + then + echo "Cloudflare token is present" + + echo "dns_cloudflare_api_token = $CLOUDFLARE_TOKEN" > /config/.secrets/cloudflare.ini + + fi + + if [ ! -s /config/.secrets/cloudflare.ini ] + then + echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done as an ENV var, or by editing the file directly" + + exit 1 + fi + + #Securing cloudflare.ini to supress warnings + chmod 600 /config/.secrets/cloudflare.ini + + echo "Creating certificates, or attempting to renew if they already exist" + + if [ $STAGING = true ] + then + echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" + ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging + # Add to renewal list + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging" >> /config/renew-list.sh + echo "Creation/renewal attempt complete" + elif [ $STAGING = false ] + then + echo "Using production endpoint" + ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini + # Add to renewal list + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini" >> /config/renew-list.sh + echo "Creation/renewal attempt complete" + else + echo "Unrecognised option for STAGING variable - check your configuration" + + exit 1 + fi + + ## Run with Standalone plugin + elif [ $PLUGIN == "standalone" ] + then + + echo "Using HTTP verification via built-in web-server - please ensure port 80 is exposed." + + if [ $STAGING = true ] + then + echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" + REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone --staging + # Add to renewal list + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone --staging" >> /config/renew-list.sh + echo "Creation/renewal attempt complete" + elif [ $STAGING = false ] + then + echo "Using production endpoint" + REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone + # Add to renewal list + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone" >> /config/renew-list.sh + echo "Creation/renewal attempt complete" + else + echo "Unrecognised option for STAGING variable - check your configuration" + + exit 1 + fi + + ## Run with webroot plugin + elif [ $PLUGIN == "webroot" ] + then + + echo "Using HTTP verification via webroot - please ensure you have mounted a webroot at /config/webroot from a web-server reachable via the domain you are issuing a certificate for." + + if [ $STAGING = true ] + then + echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" + REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging + # Add to renewal list + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging" >> /config/renew-list.sh + echo "Creation/renewal attempt complete" + elif [ $STAGING = false ] + then + echo "Using production endpoint" + REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot + # Add to renewal list + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot" >> /config/renew-list.sh + echo "Creation/renewal attempt complete" + else + echo "Unrecognised option for STAGING variable - check your configuration" + + exit 1 + fi + + else + + echo "Unrecognised option for PLUGIN variable - check your configuration" + + fi + + if [ $GENERATE_DHPARAM = true ] && [ ! -s /config/letsencrypt/keys/ssl-dhparams.pem ] + then + echo "Generating Diffie-Hellman keys, saved to /config/letsencrypt/keys" + openssl dhparam -out /config/letsencrypt/keys/ssl-dhparams.pem 4096 + fi + + echo "$INTERVAL /certbot-renew.sh >> /config/logs/renew.log" > /config/.crontab.txt + + echo "Starting automatic renewal job. Schedule is $INTERVAL" + crontab /config/.crontab.txt + +} + +if [ $CERT_COUNT == 1 ] then - touch /config/.secrets/cloudflare.ini -fi - -if [ -n "$CLOUDFLARE_TOKEN" ] -then - echo "Cloudflare token is present" - - echo "dns_cloudflare_api_token = $CLOUDFLARE_TOKEN" > /config/.secrets/cloudflare.ini - -fi - -if [ ! -s /config/.secrets/cloudflare.ini ] -then - echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done as an ENV var, or by editing the file directly" - - exit 22 -fi - -#Securing cloudflare.ini to supress warnings -chmod 600 /config/.secrets/cloudflare.ini - -echo "Creating certificates, or attempting to renew if they already exist" - -if [[ $STAGING = true ]] -then - echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" - certbot certonly --staging --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --email $EMAIL -d $DOMAINS - echo "Creation/renewal attempt complete" -elif [[ $STAGING = false ]] -then - echo "Using production endpoint" - certbot certonly --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --email $EMAIL -d $DOMAINS - echo "Creation/renewal attempt complete" -else - echo "Unrecognised option for STAGING variable - check your configuration" - - exit 22 -fi - -if [[ $GENERATE_DHPARAM = true ]] && [[ ! -s /config/letsencrypt/keys/ssl-dhparams.pem ]] -then - echo "Generating Diffie-Hellman keys, saved to /config/letsencrypt/keys" - openssl dhparam -out /config/letsencrypt/keys/ssl-dhparams.pem 4096 -fi - -echo "$INTERVAL /certbot-renew.sh >> /config/logs/renew.log" > /config/.crontab.txt - -echo "Starting automatic renewal job. Schedule is $INTERVAL" -crontab /config/.crontab.txt \ No newline at end of file + single_domain +fi \ No newline at end of file diff --git a/root/certbot-renew.sh b/root/certbot-renew.sh index 485a0d5..acedd1c 100644 --- a/root/certbot-renew.sh +++ b/root/certbot-renew.sh @@ -3,18 +3,4 @@ echo '' date echo "Attempting to renew certificates" -if [[ $STAGING = true ]] -then - echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" - certbot certonly --staging --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --email $EMAIL -d $DOMAINS - echo "Renewal attempt complete" -elif [[ $STAGING = false ]] -then - echo "Using production endpoint" - certbot certonly --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --email $EMAIL -d $DOMAINS - echo "Renewal attempt complete" -else - echo "Unrecognised option for STAGING variable - check your configuration" - - exit 8 -fi \ No newline at end of file +bash /config/.renew-list.sh \ No newline at end of file diff --git a/root/container-init.sh b/root/container-init.sh index 1f4fe54..180aac6 100644 --- a/root/container-init.sh +++ b/root/container-init.sh @@ -15,18 +15,14 @@ echo "" echo "Initialising container" echo " ---------------------------------------------------------------------- -ENVIRONMENT +ENVIRONMENT (only core variables shown) ---------------------------------------------------------------------- PUID=${PUID} PGID=${PGID} TZ=${TZ} -DOMAINS=${DOMAINS} -EMAIL=${EMAIL} INTERVAL=${INTERVAL} -STAGING=${STAGING} -PROPOGATION_TIME=${PROPOGATION_TIME} GENERATE_DHPARAM=${GENERATE_DHPARAM} -CLOUDFLARE_TOKEN=${CLOUDFLARE_TOKEN} +CERT_COUNT=${CERT_COUNT} ---------------------------------------------------------------------- " @@ -41,7 +37,7 @@ if [[ ! "${PUID}" -eq 0 ]] && [[ ! "${PGID}" -eq 0 ]]; then groupmod -o -g "${PGID}" mrmeeb else echo "Running as root is not supported, please fix your PUID and PGID!" - exit 1 + sleep infinity fi echo "Checking permissions in /config and /app." From 3a6466612b4110c94bba3c98e25cd5748a26cf87 Mon Sep 17 00:00:00 2001 From: MrMeeb Date: Sat, 15 Jul 2023 16:04:45 +0000 Subject: [PATCH 2/4] enable tracking of env vars between runs --- root/certbot-prepare.sh | 99 ++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 16 deletions(-) diff --git a/root/certbot-prepare.sh b/root/certbot-prepare.sh index 550aa66..edaa9e5 100644 --- a/root/certbot-prepare.sh +++ b/root/certbot-prepare.sh @@ -1,7 +1,7 @@ #!/command/with-contenv bash # shellcheck shell=bash -#Creating needed folders and files if they don't already exist +# Creating needed folders and files if they don't already exist if [ ! -d /config/.secrets ] then mkdir /config/.secrets @@ -32,10 +32,80 @@ then touch /config/.crontab.txt fi -#Cleanup renew list and create it fresh, ready for commands to be run and added -echo "#!/command/with-contenv bash" > /config/renew-list.sh +# Cleanup renew list and create it fresh, ready for commands to be run and added +echo "#!/command/with-contenv bash" > /config/.renew-list.sh echo "" >> /config/.renew-list.sh +# Create original config file to track changes to environmental variables +if [ ! -f /config/.donoteditthisfile ] +then + echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\"" > /config/.donoteditthisfile + echo "Created .donoteditthisfile" +fi + +# Load original config file +. /config/.donoteditthisfile + +# Checking for changes to config file, revoke certs if necessary +if [ ! "${DOMAINS}" = "${ORIGDOMAINS}" ] || + [ ! "${EMAIL}" = "${ORIGEMAIL}" ] || + [ ! "${STAGING}" = "${ORIGSTAGING}" ] || + [ ! "${CUSTOM_CA}" = "${ORIGCUSTOM_CA}" ] || + [ ! "${CUSTOM_CA_SERVER}" = "${ORIGCUSTOM_CA_SERVER}" ] || + [ ! "${PLUGIN}" = "${ORIGPLUGIN}" ] || + [ ! "${PROPOGATION_TIME}" = "${ORIGPROPOGATION_TIME}" ] +then + + echo "Configuration has changed since the last certificate was issued. Revoking and regenerating certs" + FIRST_DOMAIN=$(echo $ORIGDOMAINS | cut -d \, -f1) + + if [ ! -z $ORIGCUSTOM_CA ] + then + + echo "A custom CA was used for issuing. Using it to revoke as well." + + if [ ! -d /config/custom_ca ] + then + mkdir /config/custom_ca + echo "Please place the custom CA root file used to generate the current certificate into /config/custom_ca and restart the container" + exit 1 + fi + + if [ -z "$(ls -A /config/custom_ca)" ] + then + echo "A root certificate called ${ORIGCUSTOM_CA} was used to generate a certificate, but the /config/custom_ca dir is now empty. Please place this root certificate back this directory and restart the container so it can be safely revoked" + exit 1 + fi + + ORIGCUSTOM_CA_PATH=/config/custom_ca/$ORIGCUSTOM_CA + ORIGCUSTOM_CA_SERVER_OPT="--server $ORIGCUSTOM_CA_SERVER" + + fi + + if [ $ORIGSTAGING = "true" ] + then + + # Reusing the CUSTOM_CA_SERVER_OPT variable to add staging option if that was selected + ORIGCUSTOM_CA_SERVER_OPT="--server https://acme-staging-v02.api.letsencrypt.org/directory" + + fi + + if [ -f /config/letsencrypt/live/"${FIRST_DOMAIN}"/fullchain.pem ] + then + + REQUESTS_CA_BUNDLE=$ORIGCUSTOM_CA_PATH certbot revoke --non-interactive --agree-tos --email $ORIGEMAIL --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/"${FIRST_DOMAIN}"/fullchain.pem $ORIGCUSTOM_CA_SERVER_OPT || true + + rm -rf /config/letsencrypt/archive/"${FIRST_DOMAIN}" + rm -rf /config/letsencrypt/live/"${FIRST_DOMAIN}" + rm -rf /config/letsencrypt/renewal/"${FIRST_DOMAIN}".conf + + fi + +fi + +# Update config file with new env vars +echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\"" > /config/.donoteditthisfile + function single_domain { if [ ! -z $CUSTOM_CA ] @@ -62,17 +132,14 @@ function single_domain { exit 1 fi - #REQUESTS_CA_BUNDLE=/config/custom_ca/$CUSTOM_CA - CUSTOM_CA_PATH=/config/custom_ca/$CUSTOM_CA CUSTOM_CA_SERVER_OPT="--server $CUSTOM_CA_SERVER" - if [ $STAGING ] + if [ $STAGING = "true" ] then - echo "Staging is not supported when using a custom CA, so overriding. To remove this alert, set staging to false." - - STAGING=false + echo "Staging option is not supported when using a custom CA. To remove this alert, set staging to false. If your CA has a standing endpoint, use the CUSTOM_CA_SERVER option to point to it instead" + exit 1 fi @@ -101,7 +168,7 @@ function single_domain { if [ ! -s /config/.secrets/cloudflare.ini ] then - echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done as an ENV var, or by editing the file directly" + echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done by setting CLOUDFLARE_TOKEN, or by editing /config/.secrets/cloudflare.ini directly" exit 1 fi @@ -116,14 +183,14 @@ function single_domain { echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging # Add to renewal list - echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging" >> /config/renew-list.sh + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging" >> /config/.renew-list.sh echo "Creation/renewal attempt complete" elif [ $STAGING = false ] then echo "Using production endpoint" ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini # Add to renewal list - echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini" >> /config/renew-list.sh + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds $PROPOGATION_TIME --dns-cloudflare-credentials /config/.secrets/cloudflare.ini" >> /config/.renew-list.sh echo "Creation/renewal attempt complete" else echo "Unrecognised option for STAGING variable - check your configuration" @@ -142,14 +209,14 @@ function single_domain { echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone --staging # Add to renewal list - echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone --staging" >> /config/renew-list.sh + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone --staging" >> /config/.renew-list.sh echo "Creation/renewal attempt complete" elif [ $STAGING = false ] then echo "Using production endpoint" REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone # Add to renewal list - echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone" >> /config/renew-list.sh + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --standalone" >> /config/.renew-list.sh echo "Creation/renewal attempt complete" else echo "Unrecognised option for STAGING variable - check your configuration" @@ -168,14 +235,14 @@ function single_domain { echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging # Add to renewal list - echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging" >> /config/renew-list.sh + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging" >> /config/.renew-list.sh echo "Creation/renewal attempt complete" elif [ $STAGING = false ] then echo "Using production endpoint" REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot # Add to renewal list - echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot" >> /config/renew-list.sh + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot" >> /config/.renew-list.sh echo "Creation/renewal attempt complete" else echo "Unrecognised option for STAGING variable - check your configuration" From 5d14d166ebcc0358bde477a3e4c4e060fb46aa1c Mon Sep 17 00:00:00 2001 From: MrMeeb Date: Sun, 16 Jul 2023 15:37:12 +0000 Subject: [PATCH 3/4] add multi-certificate support --- README.md | 81 +++++- root/certbot-prepare.sh | 603 ++++++++++++++++++++++++++++++++++++---- root/container-init.sh | 45 ++- 3 files changed, 661 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 83b35fa..3c5655b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Dockerised Certbot that utilises cron to schedule creating and renewing SSL cert ## Running ### Docker CLI -``` +```bash docker run -d --name certbot \ -e EMAIL=admin@domain.com \ -e DOMAINS=domain.com \ @@ -25,7 +25,7 @@ docker run -d --name certbot \ ``` ### Docker Compose -``` +```yaml version: "3" services: certbot: @@ -99,12 +99,87 @@ Options to use a custom Certificate Authority, for example when issuing internal | CUSTOM_CA | null | Name of the root certificate Certbot/ACME will trust requesting the certificate, e.g `root.pem`. **Must be placed in `/config/custom_ca`** | | CUSTOM_CA_SERVER | null | Custom server URL used by Certbot/ACME when requesting a certificate, e.g `https://ca.internal/acme/acme/directory` | +### Multiple Certificates + +This container can issue multiple certificates each containing different domains. This could be used to issue a certificate for a public domain on Cloudflare, but then also for a local certificate from an internal Certificate Authority, for example. Another example would be you have a web-server hosting two separate websites and you want them to have dedicated SSL certificates instead of sharing one. + +When issuing multiple certificates, first `CERT_COUNT` must be set to a value greater than 1. + +#### Global Environment Variables + +Some environment variables can be set globally, where they apply to all certificates (unless otherwise specifically specified). The following can be used globally: + +| Variable | DESCRIPTION | +| --- | --- | +|EMAIL| Email address for renewal information & other communications | +|STAGING| Uses the LetsEncrypt staging endpoint for testing - avoids the aggressive rate-limiting of the production endpoint. **Not supported when using a custom Certificate Authority.** | +|CUSTOM_CA| Name of the root certificate Certbot/ACME will trust requesting the certificate, e.g `root.pem`. **Must be placed in `/config/custom_ca`** | +|CUSTOM_CA_SERVER| Custom server URL used by Certbot/ACME when requesting a certificate, e.g `https://ca.internal/acme/acme/directory` | +|PLUGIN| Options are `webroot`, `standalone`, or `cloudflare` | +|PROPOGATION_TIME| **(Applies to Cloudflare plugin)** The amount of time (seconds) that certbot waits for the TXT records to propogate to Cloudflare before verifying - the more domains in the certificate, the longer you might need | + +More detail on these environment variables may be found further up. + +#### Certificate-specific Environment Variables + +Any variable other than those described as **Core Options** can be set per-certificate in a multi-certificate environment. The syntax is `${VARIABLE_NAME}_${CERT_NUMBER}`. The only certificate-specific option that **must** be set is the `DOMAINS` option. + +##### Multi-certificate container using global variables: + +```yaml + certbot: + container_name: certbot + image: git.mrmeeb.stream/mrmeeb/certbot-cron + volumes: + - /docker/certbot-cron:/config + - /docker/nginx/www:/config/webroot + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/London + - GENERATE_DHPARAM=false + - CERT_COUNT=2 + - EMAIL=admin@domain.com + - CUSTOM_CA=root.pem + - CUSTOM_CA_SERVER=https://ca.internal/acme/acme/directory + - PLUGIN=webroot + - STAGING=false + - DOMAINS_1=website1.com + - DOMAINS_2=website2.com +``` + +##### Multi-certificate container using different options for each certificate: +```yaml + certbot: + container_name: certbot + image: git.mrmeeb.stream/mrmeeb/certbot-cron + volumes: + - /docker/certbot-cron:/config + - /docker/nginx/www:/config/webroot + environment: + - PUID=1000 + - PGID=1000 + - TZ=Europe/London + - GENERATE_DHPARAM=false + - CERT_COUNT=2 + - EMAIL=admin@domain.com + - DOMAINS_1=website1.com + - CUSTOM_CA_1=root.pem + - CUSTOM_CA_SERVER_1=https://ca.internal/acme/acme/directory + - PLUGIN_1=webroot + - STAGING_1=false + - DOMAINS_2=website2.com + - PLUGIN_2=cloudflare + - CLOUDFLARE_TOKEN_2=abc123 + - PROPOGATION_TIME_2=30 + - STAGING_2=true +``` + ## Volumes | Docker path | Purpose | | --- | --- | | /config | Stores configs and LetsEncrypt output for mounting in other containers -| /config/custom_ca | Mountpoint for a custom Certificate Authority root certificate. **Required if `CUSTOM_CA` is set** | /config/webroot | Mountpoint for the webroot of a separate webserver. **Required if `PLUGIN=webroot` is set** ## Ports diff --git a/root/certbot-prepare.sh b/root/certbot-prepare.sh index edaa9e5..f65f2fd 100644 --- a/root/certbot-prepare.sh +++ b/root/certbot-prepare.sh @@ -1,6 +1,9 @@ #!/command/with-contenv bash # shellcheck shell=bash +# Halt container if anything returns a non-zero exit code +set -e + # Creating needed folders and files if they don't already exist if [ ! -d /config/.secrets ] then @@ -32,6 +35,17 @@ then touch /config/.crontab.txt fi +function better_exit { + + echo "" + echo "" + echo "" + echo "You can ignore the below error messages - they happened because the container exited with a non-0 exit code due misconfiguration" + echo "==========================================================" + exit 1 + +} + # Cleanup renew list and create it fresh, ready for commands to be run and added echo "#!/command/with-contenv bash" > /config/.renew-list.sh echo "" >> /config/.renew-list.sh @@ -39,75 +53,184 @@ echo "" >> /config/.renew-list.sh # Create original config file to track changes to environmental variables if [ ! -f /config/.donoteditthisfile ] then - echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\"" > /config/.donoteditthisfile - echo "Created .donoteditthisfile" + echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\" ORIGCERT_COUNT=${CERT_COUNT}" > /config/.donoteditthisfile fi # Load original config file . /config/.donoteditthisfile -# Checking for changes to config file, revoke certs if necessary -if [ ! "${DOMAINS}" = "${ORIGDOMAINS}" ] || - [ ! "${EMAIL}" = "${ORIGEMAIL}" ] || - [ ! "${STAGING}" = "${ORIGSTAGING}" ] || - [ ! "${CUSTOM_CA}" = "${ORIGCUSTOM_CA}" ] || - [ ! "${CUSTOM_CA_SERVER}" = "${ORIGCUSTOM_CA_SERVER}" ] || - [ ! "${PLUGIN}" = "${ORIGPLUGIN}" ] || - [ ! "${PROPOGATION_TIME}" = "${ORIGPROPOGATION_TIME}" ] -then +# Revoke all certs if CERT_COUNT has decreased, starting fresh +if [ "${CERT_COUNT}" -lt "${ORIGCERT_COUNT}" ]; then - echo "Configuration has changed since the last certificate was issued. Revoking and regenerating certs" - FIRST_DOMAIN=$(echo $ORIGDOMAINS | cut -d \, -f1) + echo "" - if [ ! -z $ORIGCUSTOM_CA ] - then + echo "CERT_COUNT has decreased - revoking all certificates then reissuing to cleanup any lingerers." - echo "A custom CA was used for issuing. Using it to revoke as well." + # Use .donoteditthisfile_cert_* to get details of each issued certificate to revoke with correct parameters - if [ ! -d /config/custom_ca ] + x=1 + while [ $x -le ${ORIGCERT_COUNT} ]; do + + # Load config of particular cert + . /config/.donoteditthisfile_cert_${x} + + # Setting up variables (requires two passes to clean away requirement for indirect variables) + ## Pass 1 + DOMAINS_P1=ORIGDOMAINS_${x} + EMAIL_P1=ORIGEMAIL_${x} + STAGING_P1=ORIGSTAGING_${x} + CUSTOM_CA_P1=ORIGCUSTOM_CA_${x} + CUSTOM_CA_SERVER_P1=ORIGCUSTOM_CA_SERVER_${x} + PLUGIN_P1=ORIGPLUGIN_${x} + PROPOGATION_TIME_P1=ORIGPROPOGATION_TIME_${x} + CLOUDFLARE_TOKEN_P1=ORIGCLOUDFLARE_TOKEN_${x} + + ## Pass 2 + DOMAINS_MULTI=${!DOMAINS_P1} + EMAIL_MULTI=${!EMAIL_P1} + STAGING_MULTI=${!STAGING_P1} + CUSTOM_CA_MULTI=${!CUSTOM_CA_P1} + CUSTOM_CA_SERVER_MULTI=${!CUSTOM_CA_SERVER_P1} + PLUGIN_MULTI=${!PLUGIN_P1} + PROPOGATION_TIME_MULTI=${!PROPOGATION_TIME_P1} + CLOUDFLARE_TOKEN_MULTI=${!CLOUDFLARE_TOKEN_P1} + + FIRST_DOMAIN_MULTI=$(echo ${DOMAINS_MULTI} | cut -d \, -f1) + + echo ${FIRST_DOMAIN_MULTI} + + if [ ! -z ${CUSTOM_CA_MULTI} ] then - mkdir /config/custom_ca - echo "Please place the custom CA root file used to generate the current certificate into /config/custom_ca and restart the container" - exit 1 + + echo "A custom CA was used for issuing certificate ${x}. Using it to revoke as well." + + if [ ! -d /config/custom_ca ] + then + mkdir /config/custom_ca + echo "Please place the custom CA root file used to generate the current certificate ${x} into /config/custom_ca and restart the container" + better_exit + fi + + if [ -z "$(ls -A /config/custom_ca)" ] + then + echo "A root certificate called ${CUSTOM_CA_MULTI} was used to generate a certificate, but the /config/custom_ca dir is now empty. Please place this root certificate back this directory and restart the container so it can be safely revoked" + better_exit + fi + + CUSTOM_CA_PATH_MULTI=/config/custom_ca/${CUSTOM_CA_MULTI} + CUSTOM_CA_SERVER_OPT_MULTI="--server ${CUSTOM_CA_SERVER_MULTI}" + fi - if [ -z "$(ls -A /config/custom_ca)" ] + if [ $STAGING_MULTI = "true" ] then - echo "A root certificate called ${ORIGCUSTOM_CA} was used to generate a certificate, but the /config/custom_ca dir is now empty. Please place this root certificate back this directory and restart the container so it can be safely revoked" - exit 1 + + # Reusing the CUSTOM_CA_SERVER_OPT variable to add staging option if that was selected + CUSTOM_CA_SERVER_OPT_MULTI="--server https://acme-staging-v02.api.letsencrypt.org/directory" + fi - ORIGCUSTOM_CA_PATH=/config/custom_ca/$ORIGCUSTOM_CA - ORIGCUSTOM_CA_SERVER_OPT="--server $ORIGCUSTOM_CA_SERVER" + if [ -f /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"/fullchain.pem ] + then - fi + REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH_MULTI certbot revoke --non-interactive --agree-tos --email $EMAIL_MULTI --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"/fullchain.pem ${CUSTOM_CA_SERVER_OPT_MULTI} || true - if [ $ORIGSTAGING = "true" ] - then + rm -rf /config/letsencrypt/archive/"${FIRST_DOMAIN_MULTI}" + rm -rf /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}" + rm -rf /config/letsencrypt/renewal/"${FIRST_DOMAIN_MULTI}".conf - # Reusing the CUSTOM_CA_SERVER_OPT variable to add staging option if that was selected - ORIGCUSTOM_CA_SERVER_OPT="--server https://acme-staging-v02.api.letsencrypt.org/directory" + fi - fi + # Delete .donoteditthisfile_cert_${x} + rm -rf /config/.donoteditthisfile_cert_${x} - if [ -f /config/letsencrypt/live/"${FIRST_DOMAIN}"/fullchain.pem ] - then + # Scrubbing variables before running next cert revoke to prevent overlap of values + DOMAINS_MULTI= + EMAIL_MULTI= + STAGING_MULTI= + CUSTOM_CA_MULTI= + CUSTOM_CA_SERVER_MULTI= + PLUGIN_MULTI= + PROPOGATION_TIME_MULTI= + CLOUDFLARE_TOKEN_MULTI= + CUSTOM_CA_PATH_MULTI= + CUSTOM_CA_SERVER_OPT_MULTI= - REQUESTS_CA_BUNDLE=$ORIGCUSTOM_CA_PATH certbot revoke --non-interactive --agree-tos --email $ORIGEMAIL --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/"${FIRST_DOMAIN}"/fullchain.pem $ORIGCUSTOM_CA_SERVER_OPT || true + x=$(( $x + 1 )) - rm -rf /config/letsencrypt/archive/"${FIRST_DOMAIN}" - rm -rf /config/letsencrypt/live/"${FIRST_DOMAIN}" - rm -rf /config/letsencrypt/renewal/"${FIRST_DOMAIN}".conf + done - fi + echo "Tidying up any potential lingering ACME challenges in /config/webroot from failed webroot activations" + rm -rf /config/webroot/.well-known/acme-challenge fi -# Update config file with new env vars -echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\"" > /config/.donoteditthisfile - function single_domain { + # Checking for changes to config file, revoke certs if necessary + if [ ! "${DOMAINS}" = "${ORIGDOMAINS}" ] || + [ ! "${EMAIL}" = "${ORIGEMAIL}" ] || + [ ! "${STAGING}" = "${ORIGSTAGING}" ] || + [ ! "${CUSTOM_CA}" = "${ORIGCUSTOM_CA}" ] || + [ ! "${CUSTOM_CA_SERVER}" = "${ORIGCUSTOM_CA_SERVER}" ] || + [ ! "${PLUGIN}" = "${ORIGPLUGIN}" ] || + [ ! "${PROPOGATION_TIME}" = "${ORIGPROPOGATION_TIME}" ] + then + + echo "" + + echo "Configuration has changed since the last certificate was issued. Revoking and regenerating certs" + FIRST_DOMAIN=$(echo $ORIGDOMAINS | cut -d \, -f1) + + if [ ! -z $ORIGCUSTOM_CA ] + then + + echo "A custom CA was used for issuing. Using it to revoke as well." + + if [ ! -d /config/custom_ca ] + then + mkdir /config/custom_ca + echo "Please place the custom CA root file used to generate the current certificate into /config/custom_ca and restart the container" + better_exit + fi + + if [ -z "$(ls -A /config/custom_ca)" ] + then + echo "A root certificate called ${ORIGCUSTOM_CA} was used to generate a certificate, but the /config/custom_ca dir is now empty. Please place this root certificate back this directory and restart the container so it can be safely revoked" + better_exit + fi + + ORIGCUSTOM_CA_PATH=/config/custom_ca/$ORIGCUSTOM_CA + ORIGCUSTOM_CA_SERVER_OPT="--server $ORIGCUSTOM_CA_SERVER" + + fi + + if [ $ORIGSTAGING = "true" ] + then + + # Reusing the CUSTOM_CA_SERVER_OPT variable to add staging option if that was selected + ORIGCUSTOM_CA_SERVER_OPT="--server https://acme-staging-v02.api.letsencrypt.org/directory" + + fi + + if [ -f /config/letsencrypt/live/"${FIRST_DOMAIN}"/fullchain.pem ] + then + + REQUESTS_CA_BUNDLE=$ORIGCUSTOM_CA_PATH certbot revoke --non-interactive --agree-tos --email $ORIGEMAIL --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/"${FIRST_DOMAIN}"/fullchain.pem $ORIGCUSTOM_CA_SERVER_OPT || true + + rm -rf /config/letsencrypt/archive/"${FIRST_DOMAIN}" + rm -rf /config/letsencrypt/live/"${FIRST_DOMAIN}" + rm -rf /config/letsencrypt/renewal/"${FIRST_DOMAIN}".conf + + fi + + fi + + # Update config file with new env vars + echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\" ORIGCERT_COUNT=${CERT_COUNT}" > /config/.donoteditthisfile + + echo "" + if [ ! -z $CUSTOM_CA ] then @@ -117,19 +240,19 @@ function single_domain { then mkdir /config/custom_ca echo "Please place your custom CA file into /config/custom_ca and restart the container" - exit 1 + better_exit fi if [ -z "$(ls -A /config/custom_ca)" ] then echo "The CUSTOM_CA option is populated, but the /config/custom_ca dir is empty. Please place your root certificate in this directory and restart the container" - exit 1 + better_exit fi if [ -z $CUSTOM_CA_SERVER ] then echo "CUSTOM_CA_SERVER has not been defined. It is required for using a custom CA to issue a certificate" - exit 1 + better_exit fi CUSTOM_CA_PATH=/config/custom_ca/$CUSTOM_CA @@ -139,7 +262,7 @@ function single_domain { then echo "Staging option is not supported when using a custom CA. To remove this alert, set staging to false. If your CA has a standing endpoint, use the CUSTOM_CA_SERVER option to point to it instead" - exit 1 + better_exit fi @@ -170,7 +293,7 @@ function single_domain { then echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done by setting CLOUDFLARE_TOKEN, or by editing /config/.secrets/cloudflare.ini directly" - exit 1 + better_exit fi #Securing cloudflare.ini to supress warnings @@ -195,7 +318,7 @@ function single_domain { else echo "Unrecognised option for STAGING variable - check your configuration" - exit 1 + better_exit fi ## Run with Standalone plugin @@ -221,7 +344,7 @@ function single_domain { else echo "Unrecognised option for STAGING variable - check your configuration" - exit 1 + better_exit fi ## Run with webroot plugin @@ -247,7 +370,7 @@ function single_domain { else echo "Unrecognised option for STAGING variable - check your configuration" - exit 1 + better_exit fi else @@ -256,20 +379,384 @@ function single_domain { fi - if [ $GENERATE_DHPARAM = true ] && [ ! -s /config/letsencrypt/keys/ssl-dhparams.pem ] - then - echo "Generating Diffie-Hellman keys, saved to /config/letsencrypt/keys" - openssl dhparam -out /config/letsencrypt/keys/ssl-dhparams.pem 4096 - fi +} - echo "$INTERVAL /certbot-renew.sh >> /config/logs/renew.log" > /config/.crontab.txt +function multi_domain { - echo "Starting automatic renewal job. Schedule is $INTERVAL" - crontab /config/.crontab.txt + # Update config file with new env vars + echo -e "ORIGDOMAINS=\"${DOMAINS}\" ORIGEMAIL=\"${EMAIL}\" ORIGSTAGING=\"${STAGING}\" ORIGCUSTOM_CA=\"${CUSTOM_CA}\" ORIGCUSTOM_CA_SERVER=\"${CUSTOM_CA_SERVER}\" ORIGPLUGIN=\"${PLUGIN}\" ORIGPROPOGATION_TIME=\"${PROPOGATION_TIME}\" ORIGCERT_COUNT=${CERT_COUNT}" > /config/.donoteditthisfile + + ## Start multi-domain looper + x=1 + while [ $x -le $CERT_COUNT ] + do + + # Setting up variables (requires two passes to clean away requirement for indirect variable) + ## Pass 1 + DOMAINS_P1=DOMAINS_${x} + EMAIL_P1=EMAIL_${x} + STAGING_P1=STAGING_${x} + CUSTOM_CA_P1=CUSTOM_CA_${x} + CUSTOM_CA_SERVER_P1=CUSTOM_CA_SERVER_${x} + PLUGIN_P1=PLUGIN_${x} + PROPOGATION_TIME_P1=PROPOGATION_TIME_${x} + CLOUDFLARE_TOKEN_P1=CLOUDFLARE_TOKEN_${x} + + ## Pass 2 + DOMAINS_MULTI=${!DOMAINS_P1} + EMAIL_MULTI=${!EMAIL_P1} + STAGING_MULTI=${!STAGING_P1} + CUSTOM_CA_MULTI=${!CUSTOM_CA_P1} + CUSTOM_CA_SERVER_MULTI=${!CUSTOM_CA_SERVER_P1} + PLUGIN_MULTI=${!PLUGIN_P1} + PROPOGATION_TIME_MULTI=${!PROPOGATION_TIME_P1} + CLOUDFLARE_TOKEN_MULTI=${!CLOUDFLARE_TOKEN_P1} + + # Inheriting global default if undefined for certain variables + if [ -z ${EMAIL_MULTI} ]; then + EMAIL_MULTI=${EMAIL} + fi + + if [ -z ${STAGING_MULTI} ]; then + STAGING_MULTI=${STAGING} + fi + + if [ -z ${CUSTOM_CA_MULTI} ]; then + CUSTOM_CA_MULTI=${CUSTOM_CA} + fi + + if [ -z ${CUSTOM_CA_SERVER_MULTI} ]; then + CUSTOM_CA_SERVER_MULTI=${CUSTOM_CA_SERVER} + fi + + if [ -z ${PLUGIN_MULTI} ]; then + PLUGIN_MULTI=${PLUGIN} + fi + + if [ -z ${PROPOGATION_TIME_MULTI} ]; then + PROPOGATION_TIME_MULTI=${PROPOGATION_TIME} + fi + + # Create original config file to track changes to environmental variables + if [ ! -f /config/.donoteditthisfile_cert_${x} ] + then + echo -e "ORIGDOMAINS_${x}=\"${DOMAINS_MULTI}\" ORIGEMAIL_${x}=\"${EMAIL_MULTI}\" ORIGSTAGING_${x}=\"${STAGING_MULTI}\" ORIGCUSTOM_CA_${x}=\"${CUSTOM_CA_MULTI}\" ORIGCUSTOM_CA_SERVER_${x}=\"${CUSTOM_CA_SERVER_MULTI}\" ORIGPLUGIN_${x}=\"${PLUGIN_MULTI}\" ORIGPROPOGATION_TIME_${x}=\"${PROPOGATION_TIME_MULTI}\"" > /config/.donoteditthisfile_cert_${x} + fi + + # Load original config file + . /config/.donoteditthisfile_cert_${x} + + ORIGDOMAINS_MULTI=ORIGDOMAINS_${x} + ORIGEMAIL_MULTI=ORIGEMAIL_${x} + ORIGSTAGING_MULTI=ORIGSTAGING_${x} + ORIGCUSTOM_CA_MULTI=ORIGCUSTOM_CA_${x} + ORIGCUSTOM_CA_SERVER_MULTI=ORIGCUSTOM_CA_SERVER_${x} + ORIGPLUGIN_MULTI=ORIGPLUGIN_${x} + ORIGPROPOGATION_TIME_MULTI=ORIGPROPOGATION_TIME_${x} + ORIGCLOUDFLARE_TOKEN_MULTI=ORIGCLOUDFLARE_TOKEN_${x} + + # Log variables to console (have to remove indent because bash dumb) + + echo " +---------------------------------------------------------------------- +CERTIFICATE ${x} ENVIRONMENT +----------------------------------------------------------------------" +echo \ +"DOMAINS_${x}=${DOMAINS_MULTI} +EMAIL_${x}=${EMAIL_MULTI} +STAGING_${x}=${STAGING_MULTI} +CUSTOM_CA_${x}=${CUSTOM_CA_MULTI} +CUSTOM_CA_SERVER_${x}=${CUSTOM_CA_SERVER_MULTI} +PLUGIN_${x}=${PLUGIN_MULTI}" +## Get plugin-specific data if single certificate config +if [ ${PLUGIN_MULTI} == 'cloudflare' ]; then +echo \ +"PROPOGATION_TIME_${x}=${PROPOGATION_TIME_MULTI}" +fi +if [ ${PLUGIN_MULTI} == 'cloudflare' ] && [ ! -z ${CLOUDFLARE_TOKEN_MULTI} ]; then +echo \ +"CLOUDFLARE_TOKEN_${x}=[hidden]" +elif [ ${PLUGIN_MULTI} == 'cloudflare' ] && [ -z ${CLOUDFLARE_TOKEN_MULTI} ]; then +echo \ +"CLOUDFLARE_TOKEN_${x}=" +fi +echo \ +"---------------------------------------------------------------------- +" + + # Begin actually requesting the certificate + + echo "Requesting certificate $x" + + # Checking for changes to config file, revoke certs if necessary + if [ ! "${DOMAINS_MULTI}" = "${!ORIGDOMAINS_MULTI}" ] || + [ ! "${EMAIL_MULTI}" = "${!ORIGEMAIL_MULTI}" ] || + [ ! "${STAGING_MULTI}" = "${!ORIGSTAGING_MULTI}" ] || + [ ! "${CUSTOM_CA_MULTI}" = "${!ORIGCUSTOM_CA_MULTI}" ] || + [ ! "${CUSTOM_CA_SERVER_MULTI}" = "${!ORIGCUSTOM_CA_SERVER_MULTI}" ] || + [ ! "${PLUGIN_MULTI}" = "${!ORIGPLUGIN_MULTI}" ] || + [ ! "${PROPOGATION_TIME_MULTI}" = "${!ORIGPROPOGATION_TIME_MULTI}" ] + then + + echo "Configuration has changed since certificate ${x} was last issued. Revoking and regenerating cert ${x}" + FIRST_DOMAIN_MULTI=$(echo ${!ORIGDOMAINS_MULTI} | cut -d \, -f1) + + if [ ! -z ${!ORIGCUSTOM_CA_MULTI} ] + then + + echo "A custom CA was used for issuing certificate ${x}. Using it to revoke as well." + + if [ ! -d /config/custom_ca ] + then + mkdir /config/custom_ca + echo "Please place the custom CA root file used to generate the current certificate ${x} into /config/custom_ca and restart the container" + better_exit + fi + + if [ -z "$(ls -A /config/custom_ca)" ] + then + echo "A root certificate called ${!ORIGCUSTOM_CA_MULTI} was used to generate a certificate, but the /config/custom_ca dir is now empty. Please place this root certificate back this directory and restart the container so it can be safely revoked" + better_exit + fi + + ORIGCUSTOM_CA_PATH_MULTI=/config/custom_ca/${!ORIGCUSTOM_CA_MULTI} + ORIGCUSTOM_CA_SERVER_OPT_MULTI="--server ${!ORIGCUSTOM_CA_SERVER_MULTI}" + + fi + + if [ $ORIGSTAGING_MULTI = "true" ] + then + + # Reusing the CUSTOM_CA_SERVER_OPT variable to add staging option if that was selected + ORIGCUSTOM_CA_SERVER_OPT_MULTI="--server https://acme-staging-v02.api.letsencrypt.org/directory" + + fi + + if [ -f /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"/fullchain.pem ] + then + + REQUESTS_CA_BUNDLE=$ORIGCUSTOM_CA_PATH_MULTI certbot revoke --non-interactive --agree-tos --email $ORIGEMAIL_MULTI --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --cert-path /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}"/fullchain.pem ${ORIGCUSTOM_CA_SERVER_OPT_MULTI} || true + + rm -rf /config/letsencrypt/archive/"${FIRST_DOMAIN_MULTI}" + rm -rf /config/letsencrypt/live/"${FIRST_DOMAIN_MULTI}" + rm -rf /config/letsencrypt/renewal/"${FIRST_DOMAIN_MULTI}".conf + + fi + + echo "Tidying up any potential lingering ACME challenges in /config/webroot from failed webroot activations" + rm -rf /config/webroot/.well-known/acme-challenge + + fi + + # Update config file with new cert-specific env vars + echo -e "ORIGDOMAINS_${x}=\"${DOMAINS_MULTI}\" ORIGEMAIL_${x}=\"${EMAIL_MULTI}\" ORIGSTAGING_${x}=\"${STAGING_MULTI}\" ORIGCUSTOM_CA_${x}=\"${CUSTOM_CA_MULTI}\" ORIGCUSTOM_CA_SERVER_${x}=\"${CUSTOM_CA_SERVER_MULTI}\" ORIGPLUGIN_${x}=\"${PLUGIN_MULTI}\" ORIGPROPOGATION_TIME_${x}=\"${PROPOGATION_TIME_MULTI}\"" > /config/.donoteditthisfile_cert_${x} + + if [ ! -z ${CUSTOM_CA_MULTI} ] + then + + echo "Using a custom CA for issuing certificate ${x}" + + if [ ! -d /config/custom_ca ] + then + mkdir /config/custom_ca + echo "Please place your custom CA file into /config/custom_ca and restart the container" + better_exit + fi + + if [ -z "$(ls -A /config/custom_ca)" ] + then + echo "The CUSTOM_CA_${x} option is populated, but the /config/custom_ca dir is empty. Please place your root certificate for certificate ${x} in this directory and restart the container" + better_exit + fi + + if [ -z ${CUSTOM_CA_SERVER_MULTI} ] + then + echo "CUSTOM_CA_SERVER_${x} has not been defined. It is required when using a custom CA to issue certificate ${x}" + better_exit + fi + + CUSTOM_CA_PATH_MULTI=/config/custom_ca/${CUSTOM_CA_MULTI} + CUSTOM_CA_SERVER_OPT_MULTI="--server ${CUSTOM_CA_SERVER_MULTI}" + + if [ ${STAGING_MULTI} = "true" ] + then + + echo "Staging option is not supported when using a custom CA. To remove this alert, set staging to false. If your CA has a standing endpoint, use the CUSTOM_CA_SERVER_${x} option to point to it instead" + better_exit + + fi + + fi + + BASE_COMMAND=(certbot certonly --non-interactive --config-dir /config/letsencrypt --work-dir /config/.tmp --logs-dir /config/logs --key-path /config/letsencrypt/keys --expand --agree-tos "${CUSTOM_CA_SERVER_OPT_MULTI}" --email "${EMAIL_MULTI}" -d "${DOMAINS_MULTI}") + + ## Run with Cloudflare plugin + if [ ${PLUGIN_MULTI} == "cloudflare" ] + then + + echo "Using Cloudflare plugin" + + if [ ! -f /config/.secrets/cloudflare.ini ] + then + touch /config/.secrets/cloudflare.ini + fi + + if [ -n "${CLOUDFLARE_TOKEN_MULTI}" ] + then + echo "Cloudflare token is present" + + echo "dns_cloudflare_api_token = ${CLOUDFLARE_TOKEN_MULTI}" > /config/.secrets/cloudflare.ini + + fi + + if [ ! -s /config/.secrets/cloudflare.ini ] + then + echo "cloudflare.ini is empty - please add your Cloudflare credentials or API key before continuing. This can be done by setting CLOUDFLARE_TOKEN_${x}" + + better_exit + fi + + #Securing cloudflare.ini to supress warnings + chmod 600 /config/.secrets/cloudflare.ini + + echo "Creating certificates, or attempting to renew if they already exist" + + if [ ${STAGING_MULTI} = true ] + then + echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" + ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds ${PROPOGATION_TIME_MULTI} --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging + # Add to renewal list + echo "## Certificate ${x}" >> /config/.renew-list.sh + echo "${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds ${PROPOGATION_TIME_MULTI} --dns-cloudflare-credentials /config/.secrets/cloudflare.ini --staging" >> /config/.renew-list.sh + echo "" >> /config/.renew-list.sh + echo "Creation/renewal attempt complete" + elif [ ${STAGING_MULTI} = false ] + then + echo "Using production endpoint" + ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds ${PROPOGATION_TIME_MULTI} --dns-cloudflare-credentials /config/.secrets/cloudflare.ini + # Add to renewal list + echo "## Certificate ${x}" >> /config/.renew-list.sh + echo "REQUESTS_CA_BUNDLE=$CUSTOM_CA_PATH ${BASE_COMMAND[@]} --dns-cloudflare --dns-cloudflare-propagation-seconds ${PROPOGATION_TIME_MULTI} --dns-cloudflare-credentials /config/.secrets/cloudflare.ini" >> /config/.renew-list.sh + echo "" >> /config/.renew-list.sh + echo "Creation/renewal attempt complete" + else + echo "Unrecognised option for STAGING variable - check your configuration" + + better_exit + fi + + ## Run with Standalone plugin + elif [ ${PLUGIN_MULTI} == "standalone" ] + then + + echo "Using HTTP verification via built-in web-server - please ensure port 80 is exposed." + + if [ ${STAGING_MULTI} = true ] + then + echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" + REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --standalone --staging + # Add to renewal list + echo "## Certificate ${x}" >> /config/.renew-list.sh + echo "REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --standalone --staging" >> /config/.renew-list.sh + echo "" >> /config/.renew-list.sh + echo "Creation/renewal attempt complete" + elif [ ${STAGING_MULTI} = false ] + then + echo "Using production endpoint" + REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --standalone + # Add to renewal list + echo "## Certificate ${x}" >> /config/.renew-list.sh + echo "REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --standalone" >> /config/.renew-list.sh + echo "" >> /config/.renew-list.sh + echo "Creation/renewal attempt complete" + else + echo "Unrecognised option for STAGING variable - check your configuration" + + better_exit + fi + + ## Run with webroot plugin + elif [ ${PLUGIN_MULTI} == "webroot" ] + then + + echo "Using HTTP verification via webroot - please ensure you have mounted a webroot at /config/webroot from a web-server reachable via the domain you are issuing a certificate for." + + if [ ${STAGING_MULTI} = true ] + then + echo "Using staging endpoint - THIS SHOULD BE USED FOR TESTING ONLY" + REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging + # Add to renewal list + echo "## Certificate ${x}" >> /config/.renew-list.sh + echo "REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot --staging" >> /config/.renew-list.sh + echo "" >> /config/.renew-list.sh + echo "Creation/renewal attempt complete" + elif [ ${STAGING_MULTI} = false ] + then + echo "Using production endpoint" + REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot + # Add to renewal list + echo "## Certificate ${x}" >> /config/.renew-list.sh + echo "REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH_MULTI} ${BASE_COMMAND[@]} --webroot --webroot-path /config/webroot" >> /config/.renew-list.sh + echo "" >> /config/.renew-list.sh + echo "Creation/renewal attempt complete" + else + echo "Unrecognised option for STAGING variable - check your configuration" + + better_exit + fi + + else + + echo "Unrecognised option for PLUGIN variable - check your configuration" + + fi + + # Scrubbing variables before running next cert to prevent overlap of values + DOMAINS_MULTI= + EMAIL_MULTI= + STAGING_MULTI= + CUSTOM_CA_MULTI= + CUSTOM_CA_SERVER_MULTI= + PLUGIN_MULTI= + PROPOGATION_TIME_MULTI= + CLOUDFLARE_TOKEN_MULTI= + CUSTOM_CA_PATH_MULTI= + CUSTOM_CA_SERVER_OPT_MULTI= + ORIGDOMAINS_MULTI= + ORIGEMAIL_MULTI= + ORIGSTAGING_MULTI= + ORIGCUSTOM_CA_MULTI= + ORIGCUSTOM_CA_SERVER_MULTI= + ORIGPLUGIN_MULTI= + ORIGPROPOGATION_TIME_MULTI= + ORIGCLOUDFLARE_TOKEN_MULTI= + FIRST_DOMAIN_MULTI= + ORIGCUSTOM_CA_PATH_MULTI= + ORIGCUSTOM_CA_SERVER_OPT_MULTI= + + x=$(( $x + 1 )) + + done } if [ $CERT_COUNT == 1 ] then single_domain -fi \ No newline at end of file +elif [ $CERT_COUNT -gt 1 ] +then + multi_domain +else + echo "CERT_COUNT varaible not recognised. It needs to be a value of 1 or greater." +fi + +if [ $GENERATE_DHPARAM = true ] && [ ! -s /config/letsencrypt/keys/ssl-dhparams.pem ] +then + echo "Generating Diffie-Hellman keys, saved to /config/letsencrypt/keys. This can take a long time!" + openssl dhparam -out /config/letsencrypt/keys/ssl-dhparams.pem 4096 +fi + +echo "$INTERVAL /certbot-renew.sh >> /config/logs/renew.log" > /config/.crontab.txt + +echo "Starting automatic renewal job. Schedule is $INTERVAL" +crontab /config/.crontab.txt \ No newline at end of file diff --git a/root/container-init.sh b/root/container-init.sh index 180aac6..10683bb 100644 --- a/root/container-init.sh +++ b/root/container-init.sh @@ -13,17 +13,48 @@ echo "| |" echo "================================================" echo "" echo "Initialising container" -echo " ----------------------------------------------------------------------- -ENVIRONMENT (only core variables shown) ----------------------------------------------------------------------- -PUID=${PUID} +if [ ${CERT_COUNT} == 1 ]; then +echo \ +"---------------------------------------------------------------------- +ENVIRONMENT +----------------------------------------------------------------------" +else +echo \ +"---------------------------------------------------------------------- +ENVIRONMENT (Certificate options logged later) +----------------------------------------------------------------------" +fi +echo \ +"PUID=${PUID} PGID=${PGID} TZ=${TZ} INTERVAL=${INTERVAL} GENERATE_DHPARAM=${GENERATE_DHPARAM} -CERT_COUNT=${CERT_COUNT} ----------------------------------------------------------------------- +CERT_COUNT=${CERT_COUNT}" +## Send extra detail to logs if single certificate config +if [ ${CERT_COUNT} == 1 ]; then +echo \ +"DOMAINS=${DOMAINS} +EMAIL=${EMAIL} +STAGING=${STAGING} +CUSTOM_CA=${CUSTOM_CA} +CUSTOM_CA_SERVER=${CUSTOM_CA_SERVER} +PLUGIN=${PLUGIN}" +fi +## Get plugin-specific data if single certificate config +if [ ${CERT_COUNT} == 1 ] && [ ${PLUGIN} == 'cloudflare' ]; then +echo \ +"PROPOGATION_TIME=${PROPOGATION_TIME}" +fi +if [ ${CERT_COUNT} == 1 ] && [ ${PLUGIN} == 'cloudflare' ] && [ ! -z ${CLOUDFLARE_TOKEN} ]; then +echo \ +"CLOUDFLARE_TOKEN=[hidden]" +elif [ ${CERT_COUNT} == 1 ] && [ ${PLUGIN} == 'cloudflare' ] && [ -z ${CLOUDFLARE_TOKEN} ]; then +echo \ +"CLOUDFLARE_TOKEN=" +fi +echo \ +"---------------------------------------------------------------------- " #Setting UID and GID as configured From ada326f2d801744240535f3726ac887a42724273 Mon Sep 17 00:00:00 2001 From: MrMeeb Date: Sun, 16 Jul 2023 16:45:36 +0000 Subject: [PATCH 4/4] tweak log formatting --- root/certbot-prepare.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/root/certbot-prepare.sh b/root/certbot-prepare.sh index f65f2fd..55c2c41 100644 --- a/root/certbot-prepare.sh +++ b/root/certbot-prepare.sh @@ -498,6 +498,8 @@ echo \ [ ! "${PROPOGATION_TIME_MULTI}" = "${!ORIGPROPOGATION_TIME_MULTI}" ] then + echo "" + echo "Configuration has changed since certificate ${x} was last issued. Revoking and regenerating cert ${x}" FIRST_DOMAIN_MULTI=$(echo ${!ORIGDOMAINS_MULTI} | cut -d \, -f1) @@ -551,6 +553,8 @@ echo \ # Update config file with new cert-specific env vars echo -e "ORIGDOMAINS_${x}=\"${DOMAINS_MULTI}\" ORIGEMAIL_${x}=\"${EMAIL_MULTI}\" ORIGSTAGING_${x}=\"${STAGING_MULTI}\" ORIGCUSTOM_CA_${x}=\"${CUSTOM_CA_MULTI}\" ORIGCUSTOM_CA_SERVER_${x}=\"${CUSTOM_CA_SERVER_MULTI}\" ORIGPLUGIN_${x}=\"${PLUGIN_MULTI}\" ORIGPROPOGATION_TIME_${x}=\"${PROPOGATION_TIME_MULTI}\"" > /config/.donoteditthisfile_cert_${x} + echo "" + if [ ! -z ${CUSTOM_CA_MULTI} ] then @@ -758,5 +762,7 @@ fi echo "$INTERVAL /certbot-renew.sh >> /config/logs/renew.log" > /config/.crontab.txt +echo "" + echo "Starting automatic renewal job. Schedule is $INTERVAL" crontab /config/.crontab.txt \ No newline at end of file