MinIO self-hosted na VPS

MinIO é o storage de objetos S3-compatível open-source mais rápido do mundo, substitui o Amazon S3 para arquivos, backups e assets da aplicação rodando inteiramente na sua VPS. Com a mesma API do S3, você troca apenas o endpoint e continua usando o AWS SDK sem mudar código.

Instalar MinIO com Docker Compose

Stack completa com MinIO e configuração de produção:

yaml
# docker-compose.yml
services:
  minio:
    image: minio/minio:latest
    restart: always
    command: server /data --console-address ":9001"
    ports:
      - "127.0.0.1:9000:9000"   # API S3
      - "127.0.0.1:9001:9001"   # Console web
    environment:
      MINIO_ROOT_USER: ${MINIO_ROOT_USER}
      MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD}
      MINIO_BROWSER_REDIRECT_URL: https://minio-console.seudominio.com.br
    volumes:
      - minio_data:/data
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 30s
      timeout: 20s
      retries: 3

volumes:
  minio_data:

Configurar Nginx para API e Console

Dois virtual hosts: um para a API S3 e outro para o console web:

nginx
# /etc/nginx/conf.d/minio.conf

# API S3 (para as aplicações)
server {
    listen 443 ssl http2;
    server_name s3.seudominio.com.br;

    ssl_certificate     /etc/letsencrypt/live/s3.seudominio.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/s3.seudominio.com.br/privkey.pem;

    ignore_invalid_headers off;
    client_max_body_size 0;         # sem limite de tamanho
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_http_version 1.1;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 300s;
        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
        chunked_transfer_encoding off;
    }
}

# Console web (restrito por IP)
server {
    listen 443 ssl http2;
    server_name minio-console.seudominio.com.br;

    ssl_certificate     /etc/letsencrypt/live/minio-console.seudominio.com.br/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/minio-console.seudominio.com.br/privkey.pem;

    allow 177.10.0.1;
    deny all;

    location / {
        proxy_pass http://127.0.0.1:9001;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;
    }
}

Criar buckets e políticas via mc (MinIO Client)

CLI do MinIO para gerenciar buckets e permissões:

bash
# Instalar mc (MinIO Client)
curl -O https://dl.min.io/client/mc/release/linux-amd64/mc
chmod +x mc
sudo mv mc /usr/local/bin/

# Configurar alias para o servidor
mc alias set myminio https://s3.seudominio.com.br \
  SEU_ROOT_USER SEU_ROOT_PASSWORD

# Verificar conexão
mc ready myminio

# Criar buckets
mc mb myminio/uploads         # uploads de usuários
mc mb myminio/backups         # backups de banco de dados
mc mb myminio/assets          # assets públicos

# Tornar bucket público (para assets estáticos acessíveis sem autenticação):
mc anonymous set public myminio/assets

# Criar usuário específico para a aplicação (menor privilégio):
mc admin user add myminio app_user senha_app_user
mc admin policy attach myminio readwrite --user app_user

# Listar buckets e objetos:
mc ls myminio
mc ls myminio/uploads/

Integrar com Node.js (AWS SDK)

Usar o MinIO como drop-in replacement do S3 na aplicação:

typescript
// Node.js — usando AWS SDK v3 com MinIO
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3'
import { getSignedUrl } from '@aws-sdk/s3-request-presigner'

const s3 = new S3Client({
  endpoint: 'https://s3.seudominio.com.br',  // URL do MinIO
  region: 'us-east-1',                        // qualquer valor
  credentials: {
    accessKeyId: process.env.MINIO_ACCESS_KEY!,
    secretAccessKey: process.env.MINIO_SECRET_KEY!,
  },
  forcePathStyle: true,    // OBRIGATÓRIO para MinIO
})

// Upload de arquivo
async function uploadFile(key: string, body: Buffer, contentType: string) {
  await s3.send(new PutObjectCommand({
    Bucket: 'uploads',
    Key: key,
    Body: body,
    ContentType: contentType,
  }))
  return `https://s3.seudominio.com.br/uploads/${key}`
}

// URL pré-assinada para download temporário (1 hora)
async function getPresignedUrl(key: string) {
  return getSignedUrl(s3, new GetObjectCommand({
    Bucket: 'uploads',
    Key: key,
  }), { expiresIn: 3600 })
}

Backup e monitoramento do MinIO

Monitorar uso de storage e configurar replicação de bucket:

bash
# Ver uso de storage por bucket:
mc du myminio/uploads
mc du myminio/backups

# Replicação para outro MinIO ou S3 (DR):
mc replicate add myminio/backups \
  --remote-bucket s3://meu-bucket-aws/backups \
  --arn "arn:minio:replication::..." \
  --priority 1

# Lifecycle policy — deletar objetos antigos automaticamente:
mc ilm rule add myminio/backups \
  --expiry-days 30              # deletar após 30 dias

# Backup do volume MinIO com rsync para armazenamento externo:
rsync -av --progress /var/lib/docker/volumes/minio_data/_data/ \
  usuario@backup-server:/backups/minio/

# Métricas com Prometheus:
mc admin prometheus generate myminio
# Adicionar o scrape config gerado ao prometheus.yml

Não quer configurar manualmente?

Implante o MinIO em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

S3: sem servidor para gerenciar, 99.999999999% de durabilidade, escala infinita, mas custo por GB e por request. MinIO self-hosted: custo fixo da VPS, dados na sua infraestrutura, mesma API do S3. Use MinIO quando: dados sensíveis não podem sair da sua infra, volume alto de requests tornaria S3 caro, ou você quer eliminar dependência de cloud provider.

Sim, é um dos casos de uso mais comuns. Configure o script de pg_dump para fazer upload ao MinIO via mc cp ou AWS SDK em vez de S3. Vantagem: backup local na VPS + cópia no MinIO = dois locais sem depender de serviço externo. Para redundância real: configure replicação do bucket MinIO para S3 ou B2.

MinIO não tem limite prático de objetos, o limite é o espaço em disco da VPS. Para VPS com SSD de 500 GB: suporta dezenas de milhões de arquivos pequenos ou terabytes de arquivos grandes. Para objetos muito pequenos (< 1 MB): considere agrupa-los ou usar Redis/banco de dados em vez de object storage.

Duas opções: (1) Tornar o bucket público (mc anonymous set public myminio/assets), qualquer um pode acessar. (2) URL pré-assinada, URL temporária com token que expira. Para assets públicos (imagens, CSS): bucket público. Para arquivos de usuários: sempre URL pré-assinada com expiração curta.

Sim, mc version enable myminio/meu-bucket habilita versionamento. Cada PUT cria uma nova versão; versões antigas ficam acessíveis. Útil para backups (manter histórico de versões do banco de dados) e para evitar deleção acidental. Configure lifecycle policy para deletar versões antigas automaticamente e controlar o uso de disco.