Skip to content

Commit

Permalink
Merge pull request #442 from Greek64/PR
Browse files Browse the repository at this point in the history
New environmental variable LETSENCRYPT_RESTART_CONTAINER
  • Loading branch information
buchdag committed Dec 21, 2018
2 parents e933996 + f79496a commit 6c73fc2
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
5 changes: 5 additions & 0 deletions app/functions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
Expand Down
14 changes: 11 additions & 3 deletions app/letsencrypt_service
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions app/letsencrypt_service_data.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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 }}
1 change: 1 addition & 0 deletions test/config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ imageTests+=(
certs_single
certs_san
force_renew
container_restart
permissions_default
permissions_custom
symlinks
Expand Down
7 changes: 7 additions & 0 deletions test/tests/container_restart/expected-std-out.txt
Original file line number Diff line number Diff line change
@@ -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
70 changes: 70 additions & 0 deletions test/tests/container_restart/run.sh
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 6c73fc2

Please sign in to comment.