Skip to content
AImpact
IT EN
AI infrastructure 6 min read

MinIO: self-hosted S3-compatible storage for developers and businesses

MinIO is an object storage service compatible with Amazon S3 APIs, but runs on your own server. Docker setup in 5 minutes, bucket policies, Python/FastAPI integration, backup and AI RAG.

Published: June 3, 2025

If you use AWS S3 for file storage, you can replicate the exact same interface on your own server with MinIO. Boto3, S3 SDKs in any language, AWS CLI clients — they all work without code changes. You only change the endpoint. Cost: zero.

Docker setup in 5 minutes

A minimal docker-compose.yml to get MinIO running with a web console:

services:
  minio:
    image: minio/minio:latest
    command: server /data --console-address ":9001"
    environment:
      - MINIO_ROOT_USER=admin
      - MINIO_ROOT_PASSWORD=password123
    volumes:
      - minio_data:/data
    ports:
      - "9000:9000"   # S3 API
      - "9001:9001"   # Web console
    restart: unless-stopped

volumes:
  minio_data:

docker compose up -d, then open http://localhost:9001, log in with admin/password123, and create a bucket. The S3 API is available on localhost:9000. In production, change the password and put Caddy in front for HTTPS.

Three real use cases

Automated backups from Python scripts. You have a script that generates reports or CSV exports. Instead of saving to the filesystem, send them to MinIO with boto3:

import boto3

s3 = boto3.client(
    's3',
    endpoint_url='http://localhost:9000',
    aws_access_key_id='admin',
    aws_secret_access_key='password123'
)

s3.upload_file('report.pdf', 'backups', 'reports/2025-06-03/report.pdf')

# Download
s3.download_file('backups', 'reports/2025-06-03/report.pdf', 'local_copy.pdf')

The code works identically on real AWS S3 — only endpoint_url changes. Zero lock-in.

File uploads in a FastAPI app. A multipart endpoint that receives a file and saves it to MinIO:

from fastapi import FastAPI, UploadFile
import boto3

app = FastAPI()
s3 = boto3.client('s3', endpoint_url='http://minio:9000',
                  aws_access_key_id='admin', aws_secret_access_key='password123')

@app.post("/upload")
async def upload(file: UploadFile):
    s3.upload_fileobj(file.file, 'uploads', file.filename)
    return {"key": file.filename}

Files live on MinIO, the app holds nothing locally, and you can scale to multiple FastAPI instances without state conflicts.

Document source for AI RAG. Open WebUI connects to MinIO via its S3 settings (see the self-hosted AI stack guide). Upload company documents to the bucket, Open WebUI indexes them, and the local model can answer questions about their content. Everything stays on your local network.

Bucket policies: public vs private

For buckets with publicly accessible static assets (images, CSS, fonts), set the policy from the console or via CLI:

mc alias set local http://localhost:9000 admin password123
mc anonymous set public local/static-assets

For buckets with company documents, keep the private policy (default) and generate pre-signed URLs with expiration for temporary sharing:

url = s3.generate_presigned_url(
    'get_object',
    Params={'Bucket': 'documents', 'Key': 'contract.pdf'},
    ExpiresIn=3600  # URL valid for 1 hour
)

The URL works without authentication for 3600 seconds, then expires. Useful for sending links to clients or colleagues without exposing the bucket.

What to do

  • Start MinIO with docker compose up -d, create a test bucket from the console at localhost:9001, and do an upload/download with boto3 using endpoint_url='http://localhost:9000' to verify everything works
  • Replace filesystem saving in at least one existing Python script with a MinIO upload — you’ll immediately see the advantage when accessing files from multiple machines
  • If you use Open WebUI, connect the MinIO bucket as S3 storage in the settings and upload 3–4 company PDFs to test RAG on real documents