From c217f5f8f3f2b2cbe06066f431e26c55692d7e1e Mon Sep 17 00:00:00 2001 From: Marco Wende Date: Mon, 21 Sep 2026 13:54:56 +0200 Subject: [PATCH] Docker: socat-Bridge auf richtige Loopback-Familie (IPv4/IPv6) ausrichten .NET-HttpListener bindet den Prefix "localhost" im Container auf IPv6 ::1, socat verband aber auf 127.0.0.1 -> "Connection refused". Entrypoint startet die App jetzt zuerst, erkennt ob IPv4 oder IPv6 antwortet und richtet socat darauf aus. Kein Eingriff in den App-Code. Co-Authored-By: Claude Opus 4.8 --- docker/docker-entrypoint.sh | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh index 528c77a..c888bc4 100755 --- a/docker/docker-entrypoint.sh +++ b/docker/docker-entrypoint.sh @@ -1,14 +1,36 @@ #!/usr/bin/env bash -# Startet die App unveraendert (bindet auf 127.0.0.1:APP_PORT) und leitet externe +# Startet die App unveraendert (bindet auf localhost:APP_PORT) und leitet externe # Verbindungen per socat-Bridge dorthin - so bleibt der App-Code unangetastet. +# +# HINWEIS: .NET-HttpListener bindet den Prefix "localhost" je nach System auf IPv4 +# ODER IPv6. Deshalb ermitteln wir zur Laufzeit, welche Loopback-Familie antwortet, +# und richten socat darauf aus (sonst "Connection refused"). set -e : "${APP_PORT:=8077}" : "${BRIDGE_PORT:=8080}" -# Bridge im Hintergrund: 0.0.0.0:BRIDGE_PORT -> 127.0.0.1:APP_PORT -# (fork = pro Verbindung ein Prozess; reuseaddr = schneller Neustart). -socat "TCP-LISTEN:${BRIDGE_PORT},fork,reuseaddr" "TCP:127.0.0.1:${APP_PORT}" & +# App im Hintergrund starten. -NoBrowser: im Container kein Desktop/open. +pwsh -NoProfile -File /app/Start.ps1 -NoBrowser -Port "${APP_PORT}" & +APP_PID=$! -# App im Vordergrund (Logs -> stdout). -NoBrowser: im Container kein Desktop/open. -exec pwsh -NoProfile -File /app/Start.ps1 -NoBrowser -Port "${APP_PORT}" +# Warten bis der Listener antwortet und dabei IPv4 vs. IPv6 erkennen. +# Default = IPv6 (haeufigster Fall im Container); IPv4 wird bevorzugt, wenn erreichbar. +SOCAT_TARGET="TCP6:[::1]:${APP_PORT}" +for i in $(seq 1 30); do + if (exec 3<>"/dev/tcp/127.0.0.1/${APP_PORT}") 2>/dev/null; then + exec 3>&-; SOCAT_TARGET="TCP4:127.0.0.1:${APP_PORT}"; break + fi + if (exec 3<>"/dev/tcp/::1/${APP_PORT}") 2>/dev/null; then + exec 3>&-; SOCAT_TARGET="TCP6:[::1]:${APP_PORT}"; break + fi + # App unerwartet beendet? Dann mit deren Exit-Code aussteigen. + kill -0 "$APP_PID" 2>/dev/null || { echo "[entrypoint] App-Prozess beendet - Abbruch."; wait "$APP_PID"; exit $?; } + sleep 1 +done + +echo "[entrypoint] Bridge: 0.0.0.0:${BRIDGE_PORT} -> ${SOCAT_TARGET}" +socat "TCP-LISTEN:${BRIDGE_PORT},fork,reuseaddr" "${SOCAT_TARGET}" & + +# Am Leben des App-Prozesses haengen (Container endet, wenn die App endet). +wait "$APP_PID"