From d4d2974c21dee727479476aa1019173e2fced3e2 Mon Sep 17 00:00:00 2001 From: Jacob Tirey Date: Sat, 1 Aug 2026 15:26:26 -0400 Subject: [PATCH] fix: derive RPC probe and shutdown host from rpc-bind-address The readiness probe in svc-transmission/run and the graceful shutdown in svc-transmission/finish both hardcoded localhost. When rpc-bind-address is a specific non-loopback address, `nc -z localhost` can never succeed, so s6-notifyoncheck never signals readiness, container init never completes, and s6 therefore never delivers SIGTERM to transmission-daemon -- every docker stop ends in SIGKILL with no resume data flushed and no "stopped" tracker announce. Derive the host from rpc-bind-address in both scripts, keeping wildcard binds (0.0.0.0, ::, [::]) on loopback as before. finish now builds a full RPC URL, since transmission-remote's host:port shorthand cannot express an IPv6 literal; the path comes from rpc-url rather than being hardcoded. Also add a timeout-finish, as s6 otherwise SIGKILLs the finish script at its 5000ms default while a large library legitimately needs longer to shut down. closes #326 Co-Authored-By: Claude Opus 5 --- README.md | 1 + readme-vars.yml | 1 + root/etc/s6-overlay/s6-rc.d/svc-transmission/finish | 11 +++++++++-- root/etc/s6-overlay/s6-rc.d/svc-transmission/run | 9 +++++++-- .../s6-rc.d/svc-transmission/timeout-finish | 1 + 5 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 root/etc/s6-overlay/s6-rc.d/svc-transmission/timeout-finish diff --git a/README.md b/README.md index cbdc7493..aee64fe4 100644 --- a/README.md +++ b/README.md @@ -334,6 +334,7 @@ Once registered you can define the dockerfile to use with `-f Dockerfile.aarch64 ## Versions +* **01.08.26:** - Derive the RPC readiness check and shutdown request from `rpc-bind-address`/`rpc-url` instead of hardcoding localhost, and raise the service finish timeout. * **31.05.26:** - Bind RPC to IPv6 interface by default, fall back to IPv4 if unavailable. * **29.11.24:** - Fix PEERPORT setting. * **07.10.23:** - Install unrar from [linuxserver repo](https://github.com/linuxserver/docker-unrar). diff --git a/readme-vars.yml b/readme-vars.yml index 7c847091..c3a10fd3 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -106,6 +106,7 @@ init_diagram: | "transmission:latest" <- Base Images # changelog changelogs: + - {date: "01.08.26:", desc: "Derive the RPC readiness check and shutdown request from `rpc-bind-address`/`rpc-url` instead of hardcoding localhost, and raise the service finish timeout."} - {date: "31.05.26:", desc: "Bind RPC to IPv6 interface by default, fall back to IPv4 if unavailable."} - {date: "29.11.24:", desc: "Fix PEERPORT setting."} - {date: "07.10.23:", desc: "Install unrar from [linuxserver repo](https://github.com/linuxserver/docker-unrar)."} diff --git a/root/etc/s6-overlay/s6-rc.d/svc-transmission/finish b/root/etc/s6-overlay/s6-rc.d/svc-transmission/finish index 3e42d8a0..6de3a14a 100755 --- a/root/etc/s6-overlay/s6-rc.d/svc-transmission/finish +++ b/root/etc/s6-overlay/s6-rc.d/svc-transmission/finish @@ -3,11 +3,18 @@ pid=$(pidof transmission-daemon) PORT=$(jq '.["rpc-port"]' /config/settings.json) +HOST=$(jq -r '.["rpc-bind-address"] // empty' /config/settings.json | tr -d '[]') +URL=$(jq -r '.["rpc-url"] // "/transmission/"' /config/settings.json) + +case "${HOST}" in + "" | 0.0.0.0 | ::) HOST="127.0.0.1" ;; + *:*) HOST="[${HOST}]" ;; +esac if [[ -n "$USER" ]] && [[ -n "$PASS" ]]; then - /usr/bin/transmission-remote 127.0.0.1:${PORT:-9091} -n "$USER":"$PASS" --exit + /usr/bin/transmission-remote "http://${HOST}:${PORT:-9091}${URL%/}" -n "$USER":"$PASS" --exit else - /usr/bin/transmission-remote 127.0.0.1:${PORT:-9091} --exit + /usr/bin/transmission-remote "http://${HOST}:${PORT:-9091}${URL%/}" --exit fi tail --pid=${pid} -f /dev/null diff --git a/root/etc/s6-overlay/s6-rc.d/svc-transmission/run b/root/etc/s6-overlay/s6-rc.d/svc-transmission/run index e50c78f6..dc4e0bca 100755 --- a/root/etc/s6-overlay/s6-rc.d/svc-transmission/run +++ b/root/etc/s6-overlay/s6-rc.d/svc-transmission/run @@ -2,13 +2,18 @@ # shellcheck shell=bash PORT=$(jq '.["rpc-port"]' /config/settings.json) +HOST=$(jq -r '.["rpc-bind-address"] // empty' /config/settings.json | tr -d '[]') + +case "${HOST}" in + "" | 0.0.0.0 | ::) HOST="localhost" ;; +esac if [[ -z ${LSIO_NON_ROOT_USER} ]]; then - s6-notifyoncheck -d -n 300 -w 1000 -c "nc -z localhost ${PORT:-9091}" \ + s6-notifyoncheck -d -n 300 -w 1000 -c "nc -z ${HOST} ${PORT:-9091}" \ s6-setuidgid abc /usr/bin/transmission-daemon \ -g /config -f else - s6-notifyoncheck -d -n 300 -w 1000 -c "nc -z localhost ${PORT:-9091}" \ + s6-notifyoncheck -d -n 300 -w 1000 -c "nc -z ${HOST} ${PORT:-9091}" \ /usr/bin/transmission-daemon \ -g /config -f fi diff --git a/root/etc/s6-overlay/s6-rc.d/svc-transmission/timeout-finish b/root/etc/s6-overlay/s6-rc.d/svc-transmission/timeout-finish new file mode 100644 index 00000000..3a05c8b3 --- /dev/null +++ b/root/etc/s6-overlay/s6-rc.d/svc-transmission/timeout-finish @@ -0,0 +1 @@ +30000