TechEarl

How to Run MinIO in Docker (Local S3-Compatible Storage)

Run a single MinIO container as a local S3-compatible object store: persistent volume on /data, console on 9001, S3 API on 9000, and how to point the AWS SDK at it for free dev work.

Ishan Karunaratne⏱️ 5 min readUpdated
Share thisCopied
Run MinIO in Docker as local S3-compatible storage: console on 9001, S3 API on 9000, persistent volume on /data, and how to point the AWS SDK at it without an AWS bill.

If you build against S3, you have two unappealing options for local dev: spend money calling AWS, or run something that emulates S3 on your machine. MinIO is the second option done well — a single Go binary that speaks the S3 API and has its own web console. Point the AWS SDK at it instead of s3.amazonaws.com and most of your code doesn't know the difference.

How do I run MinIO in Docker?

bash
docker run -d --name minio \
  -p 9000:9000 -p 9001:9001 \
  -e MINIO_ROOT_USER=minio-admin \
  -e MINIO_ROOT_PASSWORD=minio-password \
  -v minio-data:/data \
  quay.io/minio/minio \
  server /data --console-address ":9001"

S3 API on http://localhost:9000, console on http://localhost:9001. Log in to the console with minio-admin / minio-password, create a bucket, get access/secret keys.

Try it with your own values

Configure ports, credentials, and the data volume.

Why a volume on /data

MinIO stores object data, bucket metadata, and config under /data. Without a volume mount there, every docker rm wipes your buckets. The volume keeps the data alive:

bash
docker stop :container_name && docker rm :container_namedocker run -d --name :container_name 
-p :s3_port:9000 -p :console_port:9001 
-e MINIO_ROOT_USER=:user 
-e MINIO_ROOT_PASSWORD=:password 
-v minio-data:/data 
quay.io/minio/minio 
server /data --console-address ":9001"Buckets and objects are still there.

Practical usage: point the AWS SDK at MinIO

For a Node app using @aws-sdk/client-s3:

javascript
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const s3 = new S3Client({
  endpoint: 'http://127.0.0.1:9000',  // MinIO instead of s3.amazonaws.com
  region: 'us-east-1',                 // arbitrary, but required
  credentials: {
    accessKeyId: 'YOUR-MINIO-ACCESS-KEY',
    secretAccessKey: 'YOUR-MINIO-SECRET-KEY',
  },
  forcePathStyle: true,                // MinIO uses path-style URLs
});

await s3.send(new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'hello.txt',
  Body: 'Hello from MinIO',
}));

Three things to know:

  • endpoint points at MinIO's S3 port instead of AWS.
  • forcePathStyle: true — MinIO uses http://host:port/bucket/key URLs, not the virtual-host style AWS prefers (bucket.host:port/key). Without this flag, modern AWS SDKs default to virtual-host style and MinIO refuses.
  • region is required but unused. Anything works.

For Python boto3:

python
import boto3
s3 = boto3.client(
    's3',
    endpoint_url='http://127.0.0.1:9000',
    aws_access_key_id='YOUR-MINIO-ACCESS-KEY',
    aws_secret_access_key='YOUR-MINIO-SECRET-KEY',
    region_name='us-east-1',
)
s3.put_object(Bucket='my-bucket', Key='hello.txt', Body=b'Hello')

Same idea — different SDK, same MinIO. Once your app talks to MinIO locally, the only thing that changes when you point it at real AWS is the endpoint and credentials.

Generate access keys

The MINIO_ROOT_USER / MINIO_ROOT_PASSWORD env vars are the admin login for the console. For actual S3-API calls, generate access keys per application:

  1. Log into the console (http://localhost::console_port).
  2. Navigate to Identity → Access Keys → Create Access Key.
  3. Copy the access key and secret. The secret is shown only once.

Use those keys in your app's SDK config.

Compose example

yaml
services:
minio:
image: quay.io/minio/minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: :user
MINIO_ROOT_PASSWORD: :password
ports:
"::s3_port:9000"
"::console_port:9001"
volumes:
minio-data:/data
restart: unless-stopped
volumes:
minio-data:

Common pitfalls

  • No volume on /data. Buckets and objects die with the container.
  • AWS SDK using virtual-host URLs. MinIO speaks path-style by default; turn on forcePathStyle: true or --addressing-style path depending on the SDK.
  • MINIO_ACCESS_KEY / MINIO_SECRET_KEY env vars. Those names worked in older MinIO releases. Current MinIO uses MINIO_ROOT_USER / MINIO_ROOT_PASSWORD.
  • Connecting from a container. Inside Docker, MinIO is reachable via the service name (minio:9000), not 127.0.0.1. The endpoint in your SDK depends on whether the calling app runs on the host or in a sibling container.
  • HTTPS in dev. MinIO can do TLS but the dev pattern is plain HTTP. Don't waste time on certs locally; if your prod code requires HTTPS, configure that conditionally.

What to do next

FAQ

For the core S3 API (PutObject, GetObject, ListObjects, presigned URLs, multipart upload), yes. Some advanced AWS-specific features (S3 Glacier, Storage Lens, certain replication semantics) are not implemented. For most app code, you can swap MinIO for AWS S3 by changing the endpoint and keys.

AWS supports two URL styles for S3: virtual-host (bucket.s3.amazonaws.com/key) and path (s3.amazonaws.com/bucket/key). MinIO uses path style by default. Modern AWS SDKs default to virtual-host style and fail against MinIO without forcePathStyle: true (Node SDK) or addressing_style='path' (boto3 / Python).

Yes, the standard S3 presigned-URL API works. The signing region matters less than the endpoint, but the SDK still requires a region value (any valid string works).

Yes for testing — MinIO distributed mode runs across multiple containers if you set them up with the right peer addresses. For production, distributed MinIO typically runs on multiple hosts; in Docker, multi-node setups are for development of cluster-aware code.

Yes if you want self-hosted S3-compatible storage — MinIO is the most common open-source choice for that. The dev recipe above is for local development; production setups involve distributed mode, TLS, and IAM-style policies. Refer to MinIO's own docs for production deployment.

Sources

Authoritative references this article was fact-checked against.

TagsDockerMinIOS3Object StorageAWSDevOps

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Software Systems Architect · Senior Software Engineer · Engineering Leadership

Software systems architect and senior software engineer with more than two decades designing, building, and running production software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Now a CTO, though what I write here is drawn from the full arc of that work, across architecture, engineering, and operations, not any single job.

Keep reading

Related posts