Minio S3 – Guia rápido

Saudações.

Esse tutorial é um guia rápido de instalação e uso do Minio.

O Minio é um software de gerenciamento de arquivos com suporte a uma quantidade muito grande de recursos, sendo seu principal recurso o suporte a API no padrão S3.

Pré-requisitos (constam em outros artigos aqui do blog):

  • Instalação do Linux (Debian);
  • Internet no servidor (sua VPS ou host);
  • Docker CE instalado;

1 – Preparando o Docker

Vamos preparar o ambiente docker com a rede (network_public).

Escolha uma das 3 formas:

  • Seção 1.1: rede com endereçamento automático e MTU 1500;
  • Seção 1.2: rede com endereçamento IPv4 manual e MTU 65495;
  • Seção 1.3: rede com endereço IPv4+IPv6 manual e MTU 65495;

1.1 – Docker Network com endereçamento automático

Bash
docker network create \
    -d bridge \
    \
    -o "com.docker.network.bridge.name"="br-net-public" \
    -o "com.docker.network.bridge.enable_icc"="true" \
    -o "com.docker.network.driver.mtu"="65495" \
    \
    --subnet 10.249.0.0/16 --gateway 10.249.255.254 \
    \
    network_public;

1.2 – Docker Network IPv4

Bash
docker network create \
    -d bridge \
    \
    -o "com.docker.network.bridge.name"="br-net-public" \
    -o "com.docker.network.bridge.enable_icc"="true" \
    -o "com.docker.network.driver.mtu"="65495" \
    \
    --subnet 10.249.0.0/16 --gateway 10.249.255.254 \
    \
    network_public;

1.3 – Docker Network Dual Stack (IPv4 + IPv6)

Bash
docker network create \
    -d bridge \
    \
    -o "com.docker.network.bridge.name"="br-net-public" \
    -o "com.docker.network.bridge.enable_icc"="true" \
    -o "com.docker.network.driver.mtu"="65495" \
    \
    --subnet 10.249.0.0/16 --gateway 10.249.255.254 \
    --ipv6 \
    --subnet=2001:db8:10:249::/64 \
    --gateway=2001:db8:10:249::ffff \
    \
    network_public;

2 – Container do Traefik

Vou usar a execução padrão do container Traefik. O container do Traefik se chamará “traefik-app“.

2.1 – Email do contato LetsEncrypt

Personalize a variável EMAIL para que o LetsEncrypt funcione corretamente. Vou salvar o email de contato no arquivo /etc/email do host:

Bash
# Email de registro no letsencrypt
EMAIL="voce@seudominio.com.br";

# Gravar no arquivo para consulta
echo "$EMAIL" > /etc/email;

2.2 – Traefik

Rodando o Traefik:

Bash
#!/bin/sh

# Variaveis
  # - Nome do container
  NAME=traefik-app;
  
  # - Imagem do software traefik
  IMAGE=traefik:latest;
  
  # - Email de registro no letsencrypt
  EMAIL=$(head -1 /etc/email);

  # - Diretorio do volume (dados persistentes)
  DATADIR=/storage/$NAME;

# Preparar volume:
  mkdir -p $DATADIR/letsencrypt;
  mkdir -p $DATADIR/logs;
  mkdir -p $DATADIR/config;

# Obter imagem atualizada:
  docker pull $IMAGE;

# Remover instância atual:
  docker rm -f $NAME 2>/dev/null;

