blumeops/docs/changelog.d/shower-app-deploy.infra.md

9 lines
607 B
Markdown
Raw Normal View History

C1: deploy adelaide-baby-shower-app to ringtail k3s Adds the Adelaide / Heidi / Addie baby shower app — a Django guest splash, raffle picker, and prize-assignment console — on ringtail k3s. Public landing at shower.eblu.me (via fly proxy), tailnet admin at shower.ops.eblu.me. App source: forge.eblu.me/eblume/adelaide-baby-shower-app, wheel-published to the Forgejo Packages PyPI index. Manifests under argocd/manifests/shower/: NFS-backed PVC for /app/media, local-path PVC for SQLite, ExternalSecret pulling DJANGO_SECRET_KEY from 1Password (item "Shower (blumeops)"), Tailscale ProxyGroup ingress. Defense-in-depth for the public surface: - /admin/ blocked at the fly edge except /admin/login/ and /admin/logout/ - shower_auth rate limit on the login path - new fail2ban filter+jail with a per-service shower-deny.conf (nginx-deny action generalized to accept nginx_deny_file) - django-axes (5 / 1h) keyed on (username, ip_address) Plus: Caddy route on indri, Pulumi gandi CNAME, Grafana APM dashboard mirroring docs-apm.json, runbook at how-to/operations/shower-app.md, and a service-versions entry. X-Clacks-Overhead set on the new server block — GNU Terry Pratchett. Build: containers/shower/default.nix uses dockerTools to ship a nixpkgs Python plus a startup wrapper that installs the wheel into /app/data/.venv on first boot and execs gunicorn. Lets the wheel come from forge PyPI without pinning hashes for every transitive dep. Prerequisites tracked in the runbook (not yet executed): - NFS share sifaka:/volume1/shower (manual Synology step) - 1Password item "Shower (blumeops)" with secret-key field - container build via `mise run container-build-and-release shower` - Pulumi dns-up after merge - fly certs add shower.eblu.me Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 08:14:12 -07:00
Wire shower app for public exposure: fly nginx `shower.eblu.me` server
C1: bump shower to v1.0.1; collapse WAN admin to tailnet-only PR review caught that we didn't need an admin login surface on WAN. App v1.0.1 adds DJANGO_PUBLIC_URL_BASE so QR codes generated from /host/ (now tailnet-only) still point at shower.eblu.me for guest phones — that closes the loop and lets us strip the WAN admin surface entirely. Container: - bump version to 1.0.1 - outputHash → fakeHash (build will print the real one) - entrypoint still does migrate + collectstatic before gunicorn — the app is small enough that auto-migration is fine Manifests: - configmap adds DJANGO_PUBLIC_URL_BASE=https://shower.eblu.me Fly nginx (shower.eblu.me): - drop the /admin/(login|logout) carveout - 403 anything under /admin/ AND /host/ with a "tailnet only" pointer - drop the shower_auth limit_req zone and \$shower_banned geo - drop the shower-admin-login fail2ban filter + jail - drop the shower-deny.conf touch from start.sh Docs: - rename how-to docs/how-to/operations/shower-app.md → shower-on-ringtail.md (mirrors cv-on-indri / docs-on-indri) - new reference card docs/reference/services/shower-app.md per PR review comment 2 (≈30s read; quick facts + cross-links) - rewrite Defense layers section: collapses to general rate limit + django-axes on the tailnet-side login (the only credential surface) - rewrite the .infra.md changelog fragment to match - add a 'Create the admin user' step (kubectl exec createsuperuser) so first-time deploys aren't locked out The nginx-deny action's per-jail \`nginx_deny_file\` generalization stays — harmless future-proofing for the next public service. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 10:23:40 -07:00
block as a guest-only surface — splash page, `/prizes/<token>/`, static
assets, media. Everything authenticated (`/admin/`, `/host/`,
`/accounts/`) returns 403 with a "tailnet only" pointer. Staff hit
`shower.ops.eblu.me` for the operator console + admin; the app's
v1.0.1 `DJANGO_PUBLIC_URL_BASE` setting makes QR codes generated on
the tailnet point back at the WAN host for guests. Plus a Caddy route
on indri, Pulumi Gandi CNAME, and a Grafana APM dashboard tracking
request rate, error rate, latency, bandwidth, and access logs.