Skip to content

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

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.

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.

  • 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-api entitlement check — never as unauthenticated files from the web server.
  • At M5, introduce an S3-compatible backend (candidates: pgsty/minio fork, 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.