diff --git a/.gitea/workflows/build-main.yaml b/.gitea/workflows/build-main.yaml index 83af6eb..e432081 100644 --- a/.gitea/workflows/build-main.yaml +++ b/.gitea/workflows/build-main.yaml @@ -2,7 +2,7 @@ name: Build Image on: push: branches: - - 'main' + - 'master' env: TEST_TAG: mrmeeb/certbot-cron:test diff --git a/.gitea/workflows/test-pr.yaml b/.gitea/workflows/test-pr.yaml index e4597f8..7ec428c 100644 --- a/.gitea/workflows/test-pr.yaml +++ b/.gitea/workflows/test-pr.yaml @@ -2,7 +2,7 @@ name: Test Pull Request on: pull_request: branches: - - 'main' + - 'master' - 'develop' env: diff --git a/Dockerfile b/Dockerfile index 0a68427..a0b96dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.19.1 as base +FROM alpine:3.20.0 as base ARG TARGETARCH FROM base AS base-amd64 @@ -18,6 +18,9 @@ ENV TZ=UTC ENV GENERATE_DHPARAM=true ENV INTERVAL="0 */6 * * *" ENV ONE_SHOT=false +ENV APPRISE_URL= +ENV NOTIFY_ON_FAILURE=false +ENV NOTIFY_ON_SUCCESS=false # Single domain ENV DOMAINS= @@ -59,18 +62,16 @@ RUN python3 -m venv /app/certbot/ && /app/certbot/bin/pip install --upgrade pip #Added additional pip steps to fix cython 3.0.0 issue - https://github.com/yaml/pyyaml/issues/601 COPY requirements.txt /app/certbot/requirements.txt RUN apk add --no-cache --virtual .deps gcc python3-dev libc-dev libffi-dev && \ - /app/certbot/bin/pip install wheel && \ + /app/certbot/bin/pip install wheel setuptools && \ /app/certbot/bin/pip install "Cython<3.0" pyyaml --no-build-isolation && \ /app/certbot/bin/pip install -r /app/certbot/requirements.txt && \ - ln -s /app/certbot/bin/certbot /usr/bin/certbot &&\ + ln -s /app/certbot/bin/certbot /usr/bin/certbot && \ + ln -s /app/certbot/bin/apprise /usr/bin/apprise && \ apk del .deps COPY root / -RUN chmod +x /container-init.sh && \ - chmod +x /certbot-prepare.sh && \ - chmod +x /certbot-renew.sh && \ - chmod +x /check-one-shot.sh && \ +RUN chmod +x /container-init.sh /certbot-prepare.sh /check-one-shot.sh /renew-function.sh && \ chown -R ${PUID}:${PGID} /app /config ENTRYPOINT [ "/init" ] diff --git a/README.md b/README.md index 25c3564..8d66f82 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,9 @@ Core options to 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. [Details here](https://git.mrmeeb.stream/MrMeeb/certbot-cron-docker#multiple-certificates) | +| APPRISE_URL | None | URL for Apprise notifications. [Syntax](https://github.com/caronc/apprise?tab=readme-ov-file#supported-notifications) +| NOTIFY_ON_SUCCESS | false | Notify on a successful renewal attempt. Note that this isn't just when the cert is renewed, but on every renewal attempt. | +| NOTIFY_ON_FAILURE | false | Notify on a failed renewal attempt. ### Certificate Options diff --git a/renovate.json b/renovate.json index d3e4131..afef6ff 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,6 @@ { "extends": [":automergeMinor", ":automergePr", ":automergeRequireAllStatusChecks", ":dependencyDashboard", ":disableRateLimiting", ":rebaseStalePrs"], - "baseBranches": ["main"], + "baseBranches": ["master"], "major": { "dependencyDashboardApproval": true }, diff --git a/requirements.txt b/requirements.txt index da8860e..cb0d741 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ -# For pinning Certbot packages to then be parsed by Renovate +# For pinning Python packages to then be parsed by Renovate -certbot ==2.9.0 -certbot-dns-cloudflare ==2.9.0 \ No newline at end of file +certbot ==2.10.0 +certbot-dns-cloudflare ==2.10.0 +apprise ==1.8.0 \ No newline at end of file diff --git a/root/certbot-prepare.sh b/root/certbot-prepare.sh index 950a130..6c4d93f 100644 --- a/root/certbot-prepare.sh +++ b/root/certbot-prepare.sh @@ -46,9 +46,22 @@ function better_exit { } +# Check APPRISE_URL is set if either NOTIFY_ON_SUCCESS or NOTIFY_ON_FAILURE are set +if [ ! -z "${NOTIFY_ON_SUCCESS}" ] || [ ! -z "${NOTIFY_ON_FAILURE}" ] && [ -z "${APPRISE_URL}" ]; then + + echo "You have notifications enabled but have not set APPRISE_URL. Please set APPRISE_URL and restart the container." + better_exit + +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 -echo "" >> /config/.renew-list.sh +echo "#!/command/with-contenv bash + +date +echo \"Attempting to renew certificates\" +source /renew-function.sh +" > /config/.renew-list.sh +chmod +x /config/.renew-list.sh # Create original config file to track changes to environmental variables if [ ! -f /config/.donoteditthisfile ] @@ -306,14 +319,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 "renew \"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 "renew \"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" @@ -332,14 +345,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 "renew \"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 "renew \"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" @@ -358,14 +371,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 "renew \"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 "renew \"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" @@ -631,7 +644,7 @@ echo \ ${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 "renew \"${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 ] @@ -640,7 +653,7 @@ echo \ ${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 "renew \"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 @@ -661,7 +674,7 @@ echo \ 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 "renew \"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 ] @@ -670,7 +683,7 @@ echo \ 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 "renew \"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 @@ -691,7 +704,7 @@ echo \ 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 "renew \"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 ] @@ -700,7 +713,7 @@ echo \ 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 "renew \"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 @@ -754,6 +767,10 @@ else echo "CERT_COUNT varaible not recognised. It needs to be a value of 1 or greater." fi +# Finish /config/.renew-list.sh now all certs have been added +echo " +echo \"Renewal attempts complete\"" >> /config/.renew-list.sh + if [ $GENERATE_DHPARAM = true ] && [ ! -s /config/letsencrypt/keys/ssl-dhparams.pem ] then echo "" @@ -769,7 +786,7 @@ if [ $ONE_SHOT == "true" ]; then elif [ $ONE_SHOT == "false" ]; then - echo "$INTERVAL /certbot-renew.sh >> /config/logs/renew.log" > /config/.crontab.txt + echo "$INTERVAL /config/.renew-list.sh >> /config/logs/renew.log" > /config/.crontab.txt echo "" diff --git a/root/certbot-renew.sh b/root/certbot-renew.sh deleted file mode 100644 index acedd1c..0000000 --- a/root/certbot-renew.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/command/with-contenv bash -# shellcheck shell=bash -echo '' -date -echo "Attempting to renew certificates" -bash /config/.renew-list.sh \ No newline at end of file diff --git a/root/container-init.sh b/root/container-init.sh index 87406fa..b7b1f86 100644 --- a/root/container-init.sh +++ b/root/container-init.sh @@ -31,7 +31,13 @@ TZ=${TZ} ONE_SHOT=${ONE_SHOT} INTERVAL=${INTERVAL} GENERATE_DHPARAM=${GENERATE_DHPARAM} -CERT_COUNT=${CERT_COUNT}" +CERT_COUNT=${CERT_COUNT} +NOTIFY_ON_SUCCESS=${NOTIFY_ON_SUCCESS} +NOTIFY_ON_FAILURE=${NOTIFY_ON_FAILURE}" +if [ ! -z ${APPRISE_URL} ]; then +echo \ +"APPRISE_URL=[hidden]" +fi ## Send extra detail to logs if single certificate config if [ ${CERT_COUNT} == 1 ]; then echo \ diff --git a/root/renew-function.sh b/root/renew-function.sh new file mode 100644 index 0000000..6f342b0 --- /dev/null +++ b/root/renew-function.sh @@ -0,0 +1,27 @@ +function renew() { + + #Variables: + + #$1 = Certbot command + + RENEWAL_DOMAINS=$(echo $1 | sed -r 's/.*\s-d\s(\S*).*/\1/') + CUSTOM_CA_PATH=$(echo $1 | sed -r 's/REQUESTS_CA_BUNDLE=(\S*)\s(.*)/\1/') + CERTBOT_COMMAND=$(echo $1 | sed -r 's/REQUESTS_CA_BUNDLE=(\S*)\s(.*)/\2/') + + echo "Renewing certificate for ${RENEWAL_DOMAINS}" + + echo "REQUESTS_CA_BUNDLE=${CUSTOM_CA_PATH} ${CERTBOT_COMMAND}" | bash + + if [ $? = 0 ]; then + echo "Renewal attempt of certificate for ${RENEWAL_DOMAINS} succeeded" + if [ "${NOTIFY_ON_SUCCESS}" = "true" ]; then + apprise -b "Renewal of certificate for ${RENEWAL_DOMAINS} succeeded" ${APPRISE_URL} + fi + else + echo "Renewal attempt of certificate for ${RENEWAL_DOMAINS} failed" + if [ "${NOTIFY_ON_FAILURE}" = "true" ]; then + apprise -b "Renewal of certificate for ${RENEWAL_DOMAINS} failed" ${APPRISE_URL} + fi + fi + +} \ No newline at end of file