fix(infra-setup): don't report a cert mismatch mid-reload

The post-reload check compares the certificate on the wire against the
one on disk, because nginx keeps its previous cycle -- and its previous
certificates -- when a reload cannot rebind, while still reporting
success. That check is right and it fired on the first run of this
script.

It was a false positive. Old workers finish their in-flight connections
before exiting, so for a second or two after a reload either cycle may
answer, and the check sampled the old one. A warning that cries wolf on
every first install is worse than no warning, because the real thing
gets ignored.

Retries for up to twenty seconds before reporting a mismatch. Verified
against hanzalova: the first run warned, the serials matched moments
later, and a re-run reports the match immediately.

Also makes the caveman and DNS steps report state rather than always
printing instructions, now that both are provisioned, and points the
bucket guidance at architecture/object-storage.md §3 -- including why
the script refuses to read the MinIO root credentials itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XZG2i4AmfSqE97EJGBVb64
This commit is contained in:
2026-08-31 11:05:17 +03:00
co-authored by Claude Opus 5
parent 8578ca6e0d
commit 0aa27dfb25
+28 -7
View File
@@ -168,12 +168,21 @@ S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY."
return 0
fi
warn "bucket and service-account creation needs MinIO root credentials, which
this script deliberately does not read. Run on $MINIO_HOST as an operator:
if ssh "$MINIO_HOST" "mc --version >/dev/null && test -d /srv/minio/$BUCKET"; then
ok "bucket $BUCKET exists"
return 0
fi
mc alias set local $MINIO_URL \"\$MINIO_ROOT_USER\" \"\$MINIO_ROOT_PASSWORD\"
warn "bucket and service-account creation needs the MinIO root credentials, which
this script deliberately does not read -- they are root-equivalent for every bucket on
that host, not just this one. Run there as an operator (architecture object-storage.md §3):
set -a; source <(sudo cat /etc/minio/minio.env); set +a
export MC_CONFIG_DIR=\$(mktemp -d); trap 'rm -rf \"\$MC_CONFIG_DIR\"' EXIT
mc alias set local http://127.0.0.1:9000 \"\$MINIO_ROOT_USER\" \"\$MINIO_ROOT_PASSWORD\"
mc mb --ignore-existing local/$BUCKET
mc admin user svcacct add local \"\$MINIO_ROOT_USER\" --name rustingface
mc admin user svcacct add local \"\$MINIO_ROOT_USER\" --name $APP \\
--access-key '$APP-<8 random>' --policy <policy scoped to $BUCKET>
then set the Gitea repo secrets S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY.
Re-run this script with --skip-minio once that is done."
@@ -244,10 +253,18 @@ provision_proxy() {
# A reload is a request, not a guarantee: nginx keeps its old cycle if it
# cannot rebind, and then serves the certificate it loaded then. Compare
# what is actually on the wire against what is on disk, by serial.
#
# Old workers finish their in-flight connections before exiting, so for a
# second or two after a reload either cycle may answer. Retry rather than
# report a mismatch that is really just the handover in progress.
local served disk
served=$(echo | openssl s_client -servername ${VHOST}.internal -connect ${PROXY_HOST}:443 2>/dev/null \
| openssl x509 -noout -serial || echo "serial=unavailable")
disk=$(ssh "$PROXY_HOST" "sudo openssl x509 -noout -serial -in $cert")
for _ in $(seq 1 10); do
served=$(echo | openssl s_client -servername ${VHOST}.internal -connect ${PROXY_HOST}:443 2>/dev/null \
| openssl x509 -noout -serial || echo "serial=unavailable")
[ "$served" = "$disk" ] && break
sleep 2
done
if [ "$served" = "$disk" ]; then
ok "the certificate on the wire matches the one on disk"
else
@@ -260,7 +277,11 @@ Investigate the bind failure in the nginx error log, then restart nginx."
fi
info "DNS"
echo " Add the split-horizon record if it is not already present:"
if getent hosts "${VHOST}.internal" >/dev/null; then
ok "${VHOST}.internal resolves"
return 0
fi
echo " Add the split-horizon record on both routers:"
echo " opn-cli --config ~/.opn-cli/hanzalova.yml unbound host create \\"
echo " --hostname ${VHOST} --domain internal --server 10.6.0.46 \\"
echo " --description 'rustingface via hanzalova reverse proxy (bob backend)'"