mirror of
https://github.com/nginx-proxy/docker-letsencrypt-nginx-proxy-companion
synced 2024-12-04 18:48:20 +01:00
203 lines
7.4 KiB
Bash
Executable File
203 lines
7.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# shellcheck disable=SC2120
|
|
|
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
|
|
source /app/functions.sh
|
|
|
|
seconds_to_wait=3600
|
|
ACME_CA_URI="${ACME_CA_URI:-https://acme-v01.api.letsencrypt.org/directory}"
|
|
DEFAULT_KEY_SIZE=4096
|
|
REUSE_ACCOUNT_KEYS="$(lc ${REUSE_ACCOUNT_KEYS:-true})"
|
|
REUSE_PRIVATE_KEYS="$(lc ${REUSE_PRIVATE_KEYS:-false})"
|
|
|
|
create_link() {
|
|
local -r target=${1?missing target argument}
|
|
local -r source=${2?missing source argument}
|
|
[[ -f "$target" ]] && return 1
|
|
ln -sf "$source" "$target"
|
|
}
|
|
|
|
create_links() {
|
|
local -r base_domain=${1?missing base_domain argument}
|
|
local -r domain=${2?missing base_domain argument}
|
|
|
|
if [[ ! -f "/etc/nginx/certs/$base_domain"/fullchain.pem || \
|
|
! -f "/etc/nginx/certs/$base_domain"/key.pem ]]; then
|
|
return 1
|
|
fi
|
|
local return_code=1
|
|
create_link "/etc/nginx/certs/$domain".crt "./$base_domain"/fullchain.pem
|
|
return_code=$(( $return_code & $? ))
|
|
create_link "/etc/nginx/certs/$domain".key "./$base_domain"/key.pem
|
|
return_code=$(( $return_code & $? ))
|
|
if [[ -f "/etc/nginx/certs/dhparam.pem" ]]; then
|
|
create_link "/etc/nginx/certs/$domain".dhparam.pem ./dhparam.pem
|
|
return_code=$(( $return_code & $? ))
|
|
fi
|
|
if [[ -f "/etc/nginx/certs/$base_domain"/chain.pem ]]; then
|
|
create_link "/etc/nginx/certs/$domain".chain.pem "./$base_domain"/chain.pem
|
|
return_code=$(( $return_code & $? ))
|
|
fi
|
|
return $return_code
|
|
}
|
|
|
|
update_certs() {
|
|
|
|
check_two_containers_case && (check_nginx_proxy_container_run || return)
|
|
|
|
[[ ! -f "$DIR"/letsencrypt_service_data ]] && return
|
|
|
|
# Load relevant container settings
|
|
unset LETSENCRYPT_CONTAINERS
|
|
# shellcheck source=/dev/null
|
|
source "$DIR"/letsencrypt_service_data
|
|
|
|
reload_nginx='false'
|
|
for cid in "${LETSENCRYPT_CONTAINERS[@]}"; do
|
|
# Derive host and email variable names
|
|
host_varname="LETSENCRYPT_${cid}_HOST"
|
|
# Array variable indirection hack: http://stackoverflow.com/a/25880676/350221
|
|
hosts_array="${host_varname}[@]"
|
|
|
|
params_d_str=""
|
|
|
|
email_varname="LETSENCRYPT_${cid}_EMAIL"
|
|
email_address="${!email_varname}"
|
|
if [[ "$email_address" != "<no value>" ]]; then
|
|
params_d_str+=" --email $email_address"
|
|
fi
|
|
|
|
keysize_varname="LETSENCRYPT_${cid}_KEYSIZE"
|
|
cert_keysize="${!keysize_varname}"
|
|
if [[ "$cert_keysize" == "<no value>" ]]; then
|
|
cert_keysize=$DEFAULT_KEY_SIZE
|
|
fi
|
|
|
|
test_certificate_varname="LETSENCRYPT_${cid}_TEST"
|
|
create_test_certificate=false
|
|
if [[ $(lc "${!test_certificate_varname:-}") == true ]]; then
|
|
create_test_certificate=true
|
|
elif [[ $ACME_CA_URI == "https://acme-staging.api.letsencrypt.org/directory" ]]; then
|
|
create_test_certificate=true
|
|
fi
|
|
|
|
account_varname="LETSENCRYPT_${cid}_ACCOUNT_ALIAS"
|
|
account_alias="${!account_varname}"
|
|
if [[ "$account_alias" == "<no value>" ]]; then
|
|
account_alias=default
|
|
fi
|
|
|
|
[[ $DEBUG == true ]] && params_d_str+=" -v"
|
|
[[ -n $ACME_TOS_HASH ]] && params_d_str+=" --tos_sha256 $ACME_TOS_HASH"
|
|
[[ $REUSE_PRIVATE_KEYS == true ]] && params_d_str+=" --reuse_key"
|
|
[[ "${1}" == "--force-renew" ]] && params_d_str+=" --valid_min 7776000"
|
|
|
|
hosts_array_expanded=("${!hosts_array}")
|
|
# First domain will be our base domain
|
|
base_domain="${hosts_array_expanded[0]}"
|
|
|
|
if [[ "$create_test_certificate" == true ]]; then
|
|
# Use staging acme end point
|
|
acme_ca_uri="https://acme-staging.api.letsencrypt.org/directory"
|
|
if [[ ! -f /etc/nginx/certs/.${base_domain}.test ]]; then
|
|
# Remove old certificates
|
|
[[ -n "${base_domain// }" ]] && rm -rf /etc/nginx/certs/${base_domain}
|
|
for domain in "${!hosts_array}"; do
|
|
rm -f /etc/nginx/certs/$domain.{crt,key,dhparam.pem}
|
|
done
|
|
touch /etc/nginx/certs/.${base_domain}.test
|
|
fi
|
|
else
|
|
acme_ca_uri="$ACME_CA_URI"
|
|
if [[ -f /etc/nginx/certs/.${base_domain}.test ]]; then
|
|
# Remove old test certificates
|
|
[[ -n "${base_domain// }" ]] && rm -rf /etc/nginx/certs/${base_domain}
|
|
for domain in "${!hosts_array}"; do
|
|
rm -f /etc/nginx/certs/$domain.{crt,key,dhparam.pem}
|
|
done
|
|
rm -f /etc/nginx/certs/.${base_domain}.test
|
|
fi
|
|
fi
|
|
|
|
# Create directory for the first domain
|
|
mkdir -p /etc/nginx/certs/$base_domain
|
|
pushd /etc/nginx/certs/$base_domain
|
|
|
|
for domain in "${!hosts_array}"; do
|
|
# Add all the domains to certificate
|
|
params_d_str+=" -d $domain"
|
|
# Add location configuration for the domain
|
|
add_location_configuration "$domain" || reload_nginx
|
|
done
|
|
|
|
# The ACME account key full path is derived from the endpoint URI
|
|
# + the account alias (set to 'default' if no alias is provided)
|
|
account_key_dir="../accounts/${acme_ca_uri#*://}"
|
|
account_key_full_path="${account_key_dir}/${account_alias}.json"
|
|
if [[ $REUSE_ACCOUNT_KEYS == true ]]; then
|
|
if [[ -f "$account_key_full_path" ]]; then
|
|
# If there is no symlink to the account key, create it
|
|
if [[ ! -L ./account_key.json ]]; then
|
|
ln -sf "$account_key_full_path" ./account_key.json
|
|
# If the symlink target the wrong account key, replace it
|
|
elif [[ "$(readlink -f ./account_key.json)" != "$account_key_full_path" ]]; then
|
|
ln -sf "$account_key_full_path" ./account_key.json
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
echo "Creating/renewal $base_domain certificates... (${hosts_array_expanded[*]})"
|
|
/usr/bin/simp_le \
|
|
-f account_key.json -f key.pem -f chain.pem -f fullchain.pem -f cert.pem \
|
|
$params_d_str \
|
|
--cert_key_size=$cert_keysize \
|
|
--server=$acme_ca_uri \
|
|
--default_root /usr/share/nginx/html/
|
|
|
|
simp_le_return=$?
|
|
|
|
if [[ $REUSE_ACCOUNT_KEYS == true ]]; then
|
|
# If the account key to be reused does not exist yet, copy it
|
|
# from the CWD and replace the file in CWD with a symlink
|
|
if [[ ! -f "$account_key_full_path" && -f ./account_key.json ]]; then
|
|
mkdir -p "$account_key_dir"
|
|
cp ./account_key.json "$account_key_full_path"
|
|
ln -sf "$account_key_full_path" ./account_key.json
|
|
fi
|
|
fi
|
|
|
|
popd
|
|
|
|
for altnames in "${hosts_array_expanded[@]:1}"; do
|
|
# Remove old CN domain that now are altnames
|
|
[[ -n "${altnames// }" ]] && rm -rf /etc/nginx/certs/${altnames}
|
|
done
|
|
|
|
for domain in "${!hosts_array}"; do
|
|
create_links $base_domain $domain && reload_nginx='true'
|
|
[[ $simp_le_return -eq 0 ]] && reload_nginx='true'
|
|
done
|
|
done
|
|
|
|
[[ "$reload_nginx" == 'true' ]] && reload_nginx
|
|
}
|
|
|
|
# Allow the script functions to be sourced without starting the Service Loop.
|
|
if [ "${1}" == "--source-only" ]; then
|
|
return 0
|
|
fi
|
|
|
|
pid=
|
|
# Service Loop: When this script exits, start it again.
|
|
trap '[[ $pid ]] && kill $pid; exec $0' EXIT
|
|
trap 'trap - EXIT' INT TERM
|
|
|
|
update_certs
|
|
|
|
# Wait some amount of time
|
|
echo "Sleep for ${seconds_to_wait}s"
|
|
sleep $seconds_to_wait & pid=$!
|
|
wait
|
|
pid=
|