Two distinct bugs, same root cause: the rendered scripts run with
'set -euo pipefail', but the generator used unquoted heredoc delimiters
(<<CONF_EOF) for config files. Bash expands $vars inside unquoted heredocs;
with 'set -u' any undefined variable aborts the heredoc, and because the
heredoc sits inside 'cat > FILE <<TAG ... TAG', the file gets opened
(truncated to zero bytes) but never written.
1) nginx generator (generators/middleware.py)
- The HTTPS server block ended with '}}\n' instead of '}\n', causing
'nginx -t' to fail with 'unexpected "}"'.
- Both server confs (HTTP + HTTPS) wrote $uri / $host / $scheme /
$request_uri / $proxy_add_x_forwarded_for / $remote_addr into
unquoted heredocs. With set -u the heredoc for harbor.yunwei.blog.conf
aborted on $scheme (and similar), leaving the file empty.
Fix: change both heredoc delimiters to <<'CONF_EOF' (quoted), and
remove the trailing extra '}'. Also strip the unnecessary Python
f-string '{{' / '}}' escapes that produced '}' in the output.
2) mongodb repo (generators/runtimes.py)
- The yum repo file used <<REPO_EOF (unquoted) with a body containing
'$releasever'. $releasever is yum's own variable, not bash's;
bash expanded it to '' under set -u and left the URL broken.
Wireguard/openvpn heredocs DO use $(...) command substitution
intentionally (to inline keys), so those stay unquoted.
Fix: change delimiter to <<'REPO_EOF'.
Verified:
- Rendered nginx.sh for harbor.yunwei.blog (proxy + SSL on port 78/443)
produces conf files with correct nginx syntax. Real 'nginx -t' on a
minimal test config passes (configuration syntax is ok / test is
successful).
- Audit of all 50 generators with default params shows zero $VAR
references inside unquoted heredocs (only intentional $(...) cmds).
- All 50 generators still pass 'bash -n'.
In bash with 'set -u', an undefined variable triggers an unbound-variable
error. Functions don't satisfy '$FUNCNAME' expansion under set -u, so
the previous fix that kept '$PKG_INSTALL pkg...' as the call syntax
broke every call site:
docker.sh: line 53: PKG_INSTALL: unbound variable
Fix: drop the leading '$' in all 47 call sites across 6 generator
files. 'PKG_INSTALL pkg...' is a normal command/function lookup and
behaves identically under set -u or not.
Verified: web UI served docker.sh now has 'PKG_INSTALL' (no $);
'bash -n' passes; smoke run with stubbed PATH hits real line-53 call
site, mock apt-get receives correct args, exit 0, no unbound variable.
Sampled 6 other generators also syntax-OK with $PKG_INSTALL count 0.
Go official tarball always extracts to <parent>/go. The old code always ran
'mv <parent>/go <install_dir>', which errors with 'cannot move /opt/go to a
subdirectory of itself' when install_dir equals the extraction target (the
default /opt/go). Only emit the mv when install_dir differs from the tar
extraction path.
Both Node.js and Java generators were emitting URLs that 404'd when
selected against the official dist servers.
Node.js: emitted v<major>.x placeholders (e.g. v24.x). nodejs.org's
dist server requires exact version paths (e.g. v24.19.0); the v<x>.x
form is not a redirect — it's a real 404. All 5 supported majors
(18, 20, 22, 24, 26) were broken.
Java: URL was hardcoded to download.java.net's openjdk-21.0.2 GA
build. That path only works for 21; 8, 11, 17 all 404. download.java.net
embeds a build hash in the URL that I don't have a way to look up
for arbitrary patch versions.
Fix:
Node.js: add a LATEST_KNOWN dict mapping each major to its real
current exact version (refreshed 2026-08):
18 -> 18.20.8, 20 -> 20.20.2, 22 -> 22.23.2,
24 -> 24.19.0, 26 -> 26.6.0
Also add a 'download_url' text field with the precise default URL,
so users can override with any mirror (Tuna, npmmirror, etc.) or
a specific patch version without waiting for code to update.
Java: switch to Tuna's Adoptium mirror, whose path format is simple
and predictable:
https://mirrors.tuna.tsinghua.edu.cn/Adoptium/<major>/jdk/x64/linux/OpenJDK<major>U-jdk_x64_linux_hotspot_<exact>.tar.gz
This works for 8/11/17/21 with the LATEST_TUNA mapping. Also add a
'download_url' text field for overrides.
Both also derive the tarball's inner directory name from the URL (via
regex) so the --strip-components=1 trick keeps working even when the
user picks a custom URL.
Verified all 9 generated URLs return 200 (HEAD):
Node v18/20/22/24/26: all 200
Java v8/11/17/21: all 200 (Tuna mirror)
All 50 generators still pass bash -n.