first commit

This commit is contained in:
Fabio 2025-02-19 21:19:29 +08:00
commit 270ae0245f
14 changed files with 491 additions and 0 deletions

2
.dockerignore Normal file
View file

@ -0,0 +1,2 @@
*
!scripts/

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
dev/

19
Dockerfile Normal file
View file

@ -0,0 +1,19 @@
# Base image
FROM ubuntu:latest
# Maintainer information
LABEL maintainer="Maksim Stojkovic <https://github.com/maksimstojkovic>" \
org.label-schema.vcs-url="https://github.com/maksimstojkovic/docker-letsencrypt"
# Install tools required
RUN apt update
RUN apt upgrade -y
RUN apt install bash certbot curl python3-certbot-nginx -y jq
# Copy scripts
WORKDIR /scripts
COPY ./scripts /scripts
RUN chmod -R +x /scripts
# Image starting command
CMD ["/bin/bash", "/scripts/start.sh"]

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Maksim Stojkovic
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

39
README.md Normal file
View file

@ -0,0 +1,39 @@
# Let's Encrypt for Duck DNS
[![Build Status](https://github.com/maksimstojkovic/docker-letsencrypt/actions/workflows/docker-build.yml/badge.svg)](https://github.com/maksimstojkovic/docker-letsencrypt)
[![Docker Pulls](https://img.shields.io/docker/pulls/maksimstojkovic/letsencrypt)](https://hub.docker.com/r/maksimstojkovic/letsencrypt)
[![Docker Stars](https://img.shields.io/docker/stars/maksimstojkovic/letsencrypt)](https://hub.docker.com/r/maksimstojkovic/letsencrypt)
[![Docker Image Size (latest by date)](https://img.shields.io/docker/image-size/maksimstojkovic/letsencrypt)](https://hub.docker.com/r/maksimstojkovic/letsencrypt)
[![Docker Image Version (latest by date)](https://img.shields.io/docker/v/maksimstojkovic/letsencrypt)](https://hub.docker.com/r/maksimstojkovic/letsencrypt)
Automatically generates Let's Encrypt certificates using a lightweight Docker container without requiring any ports to be exposed for DNS challenges.
## Environment Variables
* `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_CHAIN`: Preferred certificate chain (e.g. `ISRG Root X1`, see [https://letsencrypt.org/certificates](https://letsencrypt.org/certificates/) for more details) (optional)
* `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 `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 `<subdomain>.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):
| Type | Name | Value | Condition |
|-------|----------------------------------------|------------------------------------|-----------------------------------|
| CNAME | `*.<LETSENCRYPT_DOMAIN>` | `<DUCKDNS_DOMAIN>` | `LETSENCRYPT_WILDCARD` == `true` |
| CNAME | `<LETSENCRYPT_DOMAIN>` | `<DUCKDNS_DOMAIN>` | `LETSENCRYPT_WILDCARD` == `false` |
| CNAME | `_acme-challenge.<LETSENCRYPT_DOMAIN>` | `_acme-challenge.<DUCKDNS_DOMAIN>` | |
## Volumes
* `<certs>:/etc/letsencrypt`: A named or host volume which allows SSL certificates to persist and be accessed by other containers
**Note:** To use the `<certs>` host volume in another container, mount it as read-only for those containers. The `<certs>` host volume should be read-write enabled for the Letsencrypt container.

27
docker-compose.yml Normal file
View file

@ -0,0 +1,27 @@
version: '2.4'
services:
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:
- 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

3
scripts/auth.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
[[ "$(curl -s "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}")" = "OK" ]]

3
scripts/auth2.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
[[ "$(curl -s "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN2%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}")" = "OK" ]]

2
scripts/cleanup.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/sh
[[ "$(curl -s "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}&clear=true")" = "OK" ]]

2
scripts/cleanup2.sh Executable file
View file

@ -0,0 +1,2 @@
#!/bin/sh
[[ "$(curl -s "https://www.duckdns.org/update?domains=${DUCKDNS_DOMAIN2%.duckdns.org}&token=${DUCKDNS_TOKEN}&txt=${CERTBOT_VALIDATION}&clear=true")" = "OK" ]]

17
scripts/script-post.sh Executable file
View file

@ -0,0 +1,17 @@
#!/bin/bash
#Get domainID:
dns=$(curl -X GET https://api.dynu.com/v2/dns -H "accept: application/json" -H "API-Key: $DYNU_API_KEY")
domainID=$(echo $dns | jq ".domains[] | select(.name==\"$CERTBOT_DOMAIN\")" | jq '.id')
while
records=$(curl -s -X GET "https://api.dynu.com/v2/dns/$domainID/record" -H "accept: application/json" -H "API-Key: $DYNU_API_KEY")
identifier=$(echo $records | jq '.dnsRecords[] | select(.nodeName=="_acme-challenge")' | jq '.id' | head -n 1)
if [ ! -z "$identifier" ]
then
echo "Delete: $identifier"
curl -s -X DELETE "https://api.dynu.com/v2/dns/$domainID/record/$identifier" -H "accept: application/json" -H "API-Key: $DYNU_API_KEY"
fi
[[ ! -z "$identifier" ]]
do
continue
done

10
scripts/script-pre.sh Executable file
View file

@ -0,0 +1,10 @@
#!/bin/bash
#Get domainID:
dns=$(curl -X GET https://api.dynu.com/v2/dns -H "accept: application/json" -H "API-Key: $DYNU_API_KEY")
domainID=$(echo $dns | jq ".domains[] | select(.name==\"$CERTBOT_DOMAIN\")" | jq '.id')
#Create record
resultCreate=$(curl -s -X POST "https://api.dynu.com/v2/dns/$domainID/record" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"nodeName\":\"_acme-challenge\",\"recordType\":\"TXT\",\"ttl\":60,\"state\":true,\"group\":\"\",\"textData\":\"$CERTBOT_VALIDATION\"}" -H "API-Key: $DYNU_API_KEY")
echo $resultCreate
sleep 30

190
scripts/start.sh Executable file
View file

@ -0,0 +1,190 @@
#!/bin/sh
# Check variables DUCKDNS_TOKEN, DUCKDNS_DOMAIN
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 or still its default value"
exit 1
fi
# Print email notice if applicable
if [ -z "$LETSENCRYPT_EMAIL" ]; then
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: LETSENCRYPT_DOMAIN is unset, 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="*.$LETSENCRYPT_DOMAIN"
fi
# Set LETSENCRYPT_DOMAIN to DUCKDNS_DOMAIN if not specified
if [ -z "$LETSENCRYPT_DOMAIN2" ]; then
echo "INFO: LETSENCRYPT_DOMAIN2 is unset, using DUCKDNS_DOMAIN"
LETSENCRYPT_DOMAIN2=$DUCKDNS_DOMAIN2
fi
# Set certificate url based on LETSENCRYPT_WILDCARD value
if [ "$LETSENCRYPT_WILDCARD" = "true" ]; then
echo "INFO: A wildcard SSL certificate will be created"
LETSENCRYPT_DOMAIN2="*.$LETSENCRYPT_DOMAIN2"
else
LETSENCRYPT_WILDCARD="false"
fi
# Set default preferred chain if no value specified
if [ -z "$LETSENCRYPT_CHAIN" ]; then
echo "INFO: LETSENCRYPT_CHAIN is unset, using default chain"
LETSENCRYPT_CHAIN="default"
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_DOMAIN: $LETSENCRYPT_DOMAIN"
echo "LETSENCRYPT_EMAIL: $LETSENCRYPT_EMAIL"
echo "LETSENCRYPT_WILDCARD: $LETSENCRYPT_WILDCARD"
echo "LETSENCRYPT_CHAIN: $LETSENCRYPT_CHAIN"
echo "TESTING: $TESTING"
echo "UID: $UID"
echo "GID: $GID"
if [ -z "$LETSENCRYPT_EMAIL" ]; then
EMAIL_PARAM="--register-unsafely-without-email"
else
EMAIL_PARAM="-m $LETSENCRYPT_EMAIL --no-eff-email"
fi
if [ "$LETSENCRYPT_CHAIN" = "default" ]; then
unset CHAIN_PARAM
else
CHAIN_PARAM=( --preferred-chain "$LETSENCRYPT_CHAIN" )
fi
if [ "$TESTING" = "true" ]; then
echo "INFO: Generating staging certificate"
TEST_PARAM="--test-cert"
else
unset TEST_PARAM
fi
echo "certbot certonly --manual --preferred-challenges dns \
--manual-auth-hook /scripts/auth.sh \
--manual-cleanup-hook /scripts/cleanup.sh \
${CHAIN_PARAM[@]} $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 \
"${CHAIN_PARAM[@]}" $EMAIL_PARAM -d $LETSENCRYPT_DOMAIN \
--agree-tos --manual-public-ip-logging-ok --keep $TEST_PARAM
echo "certbot certonly --manual --preferred-challenges dns \
--manual-auth-hook /scripts/auth2.sh \
--manual-cleanup-hook /scripts/cleanup2.sh \
${CHAIN_PARAM[@]} $EMAIL_PARAM -d $LETSENCRYPT_DOMAIN2 \
--agree-tos --manual-public-ip-logging-ok --keep $TEST_PARAM"
# Create certificates
certbot certonly --manual --preferred-challenges dns \
--manual-auth-hook /scripts/auth2.sh \
--manual-cleanup-hook /scripts/cleanup2.sh \
"${CHAIN_PARAM[@]}" $EMAIL_PARAM -d $LETSENCRYPT_DOMAIN2 \
--agree-tos --manual-public-ip-logging-ok --keep $TEST_PARAM
chown -R $UID:$GID /etc/letsencrypt
echo "certbot certonly --manual-public-ip-logging-ok --non-interactive --agree-tos \
--email $EMAIL --manual --preferred-challenges=dns \
--manual-auth-hook /scripts/script-pre.sh --manual-cleanup-hook /scripts/script-post.sh \
-d $DYNU_DOMAIN -d *.$DYNU_DOMAIN"
certbot certonly --manual-public-ip-logging-ok --non-interactive --agree-tos \
--email $EMAIL --manual --preferred-challenges=dns \
--manual-auth-hook /scripts/script-pre.sh --manual-cleanup-hook /scripts/script-post.sh \
-d $DYNU_DOMAIN -d *.$DYNU_DOMAIN
echo "certbot certonly --manual-public-ip-logging-ok --non-interactive --agree-tos \
--email $EMAIL --manual --preferred-challenges=dns \
--manual-auth-hook /scripts/script-pre.sh --manual-cleanup-hook /scripts/script-post.sh \
-d $DYNU_DOMAIN2 -d *.$DYNU_DOMAIN2"
certbot certonly --manual-public-ip-logging-ok --non-interactive --agree-tos \
--email $EMAIL --manual --preferred-challenges=dns \
--manual-auth-hook /scripts/script-pre.sh --manual-cleanup-hook /scripts/script-post.sh \
-d $DYNU_DOMAIN2 -d *.$DYNU_DOMAIN2
echo "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN#\*\.}"
echo "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN#\*\.}/fullchain.pem"
echo "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN#\*\.}/privkey.pem"
# 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 for ${LETSENCRYPT_DOMAIN#\*\.}"
else
echo "SUCCESS: Create SSL certificates for ${LETSENCRYPT_DOMAIN#\*\.}"
fi
# Check for successful certificate generation
if [ ! -d "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN2#\*\.}" ] || \
[ ! -f "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN2#\*\.}/fullchain.pem" ] || \
[ ! -f "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN2#\*\.}/privkey.pem" ]; then
echo "ERROR: Failed to create SSL certificates for ${LETSENCRYPT_DOMAIN2#\*\.}"
else
echo "SUCCESS: Create SSL certificates for ${LETSENCRYPT_DOMAIN2#\*\.}"
fi
# Check for successful certificate generation
if [ ! -d "/etc/letsencrypt/live/${DYNU_DOMAIN#\*\.}" ] || \
[ ! -f "/etc/letsencrypt/live/${DYNU_DOMAIN#\*\.}/fullchain.pem" ] || \
[ ! -f "/etc/letsencrypt/live/${DYNU_DOMAIN#\*\.}/privkey.pem" ]; then
echo "ERROR: Failed to create SSL certificates for ${DYNU_DOMAIN}"
else
echo "SUCCESS: Create SSL certificates for ${DYNU_DOMAIN}"
fi
# Check for successful certificate generation
if [ ! -d "/etc/letsencrypt/live/${DYNU_DOMAIN2#\*\.}" ] || \
[ ! -f "/etc/letsencrypt/live/${DYNU_DOMAIN2#\*\.}/fullchain.pem" ] || \
[ ! -f "/etc/letsencrypt/live/${DYNU_DOMAIN2#\*\.}/privkey.pem" ]; then
echo "ERROR: Failed to create SSL certificates for ${DYNU_DOMAIN2}"
else
echo "SUCCESS: Create SSL certificates for ${DYNU_DOMAIN2}"
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

155
scripts/start_orig.sh Executable file
View file

@ -0,0 +1,155 @@
#!/bin/sh
# Check variables DUCKDNS_TOKEN, DUCKDNS_DOMAIN
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 or still its default value"
exit 1
fi
# Print email notice if applicable
if [ -z "$LETSENCRYPT_EMAIL" ]; then
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: LETSENCRYPT_DOMAIN is unset, 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="*.$LETSENCRYPT_DOMAIN"
else
LETSENCRYPT_WILDCARD="false"
fi
# Set default preferred chain if no value specified
if [ -z "$LETSENCRYPT_CHAIN" ]; then
echo "INFO: LETSENCRYPT_CHAIN is unset, using default chain"
LETSENCRYPT_CHAIN="default"
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_DOMAIN: $LETSENCRYPT_DOMAIN"
echo "LETSENCRYPT_EMAIL: $LETSENCRYPT_EMAIL"
echo "LETSENCRYPT_WILDCARD: $LETSENCRYPT_WILDCARD"
echo "LETSENCRYPT_CHAIN: $LETSENCRYPT_CHAIN"
echo "TESTING: $TESTING"
echo "UID: $UID"
echo "GID: $GID"
if [ -z "$LETSENCRYPT_EMAIL" ]; then
EMAIL_PARAM="--register-unsafely-without-email"
else
EMAIL_PARAM="-m $LETSENCRYPT_EMAIL --no-eff-email"
fi
if [ "$LETSENCRYPT_CHAIN" = "default" ]; then
unset CHAIN_PARAM
else
CHAIN_PARAM=( --preferred-chain "$LETSENCRYPT_CHAIN" )
fi
if [ "$TESTING" = "true" ]; then
echo "INFO: Generating staging certificate"
TEST_PARAM="--test-cert"
else
unset TEST_PARAM
fi
echo "certbot certonly --manual --preferred-challenges dns \
--manual-auth-hook /scripts/auth.sh \
--manual-cleanup-hook /scripts/cleanup.sh \
${CHAIN_PARAM[@]} $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 \
"${CHAIN_PARAM[@]}" $EMAIL_PARAM -d $LETSENCRYPT_DOMAIN \
--agree-tos --manual-public-ip-logging-ok --keep $TEST_PARAM
chown -R $UID:$GID /etc/letsencrypt
echo "certbot certonly --manual-public-ip-logging-ok --non-interactive --agree-tos \
--email $EMAIL --manual --preferred-challenges=dns \
--manual-auth-hook /scripts/script-pre.sh --manual-cleanup-hook /scripts/script-post.sh \
-d $DYNU_DOMAIN -d *.$DYNU_DOMAIN"
certbot certonly --manual-public-ip-logging-ok --non-interactive --agree-tos \
--email $EMAIL --manual --preferred-challenges=dns \
--manual-auth-hook /scripts/script-pre.sh --manual-cleanup-hook /scripts/script-post.sh \
-d $DYNU_DOMAIN -d *.$DYNU_DOMAIN
echo "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN#\*\.}"
echo "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN#\*\.}/fullchain.pem"
echo "/etc/letsencrypt/live/${LETSENCRYPT_DOMAIN#\*\.}/privkey.pem"
# 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 for ${LETSENCRYPT_DOMAIN}"
else
echo "SUCCESS: Create SSL certificates for ${LETSENCRYPT_DOMAIN}"
fi
# 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 for ${LETSENCRYPT_DOMAIN}"
else
echo "SUCCESS: Create SSL certificates for ${LETSENCRYPT_DOMAIN}"
fi
# 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 for ${DUCKDNS_DOMAIN}"
else
echo "SUCCESS: Create SSL certificates for ${DUCKDNS_DOMAIN}"
fi
# Check for successful certificate generation
if [ ! -d "/etc/letsencrypt/live/${DUCKDNS_DOMAIN2#\*\.}" ] || \
[ ! -f "/etc/letsencrypt/live/${DUCKDNS_DOMAIN2#\*\.}/fullchain.pem" ] || \
[ ! -f "/etc/letsencrypt/live/${DUCKDNS_DOMAIN2#\*\.}/privkey.pem" ]; then
echo "ERROR: Failed to create SSL certificates for ${DUCKDNS2_DOMAIN}"
else
echo "SUCCESS: Create SSL certificates for ${DUCKDNS2_DOMAIN}"
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