Reviewed (Opus security review, all findings verified) and tested end-to-end locally: cold build 23s, no-op poll 45ms, incremental rebuild 4s, prune, gitea-down grace, real bridge network with container DNS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012jWfn3RwPfFGTtBddm36Uy
5.3 KiB
5.3 KiB
Deploy — CTAO portal demo on strapi-experimental.cyfronet
Everything runs rootless as user strapi. Footprint on the machine:
ONE directory (~/ctao-portal-demo/) + 4 unit files in ~/.config/.
Uninstall restores the machine exactly (see bottom). No secrets in any file.
~/ctao-portal-demo/
├── gitea-data/ # Gitea state (repos, SQLite, accounts) ← the ONLY thing worth backing up
├── gitea-config/ # Gitea app.ini (generated from env)
├── repo/ # clone of the portal repo (created by first build)
├── releases/ # <sha>/ dirs + `current` symlink (what nginx serves)
├── state/ # last-built SHA
├── bin/build.sh # copied from deploy/ (source of truth stays in the repo)
└── config/nginx.conf
| Port | What | Exposed how |
|---|---|---|
| 3000 | Gitea | ingress vhost (TODO: ask Hubert) |
| 8080 | portal (nginx, static) | ingress vhost (TODO: ask Hubert) |
Install (each step reviewed before running; [W] = writes to the machine)
- [W]
mkdir -p ~/ctao-portal-demo/{gitea-data,gitea-config,releases,state,bin,config} ~/.config/containers/systemd ~/.config/systemd/user - [W] Copy files from this dir (scp from the Mac):
ctao-demo-gitea.container,ctao-demo-web.container,ctao-demo.network→~/.config/containers/systemd/ctao-portal-build.service,ctao-portal-build.timer→~/.config/systemd/user/build.sh→~/ctao-portal-demo/bin/(chmod +x)nginx.conf→~/ctao-portal-demo/config/
- [W] Pull + pin images (one-time, needs internet):
podman pull docker.io/gitea/gitea:1.27-rootless docker.io/library/nginx:stable-alpine docker.io/library/node:24-alpinepodman build -t localhost/ctao-portal-build:1 -f Containerfile.build .Thenpodman images --digests→ paste the sha256 digests into both.containerfiles. - [W]
systemctl --user daemon-reload && systemctl --user start ctao-demo-gitea - [W] Create the Gitea admin — run YOURSELF in your own terminal (password
is prompted/printed there only; never goes through chat or shell history):
podman exec -it ctao-demo-gitea gitea admin user create --admin --username <you> --email <you@…> --random-password - [W] In the Gitea UI: create org
ctao, repoportal(public read). Push from the Mac through an SSH port-forward:ssh -L 3300:localhost:3000 strapi-experimental.cyfronetthengit remote add machine http://localhost:3300/ctao/portal.git && git push machine main - [W]
systemctl --user enable --now ctao-portal-build.timer— first run clones +npm ci+ builds (minutes); later runs are seconds. Wait untiljournalctl --user -u ctao-portal-build -n 5showspublished <sha>(starting nginx earlier just serves 404s until the first build lands). - [W]
systemctl --user start ctao-demo-web - [R] Verify:
curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/andjournalctl --user -u ctao-portal-build -n 20(shows measured build times).
After Hubert assigns the vhosts
- Replace both
TODO(vhost)values inctao-demo-gitea.container(ROOT_URL → gitea vhost, CORS*→ portal origin, addGITEA__cors__SCHEME=https);systemctl --user daemon-reload && systemctl --user restart ctao-demo-gitea. - In Gitea UI: Settings → Applications → new OAuth2 app for Sveltia
(redirect:
https://<portal-vhost>/admin/), PKCE, no client secret. - Put the Gitea vhost URL + client id into
public/admin/config.ymlin the portal repo, commit, push — the timer publishes it like any other change.
Ask Hubert (one message)
- Two ingress vhosts →
192.168.10.15:8080(portal) and:3000(gitea) — same mechanism asstrapi.isl-dev…:1337. - Are vhosts public-internet or VPN-scopable? (Gitea preferably VPN-only.)
- Does Cyfronet offer static-file hosting on the ingress itself? If yes, we drop our nginx container entirely and rsync builds there instead.
Uninstall (leaves zero traces)
systemctl --user disable --now ctao-portal-build.timer
systemctl --user stop ctao-demo-web ctao-demo-gitea
rm ~/.config/containers/systemd/ctao-demo-*.container \
~/.config/containers/systemd/ctao-demo.network \
~/.config/systemd/user/ctao-portal-build.{service,timer}
systemctl --user daemon-reload
podman network rm ctao-demo 2>/dev/null || true
podman rmi localhost/ctao-portal-build:1 docker.io/gitea/gitea:1.27-rootless docker.io/library/nginx:stable-alpine
rm -rf ~/ctao-portal-demo
Notes
- Publish latency = poll (≤10 s) + build (measured 1 s on M-series; expect 4–8 s on the 2 vCPU VM — every build's time lands in the journal).
- Internet needed only for: image pulls (install) and
npm ciwhen the lockfile changes. Routine rebuilds are fully offline. - Memory caps (
MemoryHigh) keep us polite next to Outline + Strapi; the build container is capped at 1 GB viapodman run --memory. Watch the firstnpm ci+ build in the journal — if it OOMs inside its cgroup (contained, just retries), raise the cap. - Build isolation: build containers run on the
ctao-demobridge (seectao-demo.network) — repo/npm code cannot reach host loopback services. - Secrets inventory: Gitea admin password (typed interactively, lives only in Gitea's DB) — that's the complete list. Build/poll/serve use none.