How-to Guides¶
Scope
Tasks for running MinIO: choosing a build, installing from source, deploying a distributed cluster or the Kubernetes Operator, setting parity, managing IAM, encryption, TLS, audit logs, site replication, lifecycle rules, monitoring, tuning, replacing deleted Docker Hub images, and migrating data off MinIO. Facts and limits are in Reference; internals are in Explanation.
Community edition status (2026-09)
The minio/minio repository is archived and gets no fixes. There are no official community binaries or images, and the minio/minio and minio/mc Docker Hub repositories were deleted on 2026-09-11. The server commands below work the same on the last community build, AIStor, and the PGSTY Silo fork, unless marked otherwise.
Choose an Install Path¶
| Need | Path | Section |
|---|---|---|
| Supported multi-node production with vendor SLA | AIStor Enterprise Lite (below 400 TiB) or Enterprise | AIStor docs |
| Free, single node, full console | AIStor Free (license key from min.io/download) | AIStor docs |
| Open source, packaged, with console and backported fixes | PGSTY Silo fork | Run the Silo Fork |
| Open source, exact upstream code, own risk | Community edition from source | Install From Source |
| Leave MinIO | Another S3 store | Migrate Data Off MinIO |
Install From Source¶
The community edition is distributed as source only since October 2025. It needs Go 1.24 or later.
# Build the latest (final) community code into $GOPATH/bin
go install github.com/minio/minio@latest
# Or pin the last tagged community release
go install github.com/minio/minio@RELEASE.2025-10-15T17-29-55Z
# Cross-compile for another platform from a checkout
git clone https://github.com/minio/minio && cd minio
env GOOS=linux GOARCH=arm64 go build
# Single node, single drive, for development
export MINIO_ROOT_USER=admin
export MINIO_ROOT_PASSWORD='change-me-long-password'
minio server /data --console-address ":9001"
What the community build gives you
Since RELEASE.2025-05-24T17-08-30Z the embedded console on port 9001 is an object browser only. Users, policies, and configuration are managed with mc admin. CVE-2026-39414 is not fixed in any community build.
Build a Container Image¶
The repository's Dockerfile expects a minio binary in the project root.
git clone https://github.com/minio/minio && cd minio
go build -o minio .
docker build -t myminio:minio .
docker run -p 9000:9000 -p 9001:9001 myminio:minio server /tmp/minio --console-address :9001
Run the Silo Fork¶
PGSTY Silo is an AGPLv3 fork that restores the full console and publishes images and packages. It keeps the MINIO_* variables and on-disk format.
docker run -d --name silo -p 9000:9000 -p 9001:9001 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=change-me-long-password \
-v "$PWD/data:/data" \
docker.io/pgsty/silo:latest server /data --console-address ":9001"
# The image bundles the client as mcli
docker exec silo mcli alias set local http://127.0.0.1:9000 minioadmin change-me-long-password
docker exec silo mcli mb local/demo
Pin a release tag (for example RELEASE.2026-09-03T13-18-01Z) in production instead of latest.
Deploy a Distributed Cluster¶
Use at least 4 nodes with identical drives. Run the same command on every node; {1...4} is MinIO's expansion syntax, not shell brace expansion.
# /etc/default/minio (same on every node)
MINIO_VOLUMES="https://minio{1...4}.example.net:9000/mnt/disk{1...4}/minio"
MINIO_OPTS="--console-address :9001"
MINIO_ROOT_USER=admin
MINIO_ROOT_PASSWORD='change-me-long-password'
# Equivalent one-off command
minio server https://minio{1...4}.example.net:9000/mnt/disk{1...4}/minio --console-address ":9001"
| Topology | Nodes x drives | Erasure sets (auto) | Default parity | Usable share |
|---|---|---|---|---|
| Minimal HA | 4 x 4 = 16 | 1 set of 16 | EC:4 | 75% |
| Production | 8 x 8 = 64 | 4 sets of 16 | EC:4 | 75% |
| Large scale | 16 x 12 = 192 | 12 sets of 16 | EC:4 (EC:3 to EC:8 possible) | 75% at EC:4 |
MinIO picks the largest set size from 2 to 16 that divides the drive count and keeps each set spread evenly across nodes. Check the result with mc admin info after startup.
To add capacity, append a second pool to the same command on every node and restart all nodes together:
minio server https://minio{1...4}.example.net:9000/mnt/disk{1...4}/minio \
https://minio{5...8}.example.net:9000/mnt/disk{1...4}/minio
To retire an old pool, drain it with mc admin decommission start ALIAS/ https://minio{1...4}.example.net:9000/mnt/disk{1...4}/minio, then remove it from the command line.
Deploy on Kubernetes With the Operator¶
Operator is frozen
The minio/operator repository was reported archived on 2026-03-20. v7.1.1 is the final chart and needs Kubernetes 1.30 or later. The Silo project documents the same charts for its fork.
# Helm (charts still served from operator.min.io)
helm repo add minio https://operator.min.io/
helm install --namespace minio-operator --create-namespace minio-operator minio/operator
# 4-node tenant with default values
helm install --namespace tenant-ns --create-namespace tenant minio/tenant
# Alternative: kustomize, pinned to the final release
kubectl kustomize github.com/minio/operator\?ref=v7.1.1 | kubectl apply -f -
kubectl apply -k github.com/minio/operator/examples/kustomization/base
kubectl get pods -n minio-operator
A minimal Tenant resource looks like this (production tenants also need a configuration secret with root credentials, TLS settings, and a storage class):
apiVersion: minio.min.io/v2
kind: Tenant
metadata:
name: myminio
namespace: tenant-ns
spec:
pools:
- servers: 4
volumesPerServer: 4
volumeClaimTemplate:
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 100Gi
Set Erasure Parity¶
Set parity before loading data. A change applies only to objects written afterwards.
# At startup (all nodes)
export MINIO_STORAGE_CLASS_STANDARD=EC:4
export MINIO_STORAGE_CLASS_RRS=EC:2
# At runtime
mc admin config set myminio storage_class standard=EC:4 rrs=EC:2
mc admin service restart myminio
# Per object: choose the reduced-redundancy class
mc cp --storage-class REDUCED_REDUNDANCY big.log myminio/logs/
Manage Users and Policies¶
Write a least-privilege policy, then attach it. Example: each user gets a private prefix through the ${aws:username} variable.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::mybucket"],
"Condition": {"StringLike": {"s3:prefix": ["${aws:username}/*"]}}
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": ["arn:aws:s3:::mybucket/${aws:username}/*"]
}
]
}
# Create a policy from a JSON file
mc admin policy create myminio home-prefix /tmp/home-prefix.json
# Create a user and attach the policy
mc admin user add myminio alice 'long-random-secret'
mc admin policy attach myminio home-prefix --user alice
# Attach a built-in policy to a group
mc admin group add myminio auditors bob
mc admin policy attach myminio readonly --group auditors
# Create an access key (service account) for an application
mc admin user svcacct add myminio alice
# Inspect and clean up
mc admin policy list myminio
mc admin policy info myminio home-prefix
mc admin policy detach myminio home-prefix --user alice
mc admin policy remove myminio home-prefix
# Block anonymous access on a bucket
mc anonymous set none myminio/mybucket
Use STS Credentials With mc¶
For Operator tenants that expose the STS endpoint, point mc at it; for any deployment, you can pass temporary credentials as a host alias.
# Operator STS endpoint for the alias myalias
export MC_STS_ENDPOINT_myalias=https://sts.minio-operator.svc.cluster.local:4223/sts/tenant-ns
# Temporary credentials (access key, secret key, session token) as an alias
export MC_HOST_myalias=https://ACCESSKEY:SECRETKEY:SESSIONTOKEN@minio.example.net
mc ls myalias
Configure Server-Side Encryption¶
SSE-S3 and SSE-KMS need a KMS. With the open-source stack that is KES (deprecated but working); AIStor uses MinKMS.
# Point MinIO at KES (all nodes)
export MINIO_KMS_KES_ENDPOINT=https://kes.example.net:7373
export MINIO_KMS_KES_KEY_FILE=/etc/minio/kes-client.key
export MINIO_KMS_KES_CERT_FILE=/etc/minio/kes-client.crt
export MINIO_KMS_KES_KEY_NAME=minio-default-key
# Create a named key and set bucket default encryption
mc admin kms key create myminio my-bucket-key
mc encrypt set sse-kms my-bucket-key myminio/mybucket
mc encrypt set sse-s3 myminio/otherbucket
mc encrypt info myminio/mybucket
# SSE-C: the client supplies a 32-byte base64 key per request (TLS required)
mc cp file.txt myminio/mybucket/secret/file.txt \
--enc-c "myminio/mybucket/secret/=c2VjcmV0ZW5jcnlwdGlvbmtleWNoYW5nZW1lMTIzNAo="
SSE-C key loss
MinIO never stores SSE-C keys. Losing the key loses the object. Older mc releases used --encrypt-key; current ones use --enc-c, --enc-kms, and --enc-s3.
Enable TLS¶
# Default location, picked up automatically
mkdir -p ~/.minio/certs/CAs
cp server-fullchain.crt ~/.minio/certs/public.crt
cp server.key ~/.minio/certs/private.key
cp internal-ca.crt ~/.minio/certs/CAs/
# Or a custom directory
minio server /data --certs-dir /opt/minio/certs
# Password-protected private key
export MINIO_CERT_PASSWD='key-password'
Send Audit Logs¶
# Webhook target (one per name)
mc admin config set myminio audit_webhook:siem endpoint="https://audit.example.net/minio" auth_token="Bearer TOKEN"
# Kafka target
mc admin config set myminio audit_kafka:target1 brokers=kafka1:9092 topic=minio-audit
mc admin config get myminio audit_webhook
mc admin service restart myminio
Set Up Site Replication¶
Only one site may contain data when you start. All sites must share the IdP and, for SSE, the KMS.
mc alias set site1 https://minio1.example.com admin 'password1'
mc alias set site2 https://minio2.example.com admin 'password2'
mc alias set site3 https://minio3.example.com admin 'password3'
mc admin replicate add site1 site2 site3
mc admin replicate info site1
mc admin replicate status site1
Configure Lifecycle Rules and Tiering¶
Transitions go to a remote tier you define first. The rule's storage class is the tier name.
# Define a warm tier on another MinIO deployment
mc ilm tier add minio myminio WARM-TIER \
--endpoint https://warm-minio.example.net \
--access-key ACCESSKEY --secret-key SECRETKEY \
--bucket warm-bucket --prefix hot-cluster/
# Transition after 90 days, expire noncurrent versions after 30 days
mc ilm rule add myminio/mybucket --transition-days 90 --transition-tier WARM-TIER
mc ilm rule add myminio/mybucket --noncurrent-expire-days 30
mc ilm rule ls myminio/mybucket
The same rules as an S3 lifecycle document (for mc ilm import or an SDK):
{
"Rules": [
{
"ID": "expire-old-versions",
"Status": "Enabled",
"Filter": {"Prefix": ""},
"NoncurrentVersionExpiration": {"NoncurrentDays": 30}
},
{
"ID": "transition-to-warm",
"Status": "Enabled",
"Filter": {"Prefix": ""},
"Transition": {"Days": 90, "StorageClass": "WARM-TIER"}
}
]
}
Monitor With Prometheus¶
# Health and topology
mc admin info myminio
# Generate a Prometheus scrape job with a bearer token
mc admin prometheus generate myminio cluster
mc admin prometheus generate myminio node
Alert on these v2 metrics (full list in Reference):
minio_cluster_health_status == 0
minio_cluster_health_erasure_set_status == 0
minio_cluster_drive_offline_total > 0
minio_cluster_nodes_offline_total > 0
rate(minio_s3_requests_5xx_errors_total[5m]) > 0
minio_node_drive_free_bytes / (minio_node_drive_free_bytes + minio_node_drive_used_bytes) < 0.1
Tune Scanner and Healing¶
The scanner and healer throttle themselves under load. Change them only when healing or lifecycle work falls behind.
# Scanner: lower delay = faster (default 10.0; 0 = full speed, not for production)
mc admin config set myminio scanner delay=5.0 max_wait=5s
# Healing: allow more concurrent I/O before throttling
mc admin config set myminio heal max_sleep=100ms max_io=200
# Show background healing status
mc admin heal myminio
Replace Docker Hub Images¶
Builds that pull minio/minio or minio/mc from Docker Hub fail since 2026-09-11. Repointing to Quay no longer works either: anonymous pulls of quay.io/minio/minio and quay.io/minio/mc return 401 Unauthorized on every tag (HeliosSoftware/hfs#1520, 2026-09-25; byteiota). Options:
# 1. Use the maintained fork image
docker pull docker.io/pgsty/silo:RELEASE.2026-09-03T13-18-01Z
# 2. Build your own from source (see Build a Container Image)
Security state of old images
If you still hold a mirrored copy of an old MinIO image, any image older than RELEASE.2025-10-15T17-29-55Z lacks the CVE-2025-62506 fix, and none has a fix for CVE-2026-39414.
Migrate Data Off MinIO¶
mc mirror copies buckets between any S3-compatible stores and can keep running to catch up with new writes.
mc alias set old https://minio.example.net admin 'password'
mc alias set new https://s3.new-store.example.net ACCESSKEY SECRETKEY
# Initial copy, preserving attributes
mc mirror --preserve old/mybucket new/mybucket
# Keep syncing until cutover
mc mirror --watch --preserve old/mybucket new/mybucket
# Compare before switching clients
mc diff old/mybucket new/mybucket
Export IAM before the move: mc admin cluster iam export myminio writes users, groups, and policies to a zip file that another MinIO-compatible server (AIStor or Silo) can import with mc admin cluster iam import.
Troubleshooting¶
| Issue | Diagnosis | Fix |
|---|---|---|
| Drive offline | mc admin info myminio |
Replace the drive with the same mount path; healing starts automatically |
| Erasure set lost write quorum | mc admin info, minio_cluster_health_erasure_set_status |
Bring drives or nodes back; parity at half the set needs K+1 drives |
| Slow uploads | Internode bandwidth or drive I/O (mc support perf myminio) |
Check the network between nodes, use NVMe, avoid RAID controllers |
SignatureDoesNotMatch behind a proxy |
Proxy rewrites Host or other signed headers |
Pass headers unchanged; set proxy_set_header Host $http_host in NGINX |
| Access denied | mc admin policy entities myminio --user alice |
Attach the correct policy; check bucket policy and session policy |
| Disk full | mc admin info --json myminio |
Add a pool, add expiry rules, or tier cold data |
| Console has no admin pages | Community build after 2025-05-24 | Use mc admin, AIStor, or the Silo fork |
docker pull minio/minio fails |
Docker Hub repository deleted 2026-09-11 | See Replace Docker Hub Images |
Commands & Recipes¶
Install mc¶
# Build the client from source (official community binaries are no longer published)
go install github.com/minio/mc@latest
# Legacy frozen binary (reported to return 410 Gone since 2026; kept for existing scripts)
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc && sudo mv mc /usr/local/bin/
Everyday mc Operations¶
# Configure an alias
mc alias set myminio https://minio.example.net admin 'password'
# Buckets
mc mb myminio/mybucket
mc ls myminio/
mc version enable myminio/mybucket
# Upload and download
mc cp file.txt myminio/mybucket/
mc cp myminio/mybucket/file.txt ./downloaded.txt
# Mirror a local directory
mc mirror /local/data/ myminio/mybucket/
# Usage and events
mc du myminio/mybucket
mc event add myminio/mybucket arn:minio:sqs::primary:webhook --event put,delete
# Server-side trace for debugging
mc admin trace myminio --verbose
Sources¶
- minio/minio README (install from source, Docker build)
- MinIO Operator README and Helm charts
- mc command reference (community docs source)
- MinIO configuration guide: scanner and healing
- MinIO logging and audit targets
- MinIO Prometheus metrics
- MinIO site replication
- PGSTY Silo README
- AIStor mc CLI reference