📋 Preparando o ambiente
Antes de qualquer docker compose up, confirme que o host tem o que precisa: Docker Engine 24+ e Compose v2. Compose v1 (docker-compose com hífen) está deprecado e não suporta features que o Postiz usa.
Rode os dois comandos abaixo. Se falhar, instale via docs oficiais — nunca via apt install docker.io em distros antigas, vem desatualizado.
# Verificar runtime
docker --version
# Docker version 27.3.1, build ce12230
docker compose version
# Docker Compose version v2.29.7
# Criar diretório de trabalho
mkdir -p ~/postiz && cd ~/postiz
mkdir -p data/postgres data/uploads
touch docker-compose.yml .env .env.example
💡 Dica prática
Adicione seu usuário ao grupo docker (sudo usermod -aG docker $USER) e faça logout. Isso evita ter que escrever sudo antes de cada comando — e impede o reflexo perigoso de rodar containers como root.
Conceitos-chave
Runtime de containers que executa as imagens.
Plugin nativo (docker compose, sem hífen).
Cada serviço roda em seu container com FS e rede isolados.
Rodar up várias vezes converge ao mesmo estado.
📄 Escrevendo o docker-compose.yml
O stack mínimo do Postiz tem três serviços: a aplicação Postiz (Node + Next), o Postgres (persistência de posts/contas) e o Redis (filas BullMQ que disparam o agendamento). Sem o Redis nada agenda; sem o Postgres nada persiste.
Use volumes nomeados (não bind mounts para dados de banco) e uma network interna para que Postgres/Redis nunca fiquem expostos no host.
# ~/postiz/docker-compose.yml
services:
postiz:
image: ghcr.io/gitroomhq/postiz-app:latest
container_name: postiz
restart: unless-stopped
env_file: .env
ports:
- "5000:5000"
volumes:
- postiz-uploads:/uploads
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks: [postiz-net]
postgres:
image: postgres:16-alpine
container_name: postiz-postgres
restart: unless-stopped
environment:
POSTGRES_USER: postiz
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: postiz
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postiz"]
interval: 5s
timeout: 5s
retries: 10
networks: [postiz-net]
redis:
image: redis:7-alpine
container_name: postiz-redis
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
retries: 10
networks: [postiz-net]
volumes:
postgres-data:
postiz-uploads:
networks:
postiz-net:
driver: bridge
⚡ Dica prática
Note o depends_on: condition: service_healthy. Sem isso, o Postiz tenta rodar migrations antes do Postgres aceitar conexão e morre no primeiro boot — o erro mais comum em setup novo.
Conceitos-chave
Cada bloco vira um container independente.
Persistem dados além do ciclo de vida do container.
Bridge interna isola Postgres/Redis do host.
Garante ordem de boot via healthcheck.
🔐 Variáveis de ambiente (.env)
O Postiz lê configuração via variáveis de ambiente — não tem arquivo de config. As essenciais para subir o stack são URLs (backend/frontend), conexões (Postgres/Redis), o JWT_SECRET e, opcionalmente, storage + Resend para e-mails.
# ~/postiz/.env (NUNCA commitar)
# URLs públicas — ajuste se for usar domínio
MAIN_URL=http://localhost:5000
FRONTEND_URL=http://localhost:5000
NEXT_PUBLIC_BACKEND_URL=http://localhost:5000/api
BACKEND_INTERNAL_URL=http://localhost:3000
# Segredo de assinatura JWT — GERE UM NOVO
JWT_SECRET=cole_aqui_o_resultado_de_openssl_rand_hex_64
# Banco e fila (host = nome do serviço no compose)
POSTGRES_PASSWORD=troque_essa_senha_forte
DATABASE_URL=postgresql://postiz:troque_essa_senha_forte@postgres:5432/postiz
REDIS_URL=redis://redis:6379
# Storage (local p/ começar; S3/R2 em prod)
STORAGE_PROVIDER=local
# E-mail transacional (opcional no dev)
RESEND_API_KEY=re_xxx_opcional_no_dev
Gere o JWT_SECRET com entropia real. Nunca invente uma string "parece aleatória" — o segredo assina os tokens de sessão de TODAS as contas conectadas.
# 64 bytes hex = 512 bits de entropia
openssl rand -hex 64
✓ O que FAZER
- ✓Manter
.env.exampleno repo com chaves vazias. - ✓Adicionar
.envao.gitignoreimediatamente. - ✓Usar nomes de serviço (
postgres,redis) como host nas URLs. - ✓Rotacionar
JWT_SECRETse houver suspeita de vazamento.
✗ O que NÃO fazer
- ✗Commitar
.envno git — mesmo "só por um minuto". - ✗Reaproveitar
JWT_SECRETentre projetos. - ✗Apontar
DATABASE_URLparalocalhostdentro do container. - ✗Hardcodar segredos no
docker-compose.yml.
Conceitos-chave
Valores sensíveis nunca no código-fonte.
Config via ambiente, código mesmo entre dev/prod.
Compose injeta as vars no container automaticamente.
Aleatoriedade real, gerada por CSPRNG do SO.
▶️ Primeiro docker compose up
Com o .env preenchido e o docker-compose.yml salvo, o boot inicial é uma sequência de seis passos. Não pule a verificação de logs — é onde aparecem os erros silenciosos de configuração.
Baixar imagens
Pré-baixar evita race entre pull e start no up.
docker compose pull
Subir em background
A flag -d destaca os containers do terminal.
docker compose up -d
Acompanhar boot
No primeiro boot, ver os logs do Postiz é obrigatório — migrations rodam aqui.
docker compose logs -f postiz
Confirmar containers
Os três serviços devem aparecer com status Up e healthcheck healthy.
docker compose ps
Aguardar healthcheck
Postgres leva 5-15s. Redis quase instantâneo. Postiz só sobe depois.
docker compose ps --format "{{.Name}}\t{{.Status}}"
Abrir no browser
Se a tela de signup aparecer, o stack está saudável.
xdg-open http://localhost:5000
⏱️ Dica prática
Use -d para detach, mas sempre acompanhe logs -f postiz no primeiro boot. As migrations do Prisma rolam aqui e qualquer erro de DATABASE_URL aparece nos primeiros 10 segundos.
Conceitos-chave
Containers seguem rodando após fechar o terminal.
Stream do stdout/stderr dos containers.
Sonda que confirma o serviço pronto para tráfego.
5000:5000 expõe a porta do container no host.
🔍 Diagnóstico quando algo dá errado
Quase todo problema de setup do Postiz cai em quatro famílias. Antes de googlar o stack trace, leia os logs — eles dizem qual família é.
📊 Problemas comuns no primeiro boot
- Porta 5000 ocupada: outro serviço já segura a porta. Confirme com
lsof -i :5000e mude o mapeamento para8080:5000. - Postgres não sobe: volume corrompido de boot anterior ou senha trocada.
docker compose logs postgresmostra o motivo exato. - Redis connection refused: a aplicação está num network diferente ou
REDIS_URLaponta paralocalhostem vez deredis. - Permission denied em volume: bind mount com dono errado. Use volume nomeado ou faça
chowncom o UID do container.
# Logs de um serviço específico (últimas 100 linhas)
docker compose logs --tail=100 postiz
# Status detalhado de todos os containers
docker compose ps -a
# Entrar no Postgres para inspecionar
docker exec -it postiz-postgres psql -U postiz -d postiz -c "\dt"
# Testar conexão Redis de dentro do container Postiz
docker exec -it postiz sh -c "nc -zv redis 6379"
# Reset completo (APAGA volumes — só em dev!)
docker compose down -v
✓ O que FAZER
- ✓Ler os logs SEMPRE antes de googlar o erro.
- ✓Usar
down -vpara reset completo em dev. - ✓Conferir
docker compose configpara ver o YAML resolvido. - ✓Isolar o problema: subir Postgres sozinho, depois Redis, depois Postiz.
✗ O que NÃO fazer
- ✗Apagar volumes em produção sem backup recente.
- ✗Rodar containers como root (
user: root). - ✗"Restart até funcionar" sem ler nenhuma linha de log.
- ✗Editar
.enve esquecer deup -dde novo.
Conceitos-chave
Stdout/stderr do processo principal do container.
Roda um comando dentro de um container ativo.
0 ok; 1+ erro; 137 = OOM kill.
Isolar variáveis, reproduzir, ler logs, hipótese.
✅ Verificando que subiu
"Container Up" não é o mesmo que "aplicação funciona". Faça um smoke test de seis pontos antes de declarar vitória.
Browser em http://localhost:5000
A página deve carregar — não um erro de conexão recusada, não um 502, não branco.
Tela de signup aparece
Sem ela, o frontend não conseguiu falar com o backend — confirme NEXT_PUBLIC_BACKEND_URL.
Criar conta admin
O primeiro usuário cadastrado vira admin. Se o POST falhar, o problema é Postgres (escrita).
Login funciona
Token JWT é gerado e persistido em cookie. Sessão deve sobreviver a F5.
UI carrega completa
Dashboard sem ícones quebrados e sem chamadas 500 no DevTools / Network.
Endpoint de health
Resposta 200 OK indica que app + DB + Redis estão saudáveis.
# Smoke test rápido via CLI
curl -i http://localhost:5000/api/health
# HTTP/1.1 200 OK
# {"status":"ok","db":"up","redis":"up"}
💾 Dica prática
Configure backup do volume postgres-data ANTES de adicionar contas reais de redes sociais. Os tokens OAuth ficam ali e regenerá-los é trabalhoso. docker run --rm -v postiz_postgres-data:/data -v $(pwd):/backup alpine tar czf /backup/pg-$(date +%F).tar.gz /data.
Conceitos-chave
Verificação rápida de que o sistema sobe e responde.
Endpoint que reporta saúde de dependências.
Conta admin inicial — proteja com senha forte.
Domínio, HTTPS, backup, primeira integração.
🎯 Resumo do Módulo
~/postiz criado.openssl rand, secrets fora do git.pull, up -d, logs acompanhados e containers healthy./api/health respondendo 200.Próximo Módulo:
2.3 — Configuração inicial e primeira conta conectada