infra-shelf: um estoque de bancos e filas pro homelab
Todo app novo que eu subo no homelab acaba pedindo a mesma coisa: um banco, às vezes uma fila, de preferência já provisionados antes do primeiro docker compose up. Quando rodei o litellm, precisei de Postgres. O Infisical quis Postgres e Redis. Outros projetos pediram RabbitMQ ou MongoDB. O padrão preguiçoso é cada projeto subir seu próprio Postgres + Redis no compose dele — e aí, três projetos depois, você tem três Postgres, dois Redis, conflito de porta toda hora, zero isolamento de verdade e backup espalhado em pasta que ninguém lembra.
Foi pra matar essa dor que escrevi o infra-shelf, hoje aberto no GitHub: https://github.com/IvanMicai/infra-shelf.
A ideia: uma prateleira compartilhada
Em vez de cada app trazer seu próprio banco, eu rodo uma instância de cada coisa numa rede Docker privada (infra-shelf), e cada aplicativo ganha uma credencial isolada dentro dela. Nada de entregar o superusuário pra um app qualquer.
A separação por app acontece dentro de cada serviço:
| Serviço | Endereço na rede | Isolamento por app |
|---|---|---|
| PostgreSQL | postgres:5432 | database + user dedicados |
| Redis | redis:6379 | usuário ACL + prefixo de chave |
| RabbitMQ | rabbitmq:5672 | vhost + user dedicados |
| MongoDB | mongodb:27017 | database + user dedicados |
| S3 (MinIO) | aistor:9000 | bucket + access key (opt-in) |
| SignOz | signoz-otel-collector:4317 | service.name próprio (opt-in) |
O Postgres, o Redis, o RabbitMQ e o Mongo sobem com um make up. S3 e SignOz são overlays opcionais. Tudo na mesma rede, então seus apps conectam por nome de host (postgres, redis…) sem expor porta pra fora.
Como eu uso — o CLI shelf
O coração é um binário Go único, o shelf. Provisionar um app é uma linha:
shelf setup myapp -s postgres,redis,rabbitmq,mongodb
Ele gera uma senha aleatória por serviço, roda os comandos de admin dentro dos containers (psql, redis-cli, rabbitmqctl, mongosh), grava tudo num registry e cospe um bloco .env pronto pra colar no projeto:
# === PostgreSQL ===
DATABASE_URL=postgres://myapp:QzLiMENvUupGDz@postgres:5432/myapp
DB_HOST=postgres
DB_NAME=myapp
# === Redis ===
REDIS_URL=redis://myapp:keS6texnNfjnGr@redis:6379/0
REDIS_PREFIX=myapp:
# === RabbitMQ ===
AMQP_URL=amqp://myapp:j3XwLUjuRrEP11@rabbitmq:5672/myapp
RABBITMQ_VHOST=myapp
# === MongoDB ===
MONGODB_URL=mongodb://myapp:C0jbw2HqXVkuFs@mongodb:27017/myapp?authSource=myapp
MONGODB_DATABASE=myapp
A partir daí o dia a dia é só mais alguns comandos:
shelf credentials myapp # reimprime o .env quando eu perco
shelf add myapp -s signoz # pluga um serviço a mais num app existente
shelf list # mostra todos os apps provisionados
shelf status # saúde dos containers de infra
Tem também uma UI web (shelf-web), e o detalhe importante é que ela não chama o CLI por baixo: as duas pontas importam a mesma biblioteca Go (internal/shelfcore) e chamam as mesmas funções. CLI e web fazem exatamente a mesma coisa, sem parsing de stdout no meio.
A tela de criação de apps
Quando eu não tô a fim de terminal, a UI web faz o mesmo provisionamento por formulário. A tela /apps tem o campo do nome do app (padrão [a-z][a-z0-9-]*), um campo opcional de environments (pra expandir em staging/production), checkboxes dos serviços e um botão Provision. Provisionado, dá pra revelar as credenciais e baixar o .env direto pela interface.