# Renovar/criar/rodar:
docker run \
    -d --restart=unless-stopped --name $NAME -h $NAME.intranet.br \
    \
    --network network_public \
    \
    -p 80:80 \
    -p 443:443 \
    \
    -v /var/run/docker.sock:/var/run/docker.sock:ro \
    -v $DATADIR/letsencrypt:/etc/letsencrypt \
    -v $DATADIR/config:/etc/traefik \
    -v $DATADIR/logs:/logs \
    \
    --tmpfs /run:rw,noexec,nosuid,size=16m \
    --tmpfs /tmp:rw,noexec,nosuid,size=16m \
    --read-only \
    \
    $IMAGE \
      \
      --global.checkNewVersion=false \
      --global.sendAnonymousUsage=false \
      \
      --api.insecure=true \
      \
      --log.level=INFO \
      --log.filePath=/logs/error.log \
      \
      --accessLog.filePath=/logs/access.log \
      \
      --entrypoints.web.address=:80 \
      --entrypoints.web.http.redirections.entryPoint.to=websecure \
      --entrypoints.web.http.redirections.entryPoint.scheme=https \
      --entrypoints.web.http.redirections.entryPoint.permanent=true \
      \
      --entrypoints.websecure.address=:443 \
      \
      --providers.docker=true \
      --providers.file.directory=/etc/traefik \
      \
      --certificatesresolvers.letsencrypt.acme.email=$EMAIL \
      --certificatesresolvers.letsencrypt.acme.storage=/etc/letsencrypt/acme.json \
      --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web;

3 – Implementando Minio no Docker

Escolha uma das formas de rodar:

  • Seção 3.1: Minio simples, sem proxy reverso Traefik, porta de administração web com acesso direto via HTTP, bom para implementações rápidas;
  • Seção 3.2: Minio com Traefik, acesso HTTPs auto-provisionado pelo LetsEncrypt;

3.1 – Minio simples

Essa é a forma de rodar o Minio sem depender de um proxy reverso.

Será necessário informar o endereço de DNS principal da sua VPS ou o IP dela nas variáveis:

  • URL_API (API de serviço S3, porta e 9000);
  • URL_CONSOLE (administração, porta e 9001);

Script:

Bash
# Variaveis
    # - Nome do container
    NAME="minio";
    
    # Login administrativo inicial:
    MINIO_ROOT_USER="admin";
    MINIO_ROOT_PASSWORD="Sua_SenhaForte@";

    # URLs de acesso sem proxy reverso (HTTP puro)
    URL_API="http://$(hostname -f):9000";
    URL_CONSOLE="http://$(hostname -f):9001";
    #-URL_API="http://vps.seudominio.com.br:9000";
    #-URL_CONSOLE="http://vps.seudominio.com.br:9001";

    # Obter imagem do software do container:
    IMAGE="quay.io/minio/minio:RELEASE.2025-04-22T22-12-26Z";

    # - Pasta do volume
    DATADIR=/storage/minio;

# Criar pasta do volume
    mkdir -p $DATADIR;

# Baixar imagem atualizada
    docker pull $IMAGE;

# Parar container atual:
    docker rm -f $NAME 2>/dev/null;

# Criar e rodar:
    docker run -d --restart=always \
        --name $NAME --hostname $NAME.intranet.br \
        \
        --cpus=2.0 \
        --memory=2g --memory-swap=2g \
        \
        --tmpfs /run:rw,noexec,nosuid,size=32m \
        --tmpfs /tmp:rw,noexec,nosuid,size=32m \
        \
        --network network_public \
        \
        -p 9000:9000 \
        -p 9001:9001 \
        \
        -e TZ=America/Sao_Paulo \
        -e "MINIO_ROOT_USER=$MINIO_ROOT_USER" \
        -e "MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD" \
        -e "MINIO_SERVER_URL=$URL_WEB" \
        -e "MINIO_BROWSER_REDIRECT_URL=$URL_CONSOLE" \
        \
        -v $DATADIR:/data \
        \
        --health-cmd="mc ready local" \
        --health-interval=15s \
        --health-timeout=10s \
        --health-retries=5 \
        \
        $IMAGE server /data --console-address ":9001";

# Enderecos para acesso:
    echo;
    echo "Acesso:";
    echo;
    echo "API S3................: $URL_API";
    echo "Console/administracao.: $URL_CONSOLE";
    echo;

3.2 – Minio e Traefik

O Minio tem dois endereços para acesso:

  • s3.seudominio.com.br: endereço oficial para uso na API S3;
  • minio.seudominio.com.br: endereço de administração;

Troque esses nomes pelos nomes que você configurou no DNS para esses dois endereços.

