MinIO: S3 without the cloud
The first Longhorn backup RecurringJob never backed anything up — no loud error, just a job spinning in the void, because the longhorn-backups bucket did not exist yet. MinIO creates no bucket automatically, contrary to what you would expect from an “out of the box” S3 backend.
MinIO is an open-source object storage server whose API is fully compatible with AWS S3. Deployed on the cluster, it lets you use tools designed for S3 (AWS CLI, SDKs, Longhorn integrations) with no external dependency.
Use cases in this homelab:
- Longhorn backups: S3 destination for volume snapshots
- Artifact storage: locally built Docker images, archives, logs
- Experimentation: testing S3 integrations at no cloud cost
Standalone deployment
For a homelab, MinIO in standalone mode (a single node, no distributed mode) is enough. Resilience is provided by Longhorn on the underlying PVC.
containers:
- name: minio
image: minio/minio:latest
args:
- server
- /data
- --console-address
- :9001
env:
- name: MINIO_ROOT_USER
valueFrom:
secretKeyRef:
name: minio-credentials
key: access-key
- name: MINIO_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: minio-credentials
key: secret-key
ports:
- containerPort: 9000 # S3 API
- containerPort: 9001 # Web console
Note: minio/minio:latest is not pinned — prefer an explicit version tag for reproducible deployments.
Integration with Longhorn
This bucket is the target of the RecurringJobs described in Distributed block storage with Longhorn. Configuration in Longhorn Settings → General:
Backup Target: s3://longhorn-backups@us-east-1/
Backup Target Credential Secret: minio-s3-credentials
The secret must contain the keys AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY and AWS_ENDPOINTS (pointing at MinIO):
kubectl create secret generic minio-s3-credentials \
--from-literal=AWS_ACCESS_KEY_ID=<access-key> \
--from-literal=AWS_SECRET_ACCESS_KEY=<secret-key> \
--from-literal=AWS_ENDPOINTS=http://minio.minio.svc.cluster.local:9000 \
--namespace longhorn-system
The backup flow, in motion
The snapshot/backup back-and-forth speaks better animated than in prose. The three beats of the cycle light up in turn: the daily local snapshot (fast, but tied to the disk), the weekly export to the S3 bucket through the MinIO API, then the retention of the last 4 backups with restore available.
RecurringJob daily · 2h · retain 7
même disque que le volume — rapide, mais meurt avec le disque
RecurringJob weekly · dim 3h · retain 4
export incrémental via l’API S3 vers le bucket longhorn-backups
garde 4 backups · purge auto
le plus vieux est purgé ; restauration possible à tout moment
local-path (pas Longhorn) —
pour que la cible de backup ne dépende jamais du système qu’elle sauvegarde.
Lessons learned
Buckets have to be created by hand: create the buckets you need (longhorn-backups, loki, and so on) from the web console or the mc CLI before configuring the integrations.
--console-address :9001 has been mandatory since MinIO RELEASE.2022-x: without that argument, the web console shares port 9000 with the S3 API, causing conflicts. Exposing both ports through separate Services simplifies Traefik routing.
Encryption at rest: for genuinely sensitive data, enable server-side encryption in MinIO. For Longhorn backups, encryption is optional if the source Longhorn volume is already encrypted.