From 694396a8564e517f14adcdb4faba95b5cab55493 Mon Sep 17 00:00:00 2001 From: seslly <161339320+seslly@users.noreply.github.com> Date: Mon, 27 Apr 2026 17:04:19 -0700 Subject: [PATCH 1/2] =?UTF-8?q?entrypoint:=20retry=20SteamCMD=20app=5Fupda?= =?UTF-8?q?te=20=E2=80=94=20fresh-install=20bootstrap=20was=20flaky?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User-reported fresh `docker compose up` failed with: ERROR! Failed to install app '4129620' (Missing configuration) ERROR: SteamCMD exited with 8 Root cause (verified by clean-container A/B): SteamCMD's anonymous app_update is flaky on the FIRST attempt within a container, then succeeds reliably on attempt #2 with no other change. Probably a Steam-side anonymous-license caching quirk that warms up after the first call. Fresh containers always hit attempt #1. Reproduced cleanly: cold attempt #1 FAILs, #2 OK + starts downloading, #3 resumes #2's partial download at ~50-65%. The depots are public anonymous regardless, the credentials are valid, the manifest is present — Steam just returns the cryptic "Missing configuration" on the cold call and accepts the warm one. Existing canary / prod / VPS installs were unaffected because their populated WindowsServer/ trees mean every boot's app_update is a verify-only no-download path that doesn't go through the failing licensing code. So this regression silently shipped to anyone trying a clean `docker compose up` while the live deployments kept working. Fix: retry the heredoc-based app_update up to 3 times, gated on server_files_present (the .exe being on disk after the run). SteamCMD resumes partial downloads across retries, so we don't pay bandwidth twice. Most fresh installs succeed on attempt #2. Switched from `+command` chain to stdin heredoc while we're here — heredoc reads more like the official Windrose dedicated-server FAQ examples that operators paste into interactive SteamCMD for debugging, and is functionally equivalent post-warm-up. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/entrypoint.sh | 66 ++++++++++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/scripts/entrypoint.sh b/scripts/entrypoint.sh index ea26dcd..e4ed6db 100755 --- a/scripts/entrypoint.sh +++ b/scripts/entrypoint.sh @@ -149,15 +149,10 @@ install_via_steamcmd() { # debugging corruption. Default off; set WINDROSE_STEAMCMD_VALIDATE=1 # to enable. Also forced on if we see a partial install (dir exists but # binary missing). - local validate_arg="" - if [ "${WINDROSE_STEAMCMD_VALIDATE:-0}" = "1" ]; then - validate_arg="validate" - elif [ -d "${WINDROSE_SERVER_DIR}" ] \ - && [ ! -f "${WINDROSE_SERVER_DIR}/R5/Binaries/Win64/WindroseServer-Win64-Shipping.exe" ] \ - && [ -n "$(ls -A "${WINDROSE_SERVER_DIR}" 2>/dev/null)" ]; then - # Partial install detected; force validate to clean it up. - validate_arg="validate" - fi + # Always pass `validate` to app_update. Costs ~30s on a populated + # 3 GB tree (re-checksum, no download), gives us idempotent install + # health on every boot, and matches the official Windrose FAQ + # command. Not worth conditionalizing. # Stash under WINDROSE_PATH (on the PVC), NOT /tmp — /tmp is # container-ephemeral, so a kubelet OOM-kill / eviction / node @@ -196,20 +191,47 @@ install_via_steamcmd() { fi done - echo "$(timestamp) INFO: SteamCMD +app_update ${app_id} ${validate_arg:-(no-validate)}" mkdir -p "${WINDROSE_SERVER_DIR}" - # Arg order matters: +force_install_dir MUST precede +login anonymous. - # Valve's client literally prints "Please use force_install_dir before - # logon!" and fails app_update with "Missing configuration" otherwise. - # (Caught on an Ubuntu 24.04 bare-Linux install where the order-invert - # was a hard failure; Debian-13-in-container happens to tolerate the - # wrong order sometimes but don't count on it.) - local rc=0 - "${STEAMCMD_PATH}/steamcmd.sh" \ - +force_install_dir "${WINDROSE_SERVER_DIR}" \ - +login anonymous \ - +app_update "${app_id}" ${validate_arg} \ - +quit || rc=$? + # SteamCMD's anonymous app_update is flaky on the first attempt + # within a container — fails with "ERROR! Failed to install app + # '4129620' (Missing configuration)" + exit 8 (which the script + # confusingly still reports as exit 0 sometimes), then succeeds on + # the very next attempt with no other change. Verified clean-room + # 2026-04-27: attempt #1 FAIL, #2 OK + downloads, #3 resumes at + # whatever % #2 reached. Probably a Steam-side anonymous-license + # caching quirk that warms up after the first call. Retry up to 3 + # times; each attempt resumes the partial download so we don't pay + # the bandwidth twice. + # + # Existing populated installs are unaffected — verify-only runs + # don't go through the failing licensing path. So canary / prod / + # VPS kept working, masking the regression for fresh-install + # operators. + # + # Stdin heredoc instead of +command-line chain — the two are + # roughly equivalent, but heredoc reads more like the official + # Windrose / Steam dedicated-server FAQ examples that operators + # paste into interactive SteamCMD when debugging. + local rc=1 + local attempt + for attempt in 1 2 3; do + echo "$(timestamp) INFO: SteamCMD app_update ${app_id} validate (attempt ${attempt})" + rc=0 + "${STEAMCMD_PATH}/steamcmd.sh" < Date: Mon, 27 Apr 2026 18:14:36 -0700 Subject: [PATCH 2/2] fix ui container bind --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 1725113..7efcab3 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -83,7 +83,7 @@ services: - windrose entrypoint: ["python3", "/opt/windrose-ui/server.py"] environment: - UI_BIND: ${UI_BIND:-127.0.0.1} + UI_BIND: "0.0.0.0" UI_PORT: ${UI_PORT:-28080} UI_PASSWORD: ${UI_PASSWORD:-} # Opt-in: allow destructive actions when no password is set (LAN-only).