Bash
# Variaveis
    # - Nome do container
    NAME="minio";

    # - Nome de DNS para acesso ao servico
    FQDN_WEB="s3.seudominio.com.br";
    
    # - Nome de DNS para acesso administrativo
    FQDN_CONSOLE="minio.seudominio.com.br";

    # Login administrativo inicial:
    MINIO_ROOT_USER="admin";
    MINIO_ROOT_PASSWORD="Sua_SenhaForte@";

    # Obter imagem do software do container:
    IMAGE="quay.io/minio/minio:RELEASE.2025-04-22T22-12-26Z";

    # - Pasta do volume
    DATADIR=/storage/minio;

# Criar pasta do volume
    mkdir -p $DATADIR;

# Baixar imagem atualizada
    docker pull $IMAGE;

# Parar container atual:
    docker rm -f $NAME 2>/dev/null;

# Criar e rodar:
    docker run -d --restart=always \
        --name $NAME --hostname $NAME.intranet.br \
        \
        --cpus=2.0 \
        --memory=2g --memory-swap=2g \
        \
        --tmpfs /run:rw,noexec,nosuid,size=32m \
        --tmpfs /tmp:rw,noexec,nosuid,size=32m \
        \
        --network network_public \
        \
        -p 9000:9000 \
        -p 9001:9001 \
        \
        -e TZ=America/Sao_Paulo \
        -e "MINIO_ROOT_USER=$MINIO_ROOT_USER" \
        -e "MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD" \
        -e "MINIO_BROWSER_REDIRECT_URL=https://$FQDN_CONSOLE" \
        -e "MINIO_SERVER_URL=https://$FQDN_WEB" \
        \
        -v $DATADIR:/data \
        \
        --label "traefik.enable=true" \
        --label "traefik.http.routers.${NAME}w.rule=Host(\`$FQDN_WEB\`)" \
        --label "traefik.http.routers.${NAME}w.entrypoints=web,websecure" \
        --label "traefik.http.routers.${NAME}w.tls=true" \
        --label "traefik.http.routers.${NAME}w.tls.certresolver=letsencrypt" \
        --label "traefik.http.routers.${NAME}w.service=${NAME}w" \
        --label "traefik.http.services.${NAME}w.loadbalancer.passHostHeader=true" \
        --label "traefik.http.services.${NAME}w.loadbalancer.server.port=9000" \
        \
        --label "traefik.http.routers.${NAME}c.rule=Host(\`$FQDN_CONSOLE\`)" \
        --label "traefik.http.routers.${NAME}c.entrypoints=web,websecure" \
        --label "traefik.http.routers.${NAME}c.tls=true" \
        --label "traefik.http.routers.${NAME}c.tls.certresolver=letsencrypt" \
        --label "traefik.http.routers.${NAME}c.service=${NAME}c" \
        --label "traefik.http.services.${NAME}c.loadbalancer.server.port=9001" \
        --label "traefik.http.services.${NAME}c.loadbalancer.passHostHeader=true" \
        \
        --health-cmd="mc ready local" \
        --health-interval=15s \
        --health-timeout=10s \
        --health-retries=5 \
        \
        $IMAGE server /data --console-address ":9001";

# Enderecos para acesso:
    echo;
    echo "Acesso:";
    echo;
    echo "API HTTP direto.....: http://$FQDN_WEB:9000";
    echo "API HTTPs...........: https://$FQDN_WEB";
    echo;
    echo "Console HTTP direto.: http://$FQDN_WEB:9001";
    echo "Console HTTPs.......: https://$FQDN_CONSOLE";
    echo;

3.3 – Primeiro contato

Primeiros ajustes para operar o Minio:

Bash
# Entrar no container do Minio:
docker exec -it minio bash;

# Configurar o alias de conexão local
# Antes de qualquer operação, configure o alias apontando para a instância local:
mc  alias  set  local  http://localhost:9000 "admin" "Sua_SenhaForte@";
    # mc: Configuration written to `/tmp/.mc/config.json`.
    #     Please update your access credentials.
    # mc: Successfully created `/tmp/.mc/share`.
    # mc: Initialized share uploads `/tmp/.mc/share/uploads.json` file.
    # mc: Initialized share downloads `/tmp/.mc/share/downloads.json` file.
    # Added `local` successfully.

