MinIO provides an S3-compatible object storage API that works well for development, private clouds, backups, and application file storage. This guide starts with a single-node Docker Compose deployment and then explains what must change before exposing it to production traffic.

Prerequisites

Install Docker Engine and the Docker Compose plugin, then verify them:

1
2
docker version
docker compose version

Create directories for persistent data and configuration:

1
2
sudo mkdir -p /srv/minio/data
sudo chown -R 1000:1000 /srv/minio

Docker Compose configuration

Create compose.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
services:
minio:
image: quay.io/minio/minio:RELEASE.2024-09-22T00-33-43Z
container_name: minio
command: server /data --console-address ":9001"
restart: unless-stopped
environment:
MINIO_ROOT_USER: ${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
volumes:
- /srv/minio/data:/data
ports:
- "9000:9000"
- "9001:9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 10s
retries: 3

Store credentials in a local .env file and keep it out of version control:

1
2
MINIO_ROOT_USER=minio-root
MINIO_ROOT_PASSWORD=replace-with-a-long-random-secret

Start the service and inspect its health:

1
2
3
docker compose up -d
docker compose ps
docker compose logs --tail=100 minio

The S3 API listens on port 9000; the administration console uses 9001.

Configure the MinIO client

Install the official mc client, then create an alias:

1
2
3
4
mc alias set local http://127.0.0.1:9000 minio-root 'your-password'
mc admin info local
mc mb local/example
mc ls local

Applications should not use the root account. Create a dedicated user and attach only the policy it needs:

1
2
mc admin user add local app-user 'another-long-random-secret'
mc admin policy attach local readwrite --user app-user

For production, replace the broad readwrite policy with a bucket-specific policy.

Production checklist

A running container is not yet a resilient storage service:

  • Terminate TLS at MinIO or a trusted reverse proxy, and do not expose the console publicly without access controls.
  • Pin an image release, test upgrades in staging, and read the release notes before changing versions.
  • Use multiple drives and nodes when availability matters. A single data directory has no disk redundancy.
  • Back up configuration and critical objects to a separate failure domain.
  • Monitor disk capacity, request errors, latency, and node health.
  • Restrict ports with a firewall and rotate credentials regularly.

Common problems

If the container exits immediately, check directory ownership and docker compose logs. If S3 requests work locally but fail through a proxy, verify forwarded headers, the public server URL, TLS configuration, and request-size limits. Clock drift can also break signed S3 requests, so keep the host synchronized with NTP.