DocHub/storage
Tianyang 0f0b7e9d32 feat: add Garage as self-hosted S3-compatible storage, replacing MinIO
MinIO's community edition has been trimming features and its licensing
direction has grown less predictable. Garage (AGPL, purpose-built for
self-hosting) is a drop-in S3-compatible replacement — no changes needed
to backend/app/minio_client.py, which talks to the S3 API generically.

Deployed independently from the app stack (storage/docker-compose.yml),
same separation MinIO had. Single-node config (replication_factor = 1)
matching this project's learning/small-team scope. init-garage.sh handles
the one-time layout assignment + bucket creation Garage requires that
MinIO didn't (MinIO auto-creates buckets via API; Garage needs an
explicit `garage bucket create` step).
2026-08-01 09:43:08 +08:00
..
docker-compose.yml feat: add Garage as self-hosted S3-compatible storage, replacing MinIO 2026-08-01 09:43:08 +08:00
garage.toml feat: add Garage as self-hosted S3-compatible storage, replacing MinIO 2026-08-01 09:43:08 +08:00
init-garage.sh feat: add Garage as self-hosted S3-compatible storage, replacing MinIO 2026-08-01 09:43:08 +08:00
README.md feat: add Garage as self-hosted S3-compatible storage, replacing MinIO 2026-08-01 09:43:08 +08:00

DocHub Storage (Garage)

S3-compatible object storage for DocHub, deployed independently from the app stack in docker-compose.yml at the repo root — same separation as was used for MinIO, just backed by Garage instead. Garage was chosen because MinIO's community edition has been scaling back features and its licensing direction has grown less predictable; Garage is fully open source (AGPL) and purpose-built for self-hosting. Both speak the S3 API, so backend/app/minio_client.py needed no code changes — only connection settings differ.

Single-node setup, matching this project's learning/small-team scope (replication_factor = 1 in garage.toml — no data redundancy across nodes, since there's only one node).

First-time setup

cd storage
docker compose up -d
./init-garage.sh
docker compose exec garage /garage key info dochub-backend

The last command prints an access key ID and secret key. Set those as MINIO_ACCESS_KEY / MINIO_SECRET_KEY for the DocHub backend (the env var names stay MINIO_* because backend/app/config.py was written against the S3 API, not against MinIO specifically).

Connecting the backend

From the repo root, when running docker compose up there:

MINIO_ENDPOINT=<this-server-ip>:3900 \
MINIO_ACCESS_KEY=<from init-garage.sh> \
MINIO_SECRET_KEY=<from init-garage.sh> \
docker compose up -d

Garage's S3 API listens on port 3900 (vs MinIO's 9000) — that's the only endpoint difference the rest of the stack needs to know about.