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>
36 lines
1.6 KiB
Docker
36 lines
1.6 KiB
Docker
# nginx 1.30.0-alpine
|
|
FROM nginx@sha256:0272e4604ed93c1792f03695a033a6e8546840f86e0de20a884bb17d2c924883
|
|
|
|
# Copy tailscale binaries from official image (v1.94.2)
|
|
COPY --from=docker.io/tailscale/tailscale@sha256:95e528798bebe75f39b10e74e7051cf51188ee615934f232ba7ad06a3390ffa1 \
|
|
/usr/local/bin/tailscaled /usr/local/bin/tailscaled
|
|
COPY --from=docker.io/tailscale/tailscale@sha256:95e528798bebe75f39b10e74e7051cf51188ee615934f232ba7ad06a3390ffa1 \
|
|
/usr/local/bin/tailscale /usr/local/bin/tailscale
|
|
|
|
RUN mkdir -p /var/run/tailscale /var/lib/tailscale \
|
|
&& apk add --no-cache iptables ip6tables \
|
|
&& apk add --no-cache libc6-compat \
|
|
&& apk add --no-cache fail2ban \
|
|
&& rm -f /etc/fail2ban/jail.d/alpine-ssh.conf
|
|
|
|
# Copy Alloy binary from official image (v1.16.0, Ubuntu-based, needs libc6-compat)
|
|
COPY --from=docker.io/grafana/alloy@sha256:6e00cf7c5a692ff5f24844529416ed017d76fce922f8199004e73d5eca46b6b8 \
|
|
/bin/alloy /usr/local/bin/alloy
|
|
|
|
RUN mkdir -p /var/log/nginx /etc/alloy /tmp/alloy-data
|
|
|
|
COPY fail2ban/filter.d/forge-login.conf /etc/fail2ban/filter.d/forge-login.conf
|
|
COPY fail2ban/filter.d/shower-admin-login.conf /etc/fail2ban/filter.d/shower-admin-login.conf
|
|
COPY fail2ban/jail.d/forge.conf /etc/fail2ban/jail.d/forge.conf
|
|
COPY fail2ban/jail.d/shower.conf /etc/fail2ban/jail.d/shower.conf
|
|
COPY fail2ban/action.d/nginx-deny.conf /etc/fail2ban/action.d/nginx-deny.conf
|
|
|
|
COPY nginx.conf /etc/nginx/nginx.conf
|
|
COPY error.html /usr/share/nginx/html/error.html
|
|
COPY alloy.river /etc/alloy/config.alloy
|
|
COPY start.sh /start.sh
|
|
RUN chmod +x /start.sh
|
|
|
|
EXPOSE 8080
|
|
|
|
CMD ["/start.sh"]
|