hermes vhost: dial netavark's host address, not the LAN IP (fixes the 502)

hermes-webui is Network=host, so 8787 is a bare host-netns bind, and netavark
DNATs only *published* ports. From Caddy's bridge netns 192.168.0.143:8787 and
10.89.1.1:8787 are both refused, while host.containers.internal:8787
(169.254.1.2) answers 200 — measured live 2026-09-16 from inside the Caddy
container. The dashboard's published 9119 answers on that same LAN IP, which is
what made the old upstream look sound.

The vhost comment asserted "192.168.0.143:8787 is open" from that bridge; it is
not, so the claim is replaced with the measurement, and the hermes-webui quadlet
comment carries the same correction. The seam guarding this invariant accepted
any numeric upstream, so the LAN IP passed it; it now pins the measured-working
form and fails on the LAN IP (teeth verified by substitution).
This commit is contained in:
Frank
2026-09-16 19:28:34 -07:00
parent 65fbef63dc
commit d14e0a94eb
3 changed files with 30 additions and 15 deletions
+16 -6
View File
@@ -44,14 +44,24 @@ webui_service_yaml() {
caddy="$REPO_ROOT/dankclaw/Caddyfile"
grep -q 'HERMES_WEBUI_PASSWORD' <<< "$y" \
|| { echo "password gate missing"; return 1; }
# This unit is host-networked, so Caddy cannot reach it by container name:
# hermes.franksdank.cloud proxies to the host's LAN address. The app's bind
# is therefore load-bearing for that vhost — a loopback-only bind was tried
# on 2026-09-16 and broke it (502), while host networking means there is no
# port forwarder to bridge the gap.
# This unit is host-networked, so Caddy cannot reach it by container name.
# The app's bind is load-bearing for that vhost — a loopback-only bind was
# tried on 2026-09-16 and broke it (502), while host networking means there
# is no port forwarder to bridge the gap.
#
# The upstream must be netavark's HOST ADDRESS, not the host's LAN IP.
# 8787 is a bare host-netns bind and netavark DNATs only *published* ports,
# so from Caddy's bridge netns 192.168.0.143:8787 and 10.89.1.1:8787 are
# both refused, while host.containers.internal:8787 (169.254.1.2) answers
# 200 — measured 2026-09-16 from inside the Caddy container. The dashboard's
# published 9119 is reachable on the LAN IP precisely because it IS
# published. Pin the measured-working form so reverting to the LAN IP cannot
# pass silently.
local upstream
upstream=$(grep -A 6 '^hermes\.franksdank\.cloud {' "$caddy" | grep -oE 'reverse_proxy [0-9.]+:[0-9]+' | head -1)
upstream=$(grep -A 6 '^hermes\.franksdank\.cloud {' "$caddy" | grep -oE 'reverse_proxy [^ {]+' | head -1)
[ -n "$upstream" ] || { echo "no hermes vhost upstream in the Caddyfile"; return 1; }
grep -qE '^reverse_proxy (host\.containers\.internal|169\.254\.1\.2):8787$' <<< "$upstream" \
|| { echo "hermes upstream is '$upstream', not netavark's host address (host.containers.internal:8787)"; return 1; }
grep -q 'Environment=HERMES_WEBUI_HOST=0.0.0.0' <<< "$y" \
|| { echo "webui must bind all interfaces: $upstream cannot reach loopback"; return 1; }
}