diff --git a/.gitea/workflows/nightly.yml b/.gitea/workflows/nightly.yml index 490a91fc..a16a0797 100644 --- a/.gitea/workflows/nightly.yml +++ b/.gitea/workflows/nightly.yml @@ -158,16 +158,20 @@ jobs: # public surface works. This step catches: Caddy not reloaded, HSTS # header dropped, /actuator block bypassed. # - # --resolve pins staging.raddatz.cloud to the runner's loopback so we - # do NOT depend on the host router doing hairpin NAT (many SOHO - # routers do not, or do so only after a firmware update). SNI still - # uses the public hostname so the cert validates correctly. + # --resolve pins staging.raddatz.cloud to the Docker bridge gateway IP + # (the host) so we do NOT depend on hairpin NAT on the host router. + # 127.0.0.1 cannot be used: job containers run in bridge network mode + # (runner-config.yaml), so 127.0.0.1 is the container's loopback, not + # the host's. The bridge gateway IS the host; Caddy binds 0.0.0.0:443 + # and is therefore reachable from the container via that IP. + # SNI still uses the public hostname so the TLS cert validates correctly. run: | set -e HOST="staging.raddatz.cloud" URL="https://$HOST" - RESOLVE="--resolve $HOST:443:127.0.0.1" - echo "Smoke test: $URL (pinned to 127.0.0.1)" + HOST_IP=$(ip route show default | awk '/default/ {print $3}') + RESOLVE="--resolve $HOST:443:$HOST_IP" + echo "Smoke test: $URL (pinned to $HOST_IP via bridge gateway)" curl -fsS $RESOLVE --max-time 10 "$URL/login" -o /dev/null # Pin the preload-list-eligible HSTS value, not just header presence: # a degraded `max-age=1` or a dropped `includeSubDomains; preload` must diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 8d355da2..4dafb0e3 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -107,14 +107,15 @@ jobs: - name: Smoke test deployed environment # See nightly.yml — same three checks, against the prod vhost. - # --resolve pins archiv.raddatz.cloud to the runner's loopback so - # the smoke test does NOT depend on hairpin NAT on the host router. + # --resolve pins to the bridge gateway IP (the host), not 127.0.0.1 + # — see nightly.yml for the full network topology explanation. run: | set -e HOST="archiv.raddatz.cloud" URL="https://$HOST" - RESOLVE="--resolve $HOST:443:127.0.0.1" - echo "Smoke test: $URL (pinned to 127.0.0.1)" + HOST_IP=$(ip route show default | awk '/default/ {print $3}') + RESOLVE="--resolve $HOST:443:$HOST_IP" + echo "Smoke test: $URL (pinned to $HOST_IP via bridge gateway)" curl -fsS $RESOLVE --max-time 10 "$URL/login" -o /dev/null # Pin the preload-list-eligible HSTS value, not just header presence: # a degraded `max-age=1` or a dropped `includeSubDomains; preload` must