feat(forge): stand up the off-cluster Forgejo mirror host #740
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/forge-jail-kript"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Phase 1 of moving off Codeberg: a reproducible Forgejo at https://git.kri.pt,
in a FreeBSD jail on
freebsd-fsn1. It serves. Nothing mirrors to it yet.Build or converge:
scripts/freebsd/forge-jail.sh, as root on the host.Prove:
tests/forge-jail.sh, from anywhere. Both are bash + jq. No Python.Why
Codeberg does four jobs, not one. Count them before retiring it:
importSourceseedBOOTSTRAP_REPO_URLin the Makefile)sean/linuxbackupcheck-kernel-source-backup.shproves beforemake rebuild166 tracked files name Codeberg; 158 are live config, scripts or tests.
This host replaces jobs 1 and 2 later. Because it runs outside the cluster it
also survives
make rebuild, which makes it a better bootstrap source thanCodeberg rather than only a replacement.
The host is a live k3s node, and that shaped every choice
fbsd-k8sownsbridge100and thek8spfanchor, whoserdrrules carryzdns on 53, 443 and 853.
pfctl -f /etc/pf.confempties anchors declared in themain ruleset, so a
pfreload here takes production DNS down.The jail is therefore non-vnet and shares the host address: no
natrule, nordrrule, no edit to/etc/pf.conf. The script asserts the node is healthybefore it starts and again after it finishes. The guard fails if
forgerulesever appear in
pf.conf.The sharp edge
The kernel rewrites
127.0.0.1to the jail's first address, so the privatealias
127.0.1.1is listed first and the public address second. A daemon thatnaively binds
localhostthen lands somewhere private.nginx alone holds a public port. Forgejo binds
127.0.1.1:3000. PostgreSQL hasno TCP listener at all. The guard probes 3000 and 5432 from outside the host,
because from inside both look reachable either way.
Three defects the red-green loop caught
Each is kept as a comment where it bit:
secret()logged to stdout from inside a command substitution, so a logline was captured into
PG_PASS.app.inigot aPASSWDline holding a logmessage and a bare secret on the next line, and Forgejo refused to boot.
step()andinfo()now write to stderr, closing the class.jls -hprints its column header even when no jail matches, so the guard'soriginal "is it running" check could never fail. It asks for the jid now.
app.inito addLFS_JWT_SECRETand[oauth2] JWT_SECRET.The script now supplies both, so converging no longer mints new ones and
invalidates every LFS token and OAuth2 session.
Verification
app.ini unchanged— genuinely idempotent.ncdetects anopen 443, does not detect 3000; the reversed address order is rejected).
fbsd-k8sup,bridge100up, 3rdrrules in the
k8sanchor.acme.sh, notcertbot— verified the dependency closure of nginx, acme.sh,forgejo15 and postgresql17-server pulls in no python3.
Deliberately not done
per-identifier limit and this estate burns it. Switching is
ACME_CA=letsencrypt,once, when the host is proven. A staging cert will make
git clonerefuse.Codeberg until proven.
FreeBSD ports tree). Mirroring is plain git over HTTPS and the seed uses the
Gitea-compatible API 15 serves, so it should be fine — prove it on one repo
before trusting it with 37.
Load-bearing warning
rpoolon this host is a stripe of two NVMe devices, no redundancy. TheOmniOS box is a single disk. Codeberg is still the only second copy of
sean/linux. Do not retire Codeberg until a second copy of this host exists.Also:
kri.ptexpires 23 October 2026.https://claude.ai/code/session_01XdBRc9CHgFhAxCyHbdVtt6
5eac2a10b34d010225be