From 3bd0027a3e2580595cd344b9d083d2c9ae4024e2 Mon Sep 17 00:00:00 2001 From: Maksim <18454392+maksimstojkovic@users.noreply.github.com> Date: Wed, 18 Aug 2021 19:11:48 +1000 Subject: [PATCH] resolved bug with email input * added UID and GID environment variables * updated docs --- .dockerignore | 10 ++++ .github/workflows/docker-build.yml | 0 .gitignore | 3 ++ Dockerfile | 4 +- LICENSE | 0 README.md | 16 ++++--- scripts/auth.sh | 0 scripts/cert.sh | 37 -------------- scripts/cleanup.sh | 0 scripts/start.sh | 77 ++++++++++++++++++++++++------ 10 files changed, 86 insertions(+), 61 deletions(-) create mode 100644 .dockerignore mode change 100755 => 100644 .github/workflows/docker-build.yml create mode 100644 .gitignore mode change 100755 => 100644 Dockerfile mode change 100755 => 100644 LICENSE mode change 100755 => 100644 README.md mode change 100755 => 100644 scripts/auth.sh delete mode 100755 scripts/cert.sh mode change 100755 => 100644 scripts/cleanup.sh mode change 100755 => 100644 scripts/start.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..123a9ed --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.git +.github +certs + +.dockerignore +.gitignore +Dockerfile +letsencrypt.env +LICENSE +README.md diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml old mode 100755 new mode 100644 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68e0f89 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +certs + +letsencrypt.env diff --git a/Dockerfile b/Dockerfile old mode 100755 new mode 100644 index 663d1e0..53d8003 --- a/Dockerfile +++ b/Dockerfile @@ -2,17 +2,15 @@ FROM alpine:latest # Maintainer information -ARG VCS_REF LABEL maintainer="Maksim Stojkovic " \ - org.label-schema.vcs-ref=$VCS_REF \ org.label-schema.vcs-url="https://github.com/maksimstojkovic/docker-letsencrypt" # Install tools required RUN apk --no-cache add certbot curl # Copy scripts -COPY ./scripts /scripts WORKDIR /scripts +COPY ./scripts /scripts RUN chmod -R +x /scripts # Image starting command diff --git a/LICENSE b/LICENSE old mode 100755 new mode 100644 diff --git a/README.md b/README.md old mode 100755 new mode 100644 index 962c4d2..ca1ea9d --- a/README.md +++ b/README.md @@ -8,18 +8,20 @@ Automatically generates Let's Encrypt certificates using a lightweight Docker container without requiring any ports to be exposed for DNS challenges. -## Variables +## Environment Variables -* `DUCKDNS_TOKEN`: Duck DNS account token (obtained from [Duck DNS](https://www.duckdns.org)) -* `DUCKDNS_DOMAIN`: Full Duck DNS domain (e.g. `test.duckdns.org`) +* `DUCKDNS_TOKEN`: Duck DNS account token (obtained from [Duck DNS](https://www.duckdns.org)) (*required*) +* `DUCKDNS_DOMAIN`: Full Duck DNS domain (e.g. `test.duckdns.org`) (*required*) * `LETSENCRYPT_EMAIL`: Email used for certificate renewal notifications (optional) -* `LETSENCRYPT_WILDCARD`: `true` or `false`, indicating whether the SSL certificate should be for subdomains *only* of `DUCKDNS_DOMAIN` (i.e. `*.test.duckdns.org`), or for the main domain *only* (i.e. `test.duckdns.org`) (default: `false`) -* `TESTING`: `true` or `false`, indicating whether a staging SSL certificate should be generated or not (default: `false`) +* `LETSENCRYPT_WILDCARD`: `true` or `false`, indicating whether the SSL certificate should be for subdomains *only* of `DUCKDNS_DOMAIN` (i.e. `*.test.duckdns.org`), or for the main domain *only* (i.e. `test.duckdns.org`) (optional, default: `false`) +* `TESTING`: `true` or `false`, indicating whether a staging SSL certificate should be generated or not (optional, default: `false`) +* `UID`: User ID to apply to Let's Encrypt files generated (optional, recommended, default: `0` - root) +* `GID`: Group ID to apply to Let's Encrypt files generated (optional, recommended, default: `0` - root) **Note:** The format of `DUCKDNS_DOMAIN` should be the same regardless of the value of `LETSENCRYPT_WILDCARD`. ## Volumes -* `:/etc/letsencrypt`: A named or hosted volume which allows SSL certificates to persist and be accessed by other containers +* `:/etc/letsencrypt`: A named or host volume which allows SSL certificates to persist and be accessed by other containers -**Note:** If a hosted volume is used, the volume should be mounted in an unused directory in another container to prevent access conflicts. +**Note:** To use the `` host volume in another container, mount it as read-only for those containers. The `` host volume should be read-write enabled for the Letsencrypt container. diff --git a/scripts/auth.sh b/scripts/auth.sh old mode 100755 new mode 100644 diff --git a/scripts/cert.sh b/scripts/cert.sh deleted file mode 100755 index 45fd1da..0000000 --- a/scripts/cert.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -if [ -z "$LETSENCRYPT_EMAIL" ]; then - export EMAIL_PARAM="--register-unsafely-without-email" -else - export EMAIL_PARAM="-m ${LETSENCRYPT_EMAIL} --no-eff-email" -fi - -if [ ! -z "$TESTING" ]; then - echo NOTICE: Generating staging certificate - export TEST_PARAM="--staging" -fi - -# Initial check for certificates -certbot certonly --manual --preferred-challenges dns --manual-auth-hook \ - /scripts/auth.sh --manual-cleanup-hook /scripts/cleanup.sh \ - "${EMAIL_PARAM}" -d "${LETSENCRYPT_DOMAIN}" \ - --agree-tos --manual-public-ip-logging-ok --keep ${TEST_PARAM} - -# Basic check for successful certificate generation -if [ ! -d "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN}" ] || \ - [ ! -f "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN}/fullchain.pem" ] || \ - [ ! -f "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN}/privkey.pem" ]; then - echo ERROR: Failed to create SSL certificates - exit 1 -fi - -# Check if certificates require renewal twice a day -while :; do - # Wait for a random period within the next 12 hours - LETSENCRYPT_DELAY=$(shuf -i 1-720 -n 1) - echo Sleeping for $(($LETSENCRYPT_DELAY / 60)) hour\(s\) and $(($LETSENCRYPT_DELAY % 60)) minute\(s\) - sleep $((${LETSENCRYPT_DELAY} * 60)) - - echo Attempting SSL certificate renewal - certbot --manual-public-ip-logging-ok renew -done diff --git a/scripts/cleanup.sh b/scripts/cleanup.sh old mode 100755 new mode 100644 diff --git a/scripts/start.sh b/scripts/start.sh old mode 100755 new mode 100644 index 56b7099..efcbffd --- a/scripts/start.sh +++ b/scripts/start.sh @@ -2,35 +2,84 @@ # Check variables DUCKDNS_TOKEN, DUCKDNS_DOMAIN if [ -z "$DUCKDNS_TOKEN" ]; then - echo ERROR: Variable DUCKDNS_TOKEN is unset + echo "ERROR: Variable DUCKDNS_TOKEN is unset" exit 1 fi if [ -z "$DUCKDNS_DOMAIN" ]; then - echo ERROR: Variable DUCKDNS_DOMAIN is unset + echo "ERROR: Variable DUCKDNS_DOMAIN is unset" exit 1 fi # Print email notice if applicable if [ -z "$LETSENCRYPT_EMAIL" ]; then - echo NOTICE: You will not receive SSL certificate expiration notices + echo "INFO: You will not receive SSL certificate expiration notices" fi # Set certificate url based on LETSENCRYPT_WILDCARD value if [ "$LETSENCRYPT_WILDCARD" = "true" ]; then - echo NOTICE: A wildcard SSL certificate will be created - export LETSENCRYPT_DOMAIN=*.${DUCKDNS_DOMAIN} - export WILDCARD_STR="true" + echo "INFO: A wildcard SSL certificate will be created" + LETSENCRYPT_DOMAIN=*.$DUCKDNS_DOMAIN else - export LETSENCRYPT_DOMAIN=${DUCKDNS_DOMAIN} - export WILDCARD_STR="false" + LETSENCRYPT_DOMAIN=$DUCKDNS_DOMAIN + LETSENCRYPT_WILDCARD="false" +fi + +# Set user and group ID's for files +if [ -z "$UID" ]; then + echo "INFO: No UID specified, using root UID of 0" + UID=0 +fi + +if [ -z "$GID" ]; then + echo "INFO: No GID specified, using root GID of 0" + GID=0 fi # Print variables -echo DUCKDNS_TOKEN: $DUCKDNS_TOKEN -echo DUCKDNS_DOMAIN: $DUCKDNS_DOMAIN -echo LETSENCRYPT_EMAIL: $LETSENCRYPT_EMAIL -echo LETSENCRYPT_WILDCARD: $WILDCARD_STR \(Input: \"${LETSENCRYPT_WILDCARD}\"\) +echo "DUCKDNS_TOKEN: $DUCKDNS_TOKEN" +echo "DUCKDNS_DOMAIN: $DUCKDNS_DOMAIN" +echo "LETSENCRYPT_EMAIL: $LETSENCRYPT_EMAIL" +echo "LETSENCRYPT_WILDCARD: $LETSENCRYPT_WILDCARD" +echo "TESTING: $TESTING" +echo "UID: $UID" +echo "GID: $GID" -# Start automatic ssl certificate generation -/bin/sh /scripts/cert.sh +if [ -z "$LETSENCRYPT_EMAIL" ]; then + EMAIL_PARAM="--register-unsafely-without-email" +else + EMAIL_PARAM="-m $LETSENCRYPT_EMAIL --no-eff-email" +fi + +if [ "$TESTING" = "true" ]; then + echo "INFO: Generating staging certificate" + TEST_PARAM="--staging" +fi + +# Create certificates +certbot certonly --manual --preferred-challenges dns --manual-auth-hook \ + /scripts/auth.sh --manual-cleanup-hook /scripts/cleanup.sh \ + $EMAIL_PARAM -d "$LETSENCRYPT_DOMAIN" \ + --agree-tos --manual-public-ip-logging-ok --keep $TEST_PARAM + +chown -R $UID:$GID /etc/letsencrypt + +# Check for successful certificate generation +if [ ! -d "/etc/letsencrypt/live/${DUCKDNS_DOMAIN}" ] || \ + [ ! -f "/etc/letsencrypt/live/${DUCKDNS_DOMAIN}/fullchain.pem" ] || \ + [ ! -f "/etc/letsencrypt/live/${DUCKDNS_DOMAIN}/privkey.pem" ]; then + echo "ERROR: Failed to create SSL certificates" + exit 1 +fi + +# Check if certificates require renewal twice a day +while :; do + # Wait for a random period within the next 12 hours + LETSENCRYPT_DELAY=$(shuf -i 1-720 -n 1) + echo "Sleeping for $(($LETSENCRYPT_DELAY / 60)) hour(s) and $(($LETSENCRYPT_DELAY % 60)) minute(s)" + sleep $((${LETSENCRYPT_DELAY} * 60)) # Convert to seconds + + echo "INFO: Attempting SSL certificate renewal" + certbot --manual-public-ip-logging-ok renew + chown -R $UID:$GID /etc/letsencrypt +done