Nesta aula vamos instalar o Chatwoot v4.13.0 do zero na sua VPS, usando Portainer, Docker Swarm e Traefik, com banco de dados isolado no PostgreSQL, cache dedicado no Redis e envio de e-mails via SMTP. Diferente de tutoriais genéricos, aqui cada passo existe para evitar que o Sidekiq fique preso em fila ou que o primeiro acesso trave por falta de usuário administrador. Siga estritamente na ordem.
Pré-requisitos
Antes de começar, seu ambiente já precisa ter rodando:
- Portainer (gerenciador do Docker Swarm).
- Traefik (proxy reverso, com rede
traefik_publice resolver de SSLleconfigurado). - PostgreSQL (acessível na rede
digital_networkpelo hostnamepostgres). - Redis (acessível na rede
digital_networkpelo hostnameredis). - Servidor SMTP configurado (ex: Poste.io) com usuário e senha de envio.
- DNS configurado: aponte o subdomínio do Chatwoot (ex:
chatwoot.seudominio.com.br) para o IP do seu servidor.
Link das aulas pré-requisitas abaixo:
Passo a Passo
Passo 1: Autenticar no Docker Hub (evita erro toomanyrequests)
Faça login no Docker Hub direto no terminal do servidor:
docker login
Passo 2: Baixar a imagem manualmente antes do deploy
Baixe a imagem da versão 4.13.0:
docker pull chatwoot/chatwoot:v4.13.0
Passo 3: Criar o banco de dados no PostgreSQL
O Chatwoot precisa de um banco dedicado. Acesse o container do seu Postgres:
PG=$(docker ps -qf name=postgres) docker exec -i $PG psql -U postgres -c "CREATE DATABASE chatwoot;"
pgvector), ajuste POSTGRES_HOST na stack antes do deploy.Passo 4: Preparar as variáveis de ambiente
Gere uma chave forte para o SECRET_KEY_BASE:
openssl rand -hex 64
Monte o bloco de Environment Variables com domínio, chave secreta, senha do Postgres e credenciais SMTP:
# ========================================== # DOMÍNIO # ========================================== DOMINIO_BASE=seudominio.com.br # ========================================== # SEGURANÇA # ========================================== SECRET_KEY_BASE=gere_com_openssl_rand_hex_64 # ========================================== # BANCO DE DADOS (POSTGRESQL) # ========================================== POSTGRES_PASSWORD=sua_senha_do_banco_aqui # ========================================== # SMTP (SERVIDOR DE E-MAIL) # ========================================== SMTP_ADDRESS=email.seudominio.com.br SMTP_USERNAME=contato@seudominio.com.br SMTP_PASSWORD=sua_senha_smtp_aqui
Passo 5: Ajustar e colar a stack no Portainer
Vá em Stacks → Add stack, dê o nome de chatwoot e cole o código docker-compose.yml da stack (ela já sobe os serviços chatwoot_app e chatwoot_sidekiq juntos). Abaixo do editor, ative Environment variables, clique em Advanced mode e cole o bloco do Passo 4. Clique em Deploy the stack.
⬇️ Ver e copiar a stack completa
Passo 6: Acompanhar o boot e as migrations
O entrypoint padrão do Chatwoot (docker/entrypoints/rails.sh) roda as migrations do banco automaticamente antes de subir o Rails. Acompanhe os logs do serviço principal:
docker service logs chatwoot_chatwoot_app --tail 50 -f
entrypoint do serviço chatwoot_app para ["sh", "-c", "sleep infinity"], faça o redeploy da stack, entre no container e rode a migration manualmente com bundle exec rails db:chatwoot_prepare. Depois de concluído, volte o entrypoint original e faça o redeploy de novo.Passo 7: Criar o primeiro usuário administrador
Como a stack sobe com ENABLE_ACCOUNT_SIGNUP=false, não existe tela pública de cadastro — o primeiro admin precisa ser criado via console do Rails:
docker exec -it $(docker ps -qf name=chatwoot_chatwoot_app) bundle exec rails c
Dentro do console, crie a conta e o usuário administrador (ajuste nome, e-mail e senha):
account = Account.create!(name: "Minha Empresa") User.create!(name: "Admin", email: "admin@seudominio.com.br", password: "SenhaForte123", account: account, role: :administrator)
Passo 8: Primeiro acesso
Quando os dois serviços estiverem com status Running (em verde) no Portainer:
- Acesse o domínio configurado:
https://chatwoot.seudominio.com.br. - Faça login com o e-mail e senha criados no Passo 7.
Resolução de Problemas Comuns no Chatwoot
| Sintoma | Causa | Solução |
|---|---|---|
| Erro 500 logo no primeiro boot | SECRET_KEY_BASE ausente ou inválido | Confirme se a variável foi gerada e colada corretamente no Advanced mode do Portainer |
| Sidekiq não processa filas (mensagens/e-mails presos) | Serviço chatwoot_sidekiq não subiu ou perdeu conexão com Redis | Verifique os logs do serviço chatwoot_sidekiq e se REDIS_URL aponta para o banco correto |
| Migrations não rodam / app não inicia | Conflito no entrypoint ou banco chatwoot ainda não existe | Confirme se o banco foi criado no Passo 3 e use o truque do sleep infinity para rodar a migration manualmente |
| E-mails não chegam | Credenciais SMTP incorretas ou porta 587 bloqueada | Revise SMTP_ADDRESS, SMTP_USERNAME e SMTP_PASSWORD nas variáveis de ambiente |
| Tela de login não abre / 502 Bad Gateway | Traefik não encontra a rota ou o domínio não aponta para o servidor | Confirme o DNS do subdomínio e se o serviço está na rede traefik_public |
Stack Completa – Chatwoot v4.13.0
Copie o código abaixo e cole direto no editor da sua stack no Portainer.
version: "3.8"
services:
chatwoot_app:
image: chatwoot/chatwoot:v4.13.0
entrypoint: docker/entrypoints/rails.sh
command: bundle exec rails s -p 3000 -b 0.0.0.0
volumes:
- chatwoot_data:/app/storage
networks:
- traefik_public
- digital_network
environment:
- CHATWOOT_HUB_URL=https://chatwoot.${DOMINIO_BASE}
- FRONTEND_URL=https://chatwoot.${DOMINIO_BASE}
- INSTALLATION_NAME=Chatwoot
- NODE_ENV=production
- RAILS_ENV=production
- INSTALLATION_ENV=docker
- SECRET_KEY_BASE=${SECRET_KEY_BASE}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- DEFAULT_LOCALE=pt_BR
- FORCE_SSL=true
- ENABLE_ACCOUNT_SIGNUP=false
- REDIS_URL=redis://redis:6379/2
- POSTGRES_HOST=postgres
- POSTGRES_USERNAME=postgres
- POSTGRES_DATABASE=chatwoot
- ACTIVE_STORAGE_SERVICE=local
- RAILS_LOG_TO_STDOUT=true
- USE_INBOX_AVATAR_FOR_BOT=true
- SIDEKIQ_CONCURRENCY=10
- RACK_TIMEOUT_SERVICE_TIMEOUT=25
- RAILS_MAX_THREADS=5
- WEB_CONCURRENCY=2
- ENABLE_RACK_ATTACK=false
- WEBHOOKS_TRIGGER_TIMEOUT=10
- MAILER_SENDER_EMAIL=Atendimento <${SMTP_USERNAME}>
- SMTP_DOMAIN=${DOMINIO_BASE}
- SMTP_ADDRESS=${SMTP_ADDRESS}
- SMTP_PORT=587
- SMTP_USERNAME=${SMTP_USERNAME}
- SMTP_AUTHENTICATION=login
- SMTP_ENABLE_STARTTLS_AUTO=true
- SMTP_OPENSSL_VERIFY_MODE=none
- MAILER_INBOUND_EMAIL_DOMAIN=${DOMINIO_BASE}
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
resources:
limits:
cpus: "2"
memory: 4096M
labels:
- traefik.enable=true
- traefik.docker.network=traefik_public
- traefik.http.routers.chatwoot_app.rule=Host(`chatwoot.${DOMINIO_BASE}`)
- traefik.http.routers.chatwoot_app.entrypoints=websecure
- traefik.http.routers.chatwoot_app.tls=true
- traefik.http.routers.chatwoot_app.tls.certresolver=le
- traefik.http.routers.chatwoot_app.priority=1
- traefik.http.services.chatwoot_app.loadbalancer.server.port=3000
- traefik.http.services.chatwoot_app.loadbalancer.passhostheader=true
- traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https
- traefik.http.routers.chatwoot_app.middlewares=sslheader@docker
chatwoot_sidekiq:
image: chatwoot/chatwoot:v4.13.0
entrypoint: docker/entrypoints/rails.sh
command: bundle exec sidekiq -C config/sidekiq.yml
volumes:
- chatwoot_data:/app/storage
networks:
- traefik_public
- digital_network
environment:
- CHATWOOT_HUB_URL=https://chatwoot.${DOMINIO_BASE}
- FRONTEND_URL=https://chatwoot.${DOMINIO_BASE}
- INSTALLATION_NAME=Chatwoot
- NODE_ENV=production
- RAILS_ENV=production
- INSTALLATION_ENV=docker
- SECRET_KEY_BASE=${SECRET_KEY_BASE}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- SMTP_PASSWORD=${SMTP_PASSWORD}
- DEFAULT_LOCALE=pt_BR
- FORCE_SSL=true
- ENABLE_ACCOUNT_SIGNUP=false
- REDIS_URL=redis://redis:6379/2
- POSTGRES_HOST=postgres
- POSTGRES_USERNAME=postgres
- POSTGRES_DATABASE=chatwoot
- ACTIVE_STORAGE_SERVICE=local
- RAILS_LOG_TO_STDOUT=true
- USE_INBOX_AVATAR_FOR_BOT=true
- SIDEKIQ_CONCURRENCY=10
- RACK_TIMEOUT_SERVICE_TIMEOUT=25
- RAILS_MAX_THREADS=5
- WEB_CONCURRENCY=2
- ENABLE_RACK_ATTACK=false
- WEBHOOKS_TRIGGER_TIMEOUT=10
- MAILER_SENDER_EMAIL=Atendimento <${SMTP_USERNAME}>
- SMTP_DOMAIN=${DOMINIO_BASE}
- SMTP_ADDRESS=${SMTP_ADDRESS}
- SMTP_PORT=587
- SMTP_USERNAME=${SMTP_USERNAME}
- SMTP_AUTHENTICATION=login
- SMTP_ENABLE_STARTTLS_AUTO=true
- SMTP_OPENSSL_VERIFY_MODE=none
- MAILER_INBOUND_EMAIL_DOMAIN=${DOMINIO_BASE}
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
resources:
limits:
cpus: "2"
memory: 4096M
volumes:
chatwoot_data:
name: chatwoot_data
chatwoot_public:
name: chatwoot_public
networks:
traefik_public:
external: true
digital_network:
external: true