Phase 1/2 of the podman standardization plan: service pages updated to the quadlet reality (units, Containers data roots, env-file secret convention, the v1-generator findings each caught live), Storage Policy documents the two rootless ownership regimes and the merge-move migration, Deployment Flow's service-manager table no longer claims dankserver media is bare inventory-only. Bundle change log entry added.
2.6 KiB
Storage Policy
All persistent data uses bind mounts: a host directory mapped directly into the container. No named volumes. This matches the preference of this repo and the existing Gitea stack on Dankclaw.
Why Bind Mounts
- The exact host location of every byte is visible and controllable.
- Backups are a simple
tarof known host directories. - The data survives container recreation and
podman-compose down. - Ownership is explicit: everything runs as UID 1000 (
dank) so host tools can read it.
Conventions
| Stack | Host data root |
|---|---|
| Dankserver | /home/dank/Containers/<svc>/ (romm, jellyfin, calibre-web, copyparty) |
| Dankclaw | /home/dank/Containers/<svc>/ (caddy, gitea, authentik, hermes, …) |
This layout was standardized on 2026-09-01. The old /opt/<service> roots were
migrated by the deployers' migrate_data_root (merge-move, numeric ownership
preserved); /opt holds no live container data on either host.
Ownership
Containers are rootless. Two regimes exist and the deployer must respect both:
- PUID/PGID images (linuxserver calibre-web, jellyfin): data is owned by
host uid 1000 (
dank) — plainchownis safe. - Mapped-uid images (official mariadb, redis, authentik, postgres): files
land in the subuid range (e.g. 100998 for container uid 999). Renaming such
a directory requires root (rename needs write on the directory itself) and
re-chowning to 1000 breaks the container's internal user. Migrations
therefore use
sudo mv(numeric-preserving) and skip the chown pass (migrate_data_root … keep).
stat -c '%u %n' /home/dank/Containers/romm/mariadb # 100998 = mapped, leave it
Secrets
Secrets never live in bind-mounted configs that get committed. The quadlet convention on both hosts:
- One host-local env file per stack at
/home/dank/Containers/<svc>/env(mode 0600), referenced from the unit's[Service] EnvironmentFile=so${VAR}expansion works atExecStarttime; never committed. .envfiles in the checkout (git-ignored,.env.examplecommitted as template) for compose-era and Caddy-rendered secrets.
Deployed units hold only variable expansions (${COPAY_ACCOUNT} …), never
literals — enforced by the no secret material seams. The live Gitea
database password exists only in /home/dank/Containers/gitea/env on
Dankclaw. A test enforces that it never appears in this repo.
See Also
- Deployment Flow
- Gitea — the original bind-mount stack, now on the Containers layout
- Backblaze Integration — future backup target for these mounts