From 71454e34662912ac8c7d5e7522691a2350c13868 Mon Sep 17 00:00:00 2001 From: Chris Mazanec Date: Thu, 30 Sep 2021 12:26:31 +0200 Subject: [PATCH 1/2] added option for alternate (alias) domain, added `docker-compose.yml`, formatting, docs --- README.md | 11 ++++++++++- docker-compose.yml | 18 ++++++++++++++++++ scripts/auth.sh | 2 +- scripts/cleanup.sh | 2 +- scripts/start.sh | 40 ++++++++++++++++++++++++---------------- 5 files changed, 54 insertions(+), 19 deletions(-) create mode 100644 docker-compose.yml diff --git a/README.md b/README.md index ca1ea9d..8dfff5f 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,21 @@ Automatically generates Let's Encrypt certificates using a lightweight Docker co * `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_DOMAIN`: Domain to generate SSL cert for. By default SSL certificate is generated for `DUCKDNS_DOMAIN` (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`) (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`. +## Notes + +* The format of `DUCKDNS_DOMAIN` should be the same regardless of the value of `LETSENCRYPT_WILDCARD`. + +* In order to use `LETSENCRYPT_DOMAIN` feature, the following DNS records need to be created for ACME authentication +``` + CNAME -> + _acme-challenge.< CNAME -> _acme-challenge. +``` ## Volumes diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c8f1c28 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: '2.4' + +services: + duckdns-letsencrypt: + build: . + restart: unless-stopped + volumes: + - ./certs:/etc/letsencrypt + environment: + # mandatory + - "DUCKDNS_TOKEN=" + - "DUCKDNS_DOMAIN=" + # optional + # - "LETSENCRYPT_DOMAIN=" + # - "LETSENCRYPT_EMAIL=" + # - "LETSENCRYPT_WILDCARD=false" + # - "TESTING=false" + diff --git a/scripts/auth.sh b/scripts/auth.sh index e552aec..5ee98c9 100644 --- a/scripts/auth.sh +++ b/scripts/auth.sh @@ -1,3 +1,3 @@ #!/bin/sh -[[ "$(curl -s "https://www.duckdns.org/update?domains=${CERTBOT_DOMAIN%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}")" = "OK" ]] +[[ "$(curl -s "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}")" = "OK" ]] diff --git a/scripts/cleanup.sh b/scripts/cleanup.sh index 0bce0a1..da92885 100644 --- a/scripts/cleanup.sh +++ b/scripts/cleanup.sh @@ -1,2 +1,2 @@ #!/bin/sh -[[ "$(curl -s "https://www.duckdns.org/update?domains=${CERTBOT_DOMAIN%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}&clear=true")" = "OK" ]] +[[ "$(curl -s "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}&clear=true")" = "OK" ]] diff --git a/scripts/start.sh b/scripts/start.sh index 49900b5..e9cec3c 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -2,43 +2,49 @@ # Check variables DUCKDNS_TOKEN, DUCKDNS_DOMAIN if [ -z "$DUCKDNS_TOKEN" ]; then - echo "ERROR: Variable DUCKDNS_TOKEN is unset" - exit 1 + echo "ERROR: Variable DUCKDNS_TOKEN is unset" + exit 1 fi if [ -z "$DUCKDNS_DOMAIN" ]; then - echo "ERROR: Variable DUCKDNS_DOMAIN is unset" - exit 1 + echo "ERROR: Variable DUCKDNS_DOMAIN is unset" + exit 1 fi # Print email notice if applicable if [ -z "$LETSENCRYPT_EMAIL" ]; then - echo "INFO: You will not receive SSL certificate expiration notices" + echo "INFO: You will not receive SSL certificate expiration notices" +fi + +# Set LETSENCRYPT_DOMAIN to DUCKDNS_DOMAIN if not specified +if [ -z "$LETSENCRYPT_DOMAIN" ]; then + echo "INFO: No LETSENCRYPT_DOMAIN, using DUCKDNS_DOMAIN" + LETSENCRYPT_DOMAIN=$DUCKDNS_DOMAIN fi # Set certificate url based on LETSENCRYPT_WILDCARD value if [ "$LETSENCRYPT_WILDCARD" = "true" ]; then echo "INFO: A wildcard SSL certificate will be created" - LETSENCRYPT_DOMAIN="*.$DUCKDNS_DOMAIN" + LETSENCRYPT_DOMAIN="*.$LETSENCRYPT_DOMAIN" else - 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" + 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" + 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_DOMAIN: $LETSENCRYPT_DOMAIN" echo "LETSENCRYPT_EMAIL: $LETSENCRYPT_EMAIL" echo "LETSENCRYPT_WILDCARD: $LETSENCRYPT_WILDCARD" echo "TESTING: $TESTING" @@ -58,23 +64,25 @@ else unset TEST_PARAM fi -echo "certbot certonly --manual --preferred-challenges dns --manual-auth-hook \ - /scripts/auth.sh --manual-cleanup-hook /scripts/cleanup.sh \ +echo "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" # Create certificates -certbot certonly --manual --preferred-challenges dns --manual-auth-hook \ - /scripts/auth.sh --manual-cleanup-hook /scripts/cleanup.sh \ +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 +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 From 11b0c17767b6a3f0487ad2b27137fec08b9fb646 Mon Sep 17 00:00:00 2001 From: Maksim Stojkovic <18454392+maksimstojkovic@users.noreply.github.com> Date: Thu, 7 Oct 2021 03:51:09 +1100 Subject: [PATCH 2/2] alternative domain merge prep Added note about proxied DNS records to README.md Updated CNAME record docs Adjusted format of docker-compose.yml variables Re-ordered README.md variables to match docker-compose.yml Added DNS record conditions to README.md Added duckdns container to docker-compose.yml Added default value checks to start.sh --- README.md | 18 ++++++++++-------- docker-compose.yml | 31 ++++++++++++++++++++----------- scripts/start.sh | 10 +++++----- 3 files changed, 35 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 8dfff5f..8e5b849 100644 --- a/README.md +++ b/README.md @@ -12,22 +12,24 @@ Automatically generates Let's Encrypt certificates using a lightweight Docker co * `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_DOMAIN`: Domain to generate SSL cert for. By default the SSL certificate is generated for `DUCKDNS_DOMAIN` (optional) +* `LETSENCRYPT_WILDCARD`: `true` or `false`, indicating whether the SSL certificate should be for subdomains *only* of `LETSENCRYPT_DOMAIN` (i.e. `*.test.duckdns.org`), or for the main domain *only* (i.e. `test.duckdns.org`) (optional, default: `false`) * `LETSENCRYPT_EMAIL`: Email used for certificate renewal notifications (optional) -* `LETSENCRYPT_DOMAIN`: Domain to generate SSL cert for. By default SSL certificate is generated for `DUCKDNS_DOMAIN` (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`) (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) ## Notes -* The format of `DUCKDNS_DOMAIN` should be the same regardless of the value of `LETSENCRYPT_WILDCARD`. +* The `DUCKDNS_DOMAIN` should already be pointing to the server with a dynamic IP. The [maksimstojkovic/duckdns](https://github.com/maksimstojkovic/docker-duckdns) image can be used to automatically update the IP address. +* The format of `DUCKDNS_DOMAIN` should be `.duckdns.org`, regardless of the value of `LETSENCRYPT_WILDCARD`. +* To use `LETSENCRYPT_DOMAIN` feature, the following DNS records need to be created for ACME authentication (records should not be proxied): -* In order to use `LETSENCRYPT_DOMAIN` feature, the following DNS records need to be created for ACME authentication -``` - CNAME -> - _acme-challenge.< CNAME -> _acme-challenge. -``` +| Type | Name | Value | Condition | +|-------|----------------------------------------|------------------------------------|-----------------------------------| +| CNAME | `*.` | `` | `LETSENCRYPT_WILDCARD` == `true` | +| CNAME | `` | `` | `LETSENCRYPT_WILDCARD` == `false` | +| CNAME | `_acme-challenge.` | `_acme-challenge.` | | ## Volumes diff --git a/docker-compose.yml b/docker-compose.yml index c8f1c28..73dc015 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,18 +1,27 @@ version: '2.4' services: - duckdns-letsencrypt: - build: . + duckdns: + image: maksimstojkovic/duckdns + container_name: duckdns + environment: + - DUCKDNS_TOKEN=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + - DUCKDNS_DOMAIN=test.duckdns.org + - DUCKDNS_DELAY=5 #optional restart: unless-stopped + + letsencrypt: + image: maksimstojkovic/letsencrypt + container_name: letsencrypt volumes: - ./certs:/etc/letsencrypt environment: - # mandatory - - "DUCKDNS_TOKEN=" - - "DUCKDNS_DOMAIN=" - # optional - # - "LETSENCRYPT_DOMAIN=" - # - "LETSENCRYPT_EMAIL=" - # - "LETSENCRYPT_WILDCARD=false" - # - "TESTING=false" - + - DUCKDNS_TOKEN=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + - DUCKDNS_DOMAIN=test.duckdns.org + - LETSENCRYPT_DOMAIN= #optional + - LETSENCRYPT_WILDCARD=false #optional + - LETSENCRYPT_EMAIL= #optional + - TESTING=false #optional + - UID=0 #optional + - GID=0 #optional + restart: unless-stopped diff --git a/scripts/start.sh b/scripts/start.sh index e9cec3c..0227112 100644 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -1,24 +1,24 @@ #!/bin/sh # Check variables DUCKDNS_TOKEN, DUCKDNS_DOMAIN -if [ -z "$DUCKDNS_TOKEN" ]; then - echo "ERROR: Variable DUCKDNS_TOKEN is unset" +if [ -z "$DUCKDNS_TOKEN" ] || [ "$DUCKDNS_TOKEN" = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" ]; then + echo "ERROR: Variable DUCKDNS_TOKEN is unset or still its default value" exit 1 fi if [ -z "$DUCKDNS_DOMAIN" ]; then - echo "ERROR: Variable DUCKDNS_DOMAIN is unset" + echo "ERROR: Variable DUCKDNS_DOMAIN is unset or still its default value" exit 1 fi # Print email notice if applicable if [ -z "$LETSENCRYPT_EMAIL" ]; then - echo "INFO: You will not receive SSL certificate expiration notices" + echo "WARNING: You will not receive SSL certificate expiration notices" fi # Set LETSENCRYPT_DOMAIN to DUCKDNS_DOMAIN if not specified if [ -z "$LETSENCRYPT_DOMAIN" ]; then - echo "INFO: No LETSENCRYPT_DOMAIN, using DUCKDNS_DOMAIN" + echo "INFO: LETSENCRYPT_DOMAIN is unset, using DUCKDNS_DOMAIN" LETSENCRYPT_DOMAIN=$DUCKDNS_DOMAIN fi