# Verificar se a conexão está funcionando:
mc  admin  info local;
    # ●  localhost:9000
    #    Uptime: 10 minutes 
    #    Version: 2025-04-22T22:12:26Z
    #    Network: 1/1 OK 
    #    Drives: 1/1 OK 
    #    Pool: 1
    # ┌──────┬───────────────────────┬─────────────────────┬──────────────┐
    # │ Pool │ Drives Usage          │ Erasure stripe size │ Erasure sets │
    # │ 1st  │ 14.4% (total: 15 GiB) │ 1                   │ 1            │
    # └──────┴───────────────────────┴─────────────────────┴──────────────┘
    # 1 drive online, 0 drives offline, EC:0

Alterar senha de administração (usuário admin):

Bash
# Entrar no container do Minio:
docker exec -it minio bash;

# Alterar senha de admin
mc admin user change-password local "admin" "NovaSenhaForte@";

# Atualize o alias depois de trocar a senha:
mc alias set local http://localhost:9000 "admin" "NovaSenhaForte@";

3.6 – Primeiro acesso web

O Minio pode ser totalmente administrado pela interface web.

Acesse pelo navegador na porta HTTP 9001 ou pelo nome de DNS vinculado ao serviço de console.

Gerencia web:

Tela de login

Após logar, a interface web permite controle total sobre logins, chaves de autenticação na API e buckets (unidades de armazenamento) e seus privilégios.

CONSOLE Minio – Tela inicial da administração web

4 – Comandos básicos de terminal

Esse capítulo aborda as operações de administração do Minio pelo terminal.

Se você estiver no terminal do servidor utilize sempre “docker exec“.
Se estiver no shell dentro do container inicie os comandos em “mc …“.

Para entrar no terminal do container minio, execute:

Bash
# Entrar no shell do container minio:
docker exec -it minio bash;

4.1 – Gestão de usuários

Comandos para administração de contas administrativas para gestão do Minio pela interface Console.

Bash
# Criar usuários
mc admin user add local "suporte" "Tulipa@2026";

# Listar usuários existentes:
mc admin user list local;

# Atribuir política ao usuário
# Sem uma política, o usuário não tem acesso a nada.
# As políticas padrão disponíveis são:
# * readwrite - leitura e escrita em todos os buckets
# * readonly - somente leitura
# * writeonly - somente escrita
# * consoleAdmin - acesso administrativo pelo console web
# * diagnostics

# Atribuir política:
mc admin policy attach local readwrite --user "suporte";
    # Attached Policies: [readwrite]
    # To User: suporte

4.2 – Gestão de buckets

Bash
# Criar novo bucket
mc mb "local/notas-fiscais";

# Listar buckets:
mc ls local;

4.3 – Gestão de Chaves de acesso

Chaves de acesso são necessárias para conectar sistemas que precisam salvar e recuperar arquivos usando o padrão S3.

Bash
# Criar chaves de acesso (Access Keys) para uso na API S3
# As chaves de acesso são vinculadas a um usuário existente.
# Para criar chaves para um usuário específico, você precisa estar autenticado como esse usuário ou como admin.

# Como admin, criando chaves para outro usuário:
mc admin accesskey create local suporte;
    # Access Key: VBKBBB1FGGAMYO5103RR
    # Secret Key: 3PZuLiFKGq56ideYwD2aI3XtDgKz3cKVS2iihYbA
    # Expiration: NONE
    # Name: 
    # Description: 

# A saída retorna o Access Key e o Secret Key.
# Guarde o Secret Key pois não é exibido novamente.
# Listar chaves de um usuário:
mc admin accesskey list local user suporte;
    # User: suporte
    #   Access Keys:
    #     VBKBBB1FGGAMYO5103RR, expires: never, sts: false

# Revogar uma chave, exemplo com chave acima:
mc admin accesskey remove local VBKBBB1FGGAMYO5103RR;

Toda dor pode ser suportada se sobre ela puder ser contada uma história.
Hannah Arendt

Terminamos por hoje!

Patrick Brandão, patrickbrandao@gmail.com