Remove MinIO
All checks were successful
Deploy storage stack / deploy (push) Successful in 20s

Garage serves all three buckets and both apps, and a last comparison
found nothing in MinIO that Garage lacks. Drop the MinIO service, its
bootstrap and its root credentials from the deploy, and let compose
remove the leftover containers.

The storage_minio_data volume is left on the host. All images can be
pulled again, so the deploy goes back to failing on a pull error.

Document Garage in the README and SECRETS, including the key format and
how the existing secrets map to it, and swap the MinIO client in the
flake for awscli and rclone.

Assisted-by: Claude:fable-5-2
This commit is contained in:
Sergei Poljanski 2026-11-11 03:55:18 +04:00
commit e9388c0b0d
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
6 changed files with 74 additions and 231 deletions

View file

@ -1,14 +1,16 @@
# storage
Postgres + MinIO for asxp.io and any future small services that need a database
Postgres + Garage (S3) for asxp.io and any future small services that need a database
or object storage. Single-host, no clustering. Deploys via Forgejo Actions to
the same box that runs the apps.
## What's here
- `docker-compose.yml` — `postgres`, `minio`, and one-shot init containers.
- `docker-compose.yml` — `postgres`, its one-shot init container, and `garage`.
- `garage.toml` — Garage's config (single node, no secrets in it).
- `init/postgres-init.sh` — idempotent role/DB bootstrap.
- `init/minio-bootstrap.sh` — idempotent bucket + per-app service account.
- `init/garage-bootstrap.sh` — idempotent buckets, per-app keys and grants;
run on the host by the deploy, through `docker exec`.
- `.forgejo/workflows/deploy.yaml` — pushes compose + `.env` to the prod host
and runs `docker compose up -d`.
@ -17,15 +19,29 @@ the same box that runs the apps.
Two Docker networks:
- `storage` — internal-only; apps join this as an external network to reach
`postgres:5432` and `minio:9000`.
- `traefik` — existing reverse-proxy network. Only MinIO joins it, to expose
`postgres:5432` and `garage:3900`.
- `traefik` — existing reverse-proxy network. Only Garage joins it, to expose
the S3 API at `https://s3.asxp.io`.
The MinIO console (`:9001`) is **not** exposed externally. To use it, SSH-port-forward:
Garage replaced MinIO in November 2026 (MinIO was abandoned upstream and its
images removed from the registries).
## The `public` bucket
Garage answers no anonymous S3 request. `public` is marked as a website
instead, and Traefik sends unsigned GET/HEAD of
`https://s3.asxp.io/public/<key>` to Garage's web endpoint. Anyone who knows a
key can read it; nobody can list the bucket. Uploading needs the uploader key
(see `SECRETS.md`).
## Looking inside
The image has no shell; use the CLI through `docker exec`:
```sh
ssh -L 9001:storage-minio:9001 deploy@prod
# then open http://localhost:9001
ssh prod 'docker exec storage-garage /garage status'
ssh prod 'docker exec storage-garage /garage bucket list'
ssh prod 'docker exec storage-garage /garage key list'
```
## Adding a new app
@ -35,20 +51,27 @@ ssh -L 9001:storage-minio:9001 deploy@prod
3. Add Forgejo secrets `FOO_DB_PASSWORD`, `FOO_S3_ACCESS_KEY`, `FOO_S3_SECRET_KEY`
to this repo *and* to the foo repo.
4. Extend `init/postgres-init.sh` with `ensure_role "foo" ...` and `ensure_db "foo" "foo"`.
5. Extend `init/minio-bootstrap.sh` with `ensure_bucket "foo-..."`,
`write_policy "foo-...-rw" "foo-..."`, `ensure_user ... "foo-...-rw"`.
5. Extend `init/garage-bootstrap.sh` with `ensure_bucket "foo-..."`, an
`ensure_key foo ...` and a `grant` for it.
6. Pass the new envs through in `docker-compose.yml` and the deploy workflow.
7. Push.
## State and backups
Two named Docker volumes are stateful:
Three named Docker volumes are stateful:
- `pg_data` (Postgres data dir) — `/var/lib/docker/volumes/storage_pg_data/_data`
- `minio_data` (S3 object bytes) — `/var/lib/docker/volumes/storage_minio_data/_data`
- `garage_data` (S3 object bytes) and `garage_meta` (Garage's database,
with a snapshot every 6 h) — `/var/lib/docker/volumes/storage_garage_*/_data`
Server-level backup covers both. If you ever move off whole-server backup,
the minimum is `pg_dumpall` for Postgres and `mc mirror` for MinIO.
`/opt/storage/secrets/garage_rpc_secret` (Garage's node-to-node and CLI
secret) is made on the host at the first deploy and is not in Forgejo.
Server-level backup covers all three. If you ever move off whole-server backup,
the minimum is `pg_dumpall` for Postgres and `rclone sync` of each bucket.
The old `storage_minio_data` volume is still on the host from before the move;
nothing uses it.
## Secrets