fix(infra-setup): the DNS snippet it printed was not valid shell
deploy / build (push) Waiting to run
deploy / build-web (push) Waiting to run
deploy / deploy (push) Has been cancelled
deploy / deploy-web (push) Has been cancelled

Building the Cloudflare guidance out of nested-quote `echo` lines
mangled the credential extraction into

    ... | tr -d "'" ")

which is a syntax error if pasted. The whole point of printing it is
that somebody pastes it.

Prints a quoted heredoc instead, so the shell reproduces it verbatim,
and substitutes the three values with a sed pass afterwards -- doing it
inside the heredoc would put the quoting back in play, which is what
broke it. Verified by extracting the rendered snippet and running
`bash -n` over it.

Also states the ordering that matters, since the certificate and vhost
now exist while the name does not resolve: land a deploy that enforces
auth before publishing DNS, because until then an unresolvable name is
the only thing keeping the bucket private. And corrects the closing
advice, which still listed the pre-CLIENT_TOKENS secret set.

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 13:16:51 +03:00
co-authored by Claude Opus 5
parent 8595529051
commit 32621f98ad
+52 -20
View File
@@ -387,24 +387,48 @@ REMOTE
if getent hosts "${PUBLIC_NAME}" >/dev/null; then
ok "${PUBLIC_NAME} resolves to $(getent hosts "${PUBLIC_NAME}" | awk '{print $1}' | head -1)"
else
echo " ${PUBLIC_NAME} does not resolve yet. It is a zone apex, so it takes an"
echo " A record rather than a CNAME (public-dns.md §3). From ${PROXY_HOST}:"
echo
echo " TOKEN=\$(sudo grep -oP '(?<=dns_cloudflare_api_token\s=\s).*' \\"
echo " ${CERTBOT_CREDENTIALS} | tr -d \"'\" \")"
echo " zid=\$(curl -sS -H \"Authorization: Bearer \$TOKEN\" \\"
echo " 'https://api.cloudflare.com/client/v4/zones?name=${PUBLIC_NAME}' | jq -r '.result[0].id')"
echo " # apex: A record to this site's WAN address"
echo " curl -sS -X POST \"https://api.cloudflare.com/client/v4/zones/\$zid/dns_records\" \\"
echo " -H \"Authorization: Bearer \$TOKEN\" -H 'Content-Type: application/json' \\"
echo " --data '{\"type\":\"A\",\"name\":\"${PUBLIC_NAME}\",\"content\":\"$(dig +short ${SITE_INDIRECTION} A | head -1)\",\"ttl\":1,\"proxied\":false,\"comment\":\"rustingface\"}'"
echo " # www: CNAME to the site indirection, so a re-homed site is one record"
echo " curl -sS -X POST \"https://api.cloudflare.com/client/v4/zones/\$zid/dns_records\" \\"
echo " -H \"Authorization: Bearer \$TOKEN\" -H 'Content-Type: application/json' \\"
echo " --data '{\"type\":\"CNAME\",\"name\":\"www.${PUBLIC_NAME}\",\"content\":\"${SITE_INDIRECTION}\",\"ttl\":1,\"proxied\":false,\"comment\":\"rustingface\"}'"
echo
echo " Run these from ${PROXY_HOST}: the token is already there, and copying it"
echo " off the host spreads a credential that can edit every zone we own."
local wan
wan=$(dig +short "${SITE_INDIRECTION}" A | head -1)
warn "${PUBLIC_NAME} does not resolve yet, so nothing is publicly reachable.
Publishing it is deliberately not automated: the Cloudflare token can rewrite DNS for
every zone on the account, including MX records for domains whose mail we host
(public-dns.md §1). Run this on ${PROXY_HOST}, where the token already is -- copying it
off the host spreads a credential that can edit every zone we own.
BEFORE YOU DO: confirm the service is enforcing auth, or publishing the name makes every
stored model world-downloadable and lets anyone fill the bucket:
ssh ${SERVICE_HOST} 'sudo grep -E \"^(mode|anonymous|allow_new_repos)\" /etc/${APP}/config.toml'
expecting mode = \"bearer\", anonymous = \"catalog\", allow_new_repos = false."
# A quoted heredoc so the shell prints it exactly as written, then a
# sed pass for the three values -- substituting inside the heredoc
# would put the quoting back in play, which is what mangled the
# `tr -d` line the first time.
cat <<'DNS' | sed -e "s|__APEX__|${PUBLIC_NAME}|g" \
-e "s|__SITE__|${SITE_INDIRECTION}|g" \
-e "s|__WAN__|${wan}|g"
TOKEN=$(sudo grep -oP '(?<=dns_cloudflare_api_token\s=\s).*' /root/.certbot-internal \
| tr -d "\"' ")
zid=$(curl -sS -H "Authorization: Bearer $TOKEN" \
"https://api.cloudflare.com/client/v4/zones?name=__APEX__" | jq -r '.result[0].id')
# The apex takes an A record: a zone apex cannot be a CNAME (public-dns.md §3).
curl -sS -X POST "https://api.cloudflare.com/client/v4/zones/$zid/dns_records" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
--data '{"type":"A","name":"__APEX__","content":"__WAN__","ttl":1,"proxied":false,"comment":"rustingface"}' \
| jq -r 'if .success then "created \(.result.name) -> \(.result.content)" else "FAILED \(.errors)" end'
# www goes through the site indirection, so re-homing the site is one record.
curl -sS -X POST "https://api.cloudflare.com/client/v4/zones/$zid/dns_records" \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
--data '{"type":"CNAME","name":"www.__APEX__","content":"__SITE__","ttl":1,"proxied":false,"comment":"rustingface"}' \
| jq -r 'if .success then "created \(.result.name) -> \(.result.content)" else "FAILED \(.errors)" end'
DNS
fi
info "mesh DNS"
@@ -442,8 +466,16 @@ main() {
fi
info "done"
echo " Next: set the Gitea repo secrets (RSYNC_SSH_KEY, S3_ACCESS_KEY_ID,"
echo " S3_SECRET_ACCESS_KEY, HF_TOKEN) and push to main to deploy."
cat <<'NEXT'
Repo secrets this deploy needs: RSYNC_SSH_KEY, S3_ACCESS_KEY_ID,
S3_SECRET_ACCESS_KEY, CLIENT_TOKENS, and HF_TOKEN (optional, gated repos
only). Push to main to deploy.
Order matters for the public name: land a deploy that enforces auth
BEFORE publishing DNS. The certificate and vhost above are inert while the
name does not resolve, which is the only thing keeping the bucket private
until then.
NEXT
}
main "$@"