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:
EOFKey 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
}
EOFReplace 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.htmlStep 4: Access the Web Console
Open https://minio-console.yourdomain.com in your browser. Log in with:
- Username:
admin(or yourMINIO_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:
- Click "Create Bucket" → name it
backups(or whatever you need) - Click the bucket → "Upload" → select files
- 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:backupsPostgreSQL WAL archiving
# postgresql.conf
archive_mode = on
archive_command = 'wal-g wal-push %p'
# wal-g config uses S3_ENDPOINT=minio.yourdomain.comPython (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 psshows 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 myminiolists 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/backupsprotects 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.