ADR-0003: Object storage via the S3 API (MinIO now)
Synced read-only from
/home/synnet/synvirt-platform/docs-internal/adr/0003-storage-s3-minio.md. Edit at the source, not here.
ADR-0003: Object storage via the S3 API (MinIO now)
Section titled “ADR-0003: Object storage via the S3 API (MinIO now)”- Status: Accepted — amended 2026-07-14 (object storage deferred to M5)
- Date: 2026-06-28
Context
Section titled “Context”Installers, ISOs, forum uploads and CMS media must not live on the web server’s local disk, and downloads must be authorized per entitlement. We also want to be free to move storage to a managed provider later.
Decision
Section titled “Decision”All artifacts and uploads go through the S3 API. Run MinIO as a container
now; apps speak plain S3. Downloads are served via time-limited signed URLs
issued by portal-api after an entitlement check — never by streaming bytes from
the web server’s disk. The MinIO console is dev-only and never public.
Consequences
Section titled “Consequences”- Swapping to AWS S3 / Cloudflare R2 / Wasabi later = change
S3_ENDPOINT+ credentials; no code change. - Per-artifact metadata (SHA-256, signature, size, build ID, channel, arch) is stored alongside the object / in the portal DB and surfaced to users.
- Requires correct bucket policy (
mc anonymous set none) so objects are only reachable via signed URLs.
Note (2026-06): MinIO upstream is EOL — staying local for the MVP
Section titled “Note (2026-06): MinIO upstream is EOL — staying local for the MVP”Upstream minio/minio was archived 2026-04-25; :latest is frozen to the
~Sep-2025 image (missing the Oct-2025 CVE fix). Decision for the MVP: keep
object storage self-hosted/local (per product owner: “todo local de momento”).
We pin to the last official tag (RELEASE.2025-09-07T16-13-09Z) for reproducible
dev. The maintained drop-in pgsty/minio (Pigsty fork — same S3 API + restored
admin console, CVE-patched) is a one-line image swap and is the recommended path
if/when we want patches; revisit at M5/M8. Because everything speaks plain S3,
moving to the fork or to cloud S3/R2 later is config-only, no code change.
Amendment (2026-07-14): no object-storage service until M5
Section titled “Amendment (2026-07-14): no object-storage service until M5”Per product owner (“no quiero MinIO local, es innecesario de momento”), MinIO is removed from the compose stack entirely. Running an EOL’d service the MVP doesn’t use yet was cost without benefit.
- Payload media uses Payload’s default local-disk storage (an uploads
directory on the web app’s volume). It is included in filesystem backups
(see
runbooks/backup-restore.md). - The original requirement stands for M5: entitlement-gated downloads
(installers/ISOs) must be served via signed URLs after a
portal-apientitlement check — never as unauthenticated files from the web server. - At M5, introduce an S3-compatible backend (candidates:
pgsty/miniofork, Garage, or cloud S3/R2) and move Payload media to it with@payloadcms/storage-s3— an adapter + env change plus a file copy, not an app rewrite.