1
0

Merge pull request #442 from Greek64/PR

New environmental variable LETSENCRYPT_RESTART_CONTAINER
This commit is contained in:
Nicolas Duchon 2018-12-21 22:32:53 +01:00 committed by GitHub
commit 6c73fc2675
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 99 additions and 3 deletions

1
.gitignore vendored

@ -8,3 +8,4 @@ go/
nginx.tmpl
test/local_test_env.sh
test/tests/docker_api/expected-std-out.txt
test/tests/container_restart/docker_event_out.txt

@ -175,6 +175,9 @@ If needed, you can force a running letsencrypt-nginx-proxy-companion container t
$ docker exec nginx-letsencrypt /app/force_renew
```
##### Restart container on certificate renewal
Per default letsencrypt-nginx-proxy-companion only reloads the nginx-proxy container when new certificates are issued or renewed. But it may be desirable to use the certificates inside the containers for other purposes than HTTPS (e.g. FTPS Server), and that would require to also restart the containers using the certificates, whenever these certificates are renewed. This can be achieved by defining the `LETSENCRYPT_RESTART_CONTAINER` environment variable with a value of `true` for the containers that you want to be restarted on certificate renewal (and have the `LETSENCRYPT_HOST` variable set).
##### Show certificates informations
To display informations about your existing certificates, use the following command:

@ -114,6 +114,11 @@ function docker_exec {
fi
}
function docker_restart {
local id="${1?missing id}"
docker_api "/containers/$id/restart" "POST"
}
function docker_kill {
local id="${1?missing id}"
local signal="${2?missing signal}"

@ -129,6 +129,7 @@ function update_certs {
should_reload_nginx='false'
for cid in "${LETSENCRYPT_CONTAINERS[@]}"; do
should_restart_container='false'
# Derive host and email variable names
host_varname="LETSENCRYPT_${cid}_HOST"
# Array variable indirection hack: http://stackoverflow.com/a/25880676/350221
@ -231,9 +232,9 @@ function update_certs {
if [[ $simp_le_return -ne 2 ]]; then
for domain in "${!hosts_array}"; do
if [[ "$acme_ca_uri" == "$le_staging_uri" ]]; then
create_links "_test_$base_domain" "$domain" && should_reload_nginx='true'
create_links "_test_$base_domain" "$domain" && should_reload_nginx='true' && should_restart_container='true'
else
create_links "$base_domain" "$domain" && should_reload_nginx='true'
create_links "$base_domain" "$domain" && should_reload_nginx='true' && should_restart_container='true'
fi
touch "${certificate_dir}/.companion"
set_ownership_and_permissions "${certificate_dir}/.companion"
@ -250,7 +251,14 @@ function update_certs {
account_key_perm_path="$(dirname "$account_key_perm_path")"
done
# Queue nginx reload if a certificate was issued or renewed
[[ $simp_le_return -eq 0 ]] && should_reload_nginx='true'
[[ $simp_le_return -eq 0 ]] && should_reload_nginx='true' && should_restart_container='true'
fi
# Restart container if certs are updated and the respective environmental variable is set
restart_container_var="LETSENCRYPT_${cid}_RESTART_CONTAINER"
if [[ $(lc "${!restart_container_var:-}") == true ]] && [[ "$should_restart_container" == 'true' ]]; then
echo "Restarting container (${cid})..."
docker_restart "${cid}"
fi
done

@ -10,6 +10,7 @@ LETSENCRYPT_{{ $cid }}_EMAIL="{{ $container.Env.LETSENCRYPT_EMAIL }}"
LETSENCRYPT_{{ $cid }}_KEYSIZE="{{ $container.Env.LETSENCRYPT_KEYSIZE }}"
LETSENCRYPT_{{ $cid }}_TEST="{{ $container.Env.LETSENCRYPT_TEST }}"
LETSENCRYPT_{{ $cid }}_ACCOUNT_ALIAS="{{ $container.Env.LETSENCRYPT_ACCOUNT_ALIAS }}"
LETSENCRYPT_{{ $cid }}_RESTART_CONTAINER="{{ $container.Env.LETSENCRYPT_RESTART_CONTAINER }}"
{{ end }}
{{ end }}

@ -12,6 +12,7 @@ imageTests+=(
certs_single
certs_san
force_renew
container_restart
permissions_default
permissions_custom
symlinks

@ -0,0 +1,7 @@
Started letsencrypt container for test container_restart
Started test web server for le1.wtf
Started test web server for le2.wtf
Started test web server for le3.wtf
Container le1.wtf restarted
Container le2.wtf restarted
Container le3.wtf restarted

@ -0,0 +1,70 @@
#!/bin/bash
## Test for LETSENCRYPT_RESTART_CONTAINER variable.
if [[ -z $TRAVIS_CI ]]; then
le_container_name="$(basename ${0%/*})_$(date "+%Y-%m-%d_%H.%M.%S")"
else
le_container_name="$(basename ${0%/*})"
fi
run_le_container ${1:?} "$le_container_name"
# Create the $domains array from comma separated domains in TEST_DOMAINS.
IFS=',' read -r -a domains <<< "$TEST_DOMAINS"
# Listen for Docker restart events
docker events \
--filter event=restart \
--format 'Container {{.Actor.Attributes.name}} restarted' > ${TRAVIS_BUILD_DIR}/test/tests/container_restart/docker_event_out.txt &
docker_events_pid=$!
# Cleanup function with EXIT trap
function cleanup {
# Kill the Docker events listener
kill $docker_events_pid && wait $docker_events_pid 2>/dev/null
# Remove temporary files
rm -f ${TRAVIS_BUILD_DIR}/test/tests/container_restart/docker_event_out.txt
# Remove any remaining Nginx container(s) silently.
for domain in "${domains[@]}"; do
docker rm --force "$domain" > /dev/null 2>&1
done
# Cleanup the files created by this run of the test to avoid foiling following test(s).
docker exec "$le_container_name" bash -c 'rm -rf /etc/nginx/certs/le?.wtf*'
# Stop the LE container
docker stop "$le_container_name" > /dev/null
}
trap cleanup EXIT
# Run a separate nginx container for each domain in the $domains array.
# Start all the containers in a row so that docker-gen debounce timers fire only once.
for domain in "${domains[@]}"; do
docker run --rm -d \
--name "$domain" \
-e "VIRTUAL_HOST=${domain}" \
-e "LETSENCRYPT_HOST=${domain}" \
-e "LETSENCRYPT_RESTART_CONTAINER=true" \
--network boulder_bluenet \
nginx:alpine > /dev/null && echo "Started test web server for $domain"
done
for domain in "${domains[@]}"; do
# Check if container restarted
i=0
until grep "$domain" ${TRAVIS_BUILD_DIR}/test/tests/container_restart/docker_event_out.txt; do
if [ "$waited_once" = true ]; then
echo "Container $domain didn't restart in under one minute."
break
elif [ $i -gt 60 ]; then
echo "Container $domain didn't restart in under one minute."
# Wait only once for all containers (since all containers are started together)
waited_once=true
break
fi
i=$((i + 2))
sleep 2
done
# Stop the Nginx container silently.
docker stop "$domain" > /dev/null
done