From ee96410828f11ebdd0ad9f1fc711600c16354beb Mon Sep 17 00:00:00 2001 From: John Coffey Date: Wed, 28 Oct 2026 15:18:08 -0700 Subject: [PATCH] Add the IPv6 listener once, so a restarted console starts listen-ipv6.sh writes "listen [::]:8080;" and then looked for "listen [::]:8080" with one space, so the check never matched. A new container was fine; restarting the same one (a reboot, docker restart, or an installer that stops and starts the stack) added a second listener, and nginx refused the duplicate and restarted in a loop. The check now allows any number of spaces. docker/listen-ipv6.test.sh runs the script on nginx.conf three times and checks for one IPv6 listener; CI runs it. Claude-Session: https://claude.ai/code/session_01Y2F7CWRXorttf5sjSbxwpj --- .gitea/workflows/ci.yml | 1 + docker/listen-ipv6.sh | 12 +++++++++--- docker/listen-ipv6.test.sh | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 docker/listen-ipv6.test.sh diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 4ddb8c0..7eb6789 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -71,6 +71,7 @@ jobs: - run: npm run i18n:check - run: npm test - run: sh tools/release-version.test.sh + - run: sh docker/listen-ipv6.test.sh - run: npm run build # A changed upstream file without the AGPL 5(a) notice, as inbuxa-server's diff --git a/docker/listen-ipv6.sh b/docker/listen-ipv6.sh index 62a22a9..c5c8b6c 100644 --- a/docker/listen-ipv6.sh +++ b/docker/listen-ipv6.sh @@ -8,10 +8,16 @@ # open. set -eu -conf=/etc/nginx/conf.d/default.conf +# Both paths can be moved for docker/listen-ipv6.test.sh. +conf=${NGINX_CONF:-/etc/nginx/conf.d/default.conf} +if_inet6=${IF_INET6:-/proc/net/if_inet6} -[ -f /proc/net/if_inet6 ] || { echo "no IPv6 on this host, listening on IPv4 only"; exit 0; } -grep -q 'listen \[::\]:8080' "$conf" && exit 0 +[ -f "$if_inet6" ] || { echo "no IPv6 on this host, listening on IPv4 only"; exit 0; } +# A restarted container keeps the file as the last start left it, so the +# listener may be there already: nginx refuses a duplicate listen and the +# container would restart in a loop. The line below is written with several +# spaces after "listen", so match any number. +grep -q 'listen *\[::\]:8080;' "$conf" && exit 0 # Written back through the file, as 40-api-base-url.sh does with index.html: # conf.d belongs to root, the file to the nginx user. diff --git a/docker/listen-ipv6.test.sh b/docker/listen-ipv6.test.sh new file mode 100644 index 0000000..07bec65 --- /dev/null +++ b/docker/listen-ipv6.test.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# SPDX-FileCopyrightText: 2026 Coffey Labs LLC +# SPDX-License-Identifier: AGPL-3.0-only +# Tests for listen-ipv6.sh: sh docker/listen-ipv6.test.sh +set -u +here=$(dirname "$0"); fail=0 +dir=$(mktemp -d); trap 'rm -rf "$dir"' EXIT +cp "$here/nginx.conf" "$dir/default.conf"; : > "$dir/if_inet6" +run() { NGINX_CONF="$dir/default.conf" IF_INET6="$1" sh "$here/listen-ipv6.sh" >/dev/null; } +listeners() { grep -c 'listen *\[::\]:8080;' "$dir/default.conf"; } + +run "$dir/none" +[ "$(listeners)" = 0 ] || { echo "FAIL: added an IPv6 listener without IPv6"; fail=1; } +run "$dir/if_inet6" +[ "$(listeners)" = 1 ] || { echo "FAIL: first start -> $(listeners) IPv6 listeners, want 1"; fail=1; } +# A restart of the same container runs the script again on the file it left. +run "$dir/if_inet6"; run "$dir/if_inet6" +[ "$(listeners)" = 1 ] || { echo "FAIL: after restarts -> $(listeners) IPv6 listeners, want 1"; fail=1; } +[ "$(grep -c 'listen *8080;' "$dir/default.conf")" = 1 ] || { echo "FAIL: the IPv4 listener changed"; fail=1; } +[ $fail = 0 ] && echo "listen-ipv6: ok" +exit $fail -- 2.54.0