Roda em http://127.0.0.1:8080 com Basic Auth, é HTML renderizado no servidor (sem framework de frontend, SQLite puro-Go por baixo) e é o jeito que eu mais uso quando vou criar um app novo no fim de semana.
Backup — a rede de segurança
Talvez a parte que mais me dá paz. Consolidar tudo numa prateleira só também consolida o backup: é uma estratégia em vez de seis pastas perdidas.
shelf backup myapp # um app, todos os serviços dele
shelf backup --all # todos os apps provisionados
shelf restore myapp # restaura do backup mais recente
Cada serviço é salvo do jeito certo pra ele:
| Serviço | Método |
|---|---|
| PostgreSQL | pg_dump --clean --if-exists |
| Redis | snapshot das chaves do app (<app>:*) |
| RabbitMQ | export de definitions (vhost/users/policies) |
| MongoDB | mongodump do database do app |
E dá pra agendar com retenção, que é como eu deixo rodando:
shelf schedule create myapp --cron "0 3 * * *" -z UTC --retention-days 14
Backup diário às 3h, guardando 14 dias. Em caso de catástrofe — pool que corrompe, volume que some — eu tenho de onde voltar. O registry com os secrets ainda pode ser cifrado em repouso (AES-256-GCM, via INFRA_SHELF_SECRET), então o arquivo de credenciais não fica em texto puro no disco.
”E a performance?”
A pergunta óbvia ao consolidar é se juntar tudo numa instância não piora as coisas. Na prática do homelab, não — e o motivo é meio bobo: aqueles seis containers já rodavam todos no mesmo hardware, competindo pelos mesmos CPU e I/O. Consolidar não criou disputa nova; ela já existia. O que mudou foi cortar o overhead de processo duplicado — cada instância de Postgres carrega seu próprio shared buffer, background workers e processos de WAL, e isso some quando vira uma instância só com vários databases.
| Container por projeto | Instância compartilhada | |
|---|---|---|
| Nº de containers de banco | 1 por app (cresce sempre) | 1 por serviço (fixo) |
| Memória (overhead duplicado) | alto | baixo |
| Isolamento | container | database/user + ACL |
| Backup | espalhado | centralizado |
| Conflito de porta | comum | nenhum (rede interna) |
Tem número concreto pra isso: num caso de consolidação de Postgres no homelab, a memória caiu de ~3.2 GB em seis containers para ~1.8 GB numa instância única (DiyMediaServer). Bate com o que eu vi aqui: menos containers, mesma sensação de uso.
Sendo honesto sobre o trade-off: consolidar faz sentido pra cargas modestas, que é o caso de quase todo homelab. Se algum app tiver escrita pesada de verdade, exigência de isolamento estrito ou precisar de uma versão diferente do banco, aí sim vale uma instância dedicada pra ele. Pro resto, a prateleira compartilhada ganha de longe em simplicidade.
Como subir
Instalação em um comando:
curl -fsSL https://raw.githubusercontent.com/IvanMicai/infra-shelf/main/scripts/install.sh | bash
O script confere os pré-requisitos (git, docker, compose v2), clona o repo, cria o .env, builda os dois binários (usa Go local se tiver, senão builda dentro de um container) e sobe a stack core. Depois:
cd ./infra-shelf
# 1. trocar as senhas padrão no .env
# 2. shelf setup myapp -s postgres,redis,rabbitmq,mongodb
# 3. make app → http://127.0.0.1:8080
E pra quem usa Claude Code: o projeto traz uma skill (infra-shelf-install) que automatiza o install e ainda conecta o seu projeto à rede infra-shelf — ela verifica os pré-requisitos, troca as senhas padrão, provisiona o primeiro app e ajusta o compose do seu projeto pra entrar na rede externa.
Fechamento
Tá aberto no GitHub sob MIT: https://github.com/IvanMicai/infra-shelf. Se você também junta projeto self-hosted no homelab e tá cansado de subir um Postgres por app, dá pra trocar essa bagunça por uma prateleira só num fim de semana.
Se curte esse tipo de coisa, tem mais homelab por aqui — o pipeline de upscaling de anime e as 24 horas resgatando meu TrueNAS. Ideias, issues e PRs são bem-vindos. 🦥