Builds the container the "1 container" decision (D15) actually needs, which D15 itself deferred as follow-up work: Caddy + the FastAPI app + the static SvelteKit build in one image, SQLite on a mounted volume. See docs/DECISIONS.md D16 for the specific choices and why (entrypoint-run migrations instead of a separate deploy-pipeline step, tini + a small supervisor script instead of s6-overlay/supervisord, copying the Caddy binary out of its official image). Removes apps/api/Dockerfile and apps/web/Dockerfile from the old 4-container compose plan (PR #4, closed as superseded) — the root Dockerfile replaces both with one multi-stage build. deploy/unraid-template.xml turns VELODROME_PUBLIC_URL, VELODROME_SECRET_KEY, etc. into fillable Unraid Community Applications web UI fields, per the earlier decision to keep config there instead of a .env file. .gitea/workflows/release.yml builds and pushes the image to the Gitea registry on a version tag or manual dispatch; it does not touch the running container. Verified by actually running the built image, not just building it: the health endpoint responds through Caddy's proxy, the SPA serves with working client-route fallback, alembic ran and produced a real (non-empty) SQLite file under /data, the process runs as the non-root velodrome user, and killing the uvicorn process brings the whole container down (exit 143) rather than leaving Caddy serving alone — confirming the entrypoint's coupled-lifetime behavior actually holds, not just that it reads correctly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R2ZKeWkZV7ehf7fivrAkkG
38 lines
3.8 KiB
XML
38 lines
3.8 KiB
XML
<?xml version="1.0"?>
|
|
<!--
|
|
Unraid Docker "Template" for Community Applications' Add-Container form. This is what turns the
|
|
env vars in the table below into fillable fields in the Unraid web UI instead of a .env file —
|
|
see docs/DECISIONS.md D16 for why this exists.
|
|
|
|
Import: Docker tab -> Add Container -> Template drop-down -> pick this file (or paste the
|
|
"Template" URL if this repo is served over http from the Gitea instance). Every field is also
|
|
editable by hand afterward; nothing here is load-bearing beyond being a starting point.
|
|
-->
|
|
<Container version="2">
|
|
<Name>velodrome</Name>
|
|
<Repository>192.168.0.3:3000/bbergle/bike-app:latest</Repository>
|
|
<Registry>http://192.168.0.3:3000/BBergle/-/packages/container/bike-app</Registry>
|
|
<Network>bridge</Network>
|
|
<Privileged>false</Privileged>
|
|
<Support>https://192.168.0.3:3000/BBergle/bike-app/issues</Support>
|
|
<Project>http://192.168.0.3:3000/BBergle/bike-app</Project>
|
|
<Overview>Self-hosted cycling app: Bryton Rider 650 ride sync, mileage tracking, spare-parts inventory, and maintenance reminders. One container: Caddy + the FastAPI app + a SQLite database file on the Data path below. See docs/PLAN.md and docs/DECISIONS.md (D15/D16) in the repo for the design.</Overview>
|
|
<Category>Productivity:</Category>
|
|
<WebUI>http://[IP]:[PORT:8080]/</WebUI>
|
|
<Icon/>
|
|
<ExtraParams/>
|
|
<PostArgs/>
|
|
<CPUset/>
|
|
<DateInstalled/>
|
|
<DonateText/>
|
|
<DonateLink/>
|
|
<Description>Self-hosted cycling app: Bryton ride sync, mileage tracking, spare-parts inventory, maintenance reminders.</Description>
|
|
<Config Name="Web UI Port" Target="8080" Default="8080" Mode="tcp" Description="Container's HTTP port. Put a reverse proxy with TLS in front of this — the container itself only ever serves plain HTTP (docs/PLAN.md 'Service topology')." Type="Port" Display="always" Required="true" Mask="false">8080</Config>
|
|
<Config Name="Data" Target="/data" Default="/mnt/user/appdata/velodrome" Mode="rw" Description="The SQLite database file (and, in a later phase, the raw-file blob store) live here. This is the only thing worth backing up." Type="Path" Display="always" Required="true" Mask="false">/mnt/user/appdata/velodrome</Config>
|
|
<Config Name="VELODROME_PUBLIC_URL" Target="VELODROME_PUBLIC_URL" Default="" Mode="" Description="The externally-visible URL this instance is reachable at, e.g. https://bikes.example.com. Must match exactly what's in the browser's address bar — it's checked against the Origin header on cookie-authenticated requests to stop cross-site request forgery." Type="Variable" Display="always" Required="true" Mask="false"></Config>
|
|
<Config Name="VELODROME_SECRET_KEY" Target="VELODROME_SECRET_KEY" Default="" Mode="" Description="A random secret, 32+ bytes. Generate one with: openssl rand -hex 32. The image ships an insecure development placeholder — always override this before exposing the container to anything." Type="Variable" Display="always" Required="true" Mask="true"></Config>
|
|
<Config Name="VELODROME_ENVIRONMENT" Target="VELODROME_ENVIRONMENT" Default="production" Mode="" Description="development | test | production. Gates the session cookie's Secure flag — leave this as production for any deployment reachable over HTTPS." Type="Variable" Display="always" Required="true" Mask="false">production</Config>
|
|
<Config Name="VELODROME_SESSION_TTL_DAYS" Target="VELODROME_SESSION_TTL_DAYS" Default="90" Mode="" Description="Days before a login session expires and re-authentication is required." Type="Variable" Display="advanced" Required="false" Mask="false">90</Config>
|
|
<Config Name="VELODROME_SESSION_COOKIE_NAME" Target="VELODROME_SESSION_COOKIE_NAME" Default="vd_session" Mode="" Description="Name of the session cookie. No reason to change this unless it collides with another app on the same domain." Type="Variable" Display="advanced" Required="false" Mask="false">vd_session</Config>
|
|
</Container>
|