Skip to Content

Self-Host MinIO: Your Own S3-Compatible Object Storage in 15 Minutes

Self-Host MinIO: Your Own S3-Compatible Object Storage in 15 Minutes

September 10, 2026 | 12 min read

Cloud object storage is convenient until the bill arrives. AWS S3 charges per gigabyte stored, per gigabyte transferred, and per thousand requests. For homelabs, startups, and privacy-conscious teams, those costs add up fast — and your data lives on someone else's infrastructure.

MinIO changes that. It's a high-performance, S3-compatible object storage server that runs on your hardware. One binary, one container, and you've got enterprise-grade storage with the same API as AWS S3. Backups, media libraries, application assets, ML datasets — MinIO handles them all without the egress fees.

In this guide, you'll deploy MinIO with Docker Compose, secure it with TLS, create buckets, and connect it to common tools. Let's get your own S3 running.

Why Self-Host Object Storage?

  • Cost control: No per-GB egress fees. Store terabytes, transfer freely.
  • Privacy: Your files never leave your infrastructure.
  • S3 compatibility: Works with existing AWS SDKs, Terraform, rclone, and hundreds of tools.
  • Performance: MinIO is faster than S3 for sequential workloads — written in Go, optimized for NVMe.
  • Simplicity: Single binary, no external dependencies, runs anywhere Docker runs.

Prerequisites

  • A VPS or server with 2+ CPU cores, 4GB RAM, 20GB+ disk (scale based on your data)
  • Docker and Docker Compose installed
  • A domain or subdomain pointing to your server (e.g., minio.yourdomain.com)
  • Basic familiarity with reverse proxies (we'll use Caddy for automatic TLS)

Step 1: Create the Docker Compose Stack

Create a directory for MinIO and add your docker-compose.yml:

mkdir -p ~/minio && cd ~/minio
cat > docker-compose.yml << 'EOF'
version: "3.8"

services:
  minio:
    image: minio/minio:latest
    container_name: minio
    restart: unless-stopped
    command: server /data --console-address ":9001"
    environment:
      MINIO_ROOT_USER: admin
      MINIO_ROOT_PASSWORD: your-secure-password-here
      MINIO_BROWSER_REDIRECT_URL: https://minio-console.yourdomain.com
      MINIO_SERVER_URL: https://minio.yourdomain.com
    volumes:
      - ./data:/data
    ports:
      - "9000:9000"  # S3 API
      - "9001:9001"  # Web Console
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 30s
      timeout: 20s
      retries: 3

  # Optional: Caddy for automatic TLS
  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config

volumes:
  caddy_data:
  caddy_config:
EOF

Key configuration:

  • MINIO_ROOT_USER / MINIO_ROOT_PASSWORD — your admin credentials. Use a strong password; this is full storage access.
  • --console-address ":9001" — separates the web UI from the S3 API port.
  • ./data:/data — where objects are stored. Use a dedicated disk or volume for production.

Step 2: Configure Caddy for TLS

Create a Caddyfile for automatic HTTPS:

cat > Caddyfile << 'EOF'
minio.yourdomain.com {
    reverse_proxy minio:9000
}

minio-console.yourdomain.com {
    reverse_proxy minio:9001
}
EOF

Replace yourdomain.com with your actual domain. Caddy handles Let's Encrypt automatically — no certbot needed.

Step 3: Launch MinIO

docker compose up -d

# Verify containers are running
docker compose ps

# Check logs for the ready message
docker logs minio | grep "API"

You should see output like:

API: https://minio.yourdomain.com
Console: https://minio-console.yourdomain.com

Documentation: https://min.io/docs/minio/linux/index.html

Step 4: Access the Web Console

Open https://minio-console.yourdomain.com in your browser. Log in with:

  • Username: admin (or your MINIO_ROOT_USER)
  • Password: your MINIO_ROOT_PASSWORD

You'll see the MinIO Object Browser — a clean web UI for managing buckets, uploading files, and generating share links.

Step 5: Create a Bucket and Upload Files

Via Web Console:

  1. Click "Create Bucket" → name it backups (or whatever you need)
  2. Click the bucket → "Upload" → select files
  3. Click a file → "Share" for a presigned URL

Via CLI (mc client):

# Install mc (MinIO Client)
wget https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc && sudo mv mc /usr/local/bin/

# Configure alias
mc alias set myminio https://minio.yourdomain.com admin your-password

# Create bucket
mc mb myminio/backups

# Upload a file
mc cp ./important-file.tar.gz myminio/backups/

# List objects
mc ls myminio/backups/

Step 6: Connect Your Applications

MinIO works with any S3-compatible tool. Here are common configurations:

rclone (backup/sync)

rclone config
# Type: s3
# Provider: MinIO
# Endpoint: minio.yourdomain.com
# Access key: admin
# Secret key: your-password

# Sync a directory
rclone sync /local/path myminio:backups

PostgreSQL WAL archiving

# postgresql.conf
archive_mode = on
archive_command = 'wal-g wal-push %p'
# wal-g config uses S3_ENDPOINT=minio.yourdomain.com

Python (boto3)

import boto3

s3 = boto3.client(
    's3',
    endpoint_url='https://minio.yourdomain.com',
    aws_access_key_id='admin',
    aws_secret_access_key='your-password'
)

s3.upload_file('backup.tar.gz', 'backups', 'backup.tar.gz')

Verification Checklist

  • docker compose ps shows both containers as "healthy"
  • ✅ Web console loads at https://minio-console.yourdomain.com
  • ✅ Can create a bucket and upload/download a test file
  • mc ls myminio lists your buckets from CLI
  • ✅ Presigned share links work externally

Production Hardening

Before trusting MinIO with critical data:

  • Use distributed mode: Run 4+ MinIO nodes for erasure coding and redundancy. Single-node MinIO has no built-in replication.
  • Separate disks: Mount dedicated drives at /data. Don't store objects on your OS disk.
  • Enable versioning: mc version enable myminio/backups protects against accidental overwrites.
  • Set lifecycle policies: Auto-delete old files with mc ilm add.
  • Monitor: MinIO exposes Prometheus metrics at /minio/v2/metrics/cluster.
  • Backups: MinIO isn't a backup solution. Replicate to another MinIO or S3 with mc mirror --watch.

Next Steps

Now that you have S3-compatible storage, try:

  • Restic or Borgmatic — encrypted backups to your MinIO
  • Nextcloud — self-hosted Dropbox with MinIO as primary storage
  • Litestream — real-time SQLite replication to S3
  • Velero — Kubernetes cluster backups

MinIO gives you cloud-grade object storage without the cloud bill. Once it's running, every S3-compatible tool in your stack works out of the box — just point it at your domain instead of amazonaws.com.


Running MinIO in production? Share your setup in the comments — erasure coding groups, hardware specs, or integration tricks.

Self-Host Authentik: Your Own Identity Provider in 20 Minutes