Como instalar o Chatwoot em uma VPS
O Chatwoot junta os canais de atendimento numa caixa de entrada só: o chat do site, o e-mail, o WhatsApp. A equipe responde tudo de um lugar, e o histórico da conversa fica no seu banco, não no de terceiros.
É uma aplicação Rails com processamento em segundo plano, então são quatro peças: web, Sidekiq (filas), PostgreSQL e Redis.
Antes de começar
- VPS com Docker — veja o guia de Docker.
- Subdomínio apontado para o IP, por exemplo
chat.seudominio.com.br. - 4 GB de RAM. Rails com Sidekiq não cabe confortavelmente em 2 GB, e o processo de fila é o primeiro a morrer quando falta memória.
- SMTP para notificações e convites de agente.
Prepare o ambiente
O SECRET_KEY_BASE assina as sessões: troque-o depois e todo mundo é deslogado.
mkdir -p /opt/chatwoot && cd /opt/chatwoot
cat > .env <<EOF
DOMINIO=chat.seudominio.com.br
[email protected]
SECRET_KEY_BASE=$(openssl rand -hex 64)
POSTGRES_PASSWORD=$(openssl rand -hex 24)
SMTP_ADDRESS=smtp.seudominio.com.br
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=troque-aqui
[email protected]
EOF
chmod 600 .env
Escreva o docker-compose.yml
Repare que web e sidekiq usam a mesma imagem com comandos diferentes: um atende requisição, o outro processa fila.
cat > /opt/chatwoot/docker-compose.yml <<'EOF'
x-base: &base
image: chatwoot/chatwoot:v3.16.0
restart: unless-stopped
env_file: .env
environment:
RAILS_ENV: production
NODE_ENV: production
INSTALLATION_ENV: docker
FRONTEND_URL: https://${DOMINIO}
POSTGRES_HOST: postgres
POSTGRES_USERNAME: chatwoot
POSTGRES_DATABASE: chatwoot
REDIS_URL: redis://redis:6379
ACTIVE_STORAGE_SERVICE: local
RAILS_LOG_TO_STDOUT: "true"
TZ: America/Sao_Paulo
volumes:
- storage_data:/app/storage
services:
postgres:
image: pgvector/pgvector:pg16
restart: unless-stopped
environment:
POSTGRES_DB: chatwoot
POSTGRES_USER: chatwoot
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U chatwoot"]
interval: 10s
retries: 5
redis:
image: redis:7-alpine
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
web:
<<: *base
command: bundle exec rails s -b 0.0.0.0 -p 3000
depends_on:
postgres:
condition: service_healthy
sidekiq:
<<: *base
command: bundle exec sidekiq -C config/sidekiq.yml
depends_on:
postgres:
condition: service_healthy
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
DOMINIO: ${DOMINIO}
EMAIL: ${EMAIL}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
postgres_data:
redis_data:
storage_data:
caddy_data:
caddy_config:
EOF
cat > /opt/chatwoot/Caddyfile <<'EOF'
{$DOMINIO} {
tls {$EMAIL}
reverse_proxy web:3000
}
EOF
O banco é a imagem pgvector, não o PostgreSQL comum: versões recentes do Chatwoot usam essa extensão para busca. Com a imagem padrão, a migração falha.
Prepare o banco antes de subir
O Chatwoot precisa rodar as migrações uma vez antes do primeiro acesso.
cd /opt/chatwoot
docker compose up -d postgres redis
sleep 15
docker compose run --rm web bundle exec rails db:chatwoot_prepare
Suba tudo e crie a conta
docker compose up -d
docker compose ps
docker compose logs -f web
Abra https://chat.seudominio.com.br. A primeira visita mostra o cadastro do administrador e da conta.
Crie a conta assim que subir. Enquanto ninguém se cadastrar, quem abrir o endereço vira o dono da instalação.
Coloque o chat no seu site
Em Settings → Inboxes → Add Inbox → Website, informe o endereço do site. O Chatwoot gera um trecho de script para colar antes do </body> das suas páginas.
Para ligar o WhatsApp, o caminho usual é uma API intermediária — veja o guia da Evolution API.
Backup
cat > /opt/chatwoot/backup.sh <<'EOF'
#!/bin/bash
set -e
cd /opt/chatwoot
DESTINO=/opt/chatwoot/backups
mkdir -p $DESTINO
DATA=$(date +%Y%m%d-%H%M)
docker compose exec -T postgres pg_dump -U chatwoot chatwoot | gzip > "$DESTINO/chatwoot-$DATA.sql.gz"
docker run --rm -v chatwoot_storage_data:/dados -v "$DESTINO":/backup alpine tar czf "/backup/anexos-$DATA.tar.gz" -C /dados .
find "$DESTINO" -name '*.gz' -mtime +7 -delete
EOF
chmod +x /opt/chatwoot/backup.sh
(crontab -l 2>/dev/null; echo '0 3 * * * /opt/chatwoot/backup.sh') | crontab -
Se algo não funcionar
Erro de extensão vector durante a migração
A imagem do banco precisa ser a pgvector/pgvector:pg16. Se você subiu com o postgres comum, troque no compose, apague o volume do banco e refaça a preparação.
A interface abre mas nada acontece ao enviar mensagem
É o Sidekiq. Confirme que o contêiner está de pé — sem ele nada sai da fila:
docker compose ps sidekiq
docker compose logs --tail 40 sidekiq
O contêiner reinicia sozinho, sem erro claro
Falta de memória. Rails e Sidekiq juntos passam de 1,5 GB com facilidade:
free -h
docker stats --no-stream
Memória reservada, sem disputa com vizinho de nó. Ativação automática depois do pagamento.
Perguntas frequentes
O Chatwoot roda em 2 GB?
Na prática, não com folga. São dois processos Rails, PostgreSQL e Redis. Ele sobe, mas o Sidekiq é o primeiro a ser morto quando falta memória — e aí as mensagens param de sair sem erro aparente. 4 GB é o mínimo sensato.
Dá para conectar o WhatsApp?
O Chatwoot suporta a API Cloud oficial da Meta de forma nativa. Para a rota não oficial, o caminho é uma API intermediária, como a Evolution, com um conector no meio.
Como atualizo sem perder as conversas?
Rode o backup, troque a tag da imagem no compose, aplique as migrações com docker compose run --rm web bundle exec rails db:migrate e suba. Os dados vivem nos volumes. Leia as notas da versão antes de pular versões maiores.
Continue por aqui
Como instalar a Evolution API em uma VPS
API não oficial de WhatsApp com PostgreSQL e Redis, pronta para integrar com n8n, Typebot ou seu próprio sistema.
Como instalar o n8n em uma VPS com Docker e HTTPS
Sobe o n8n com banco PostgreSQL e certificado automático, em uma VPS Ubuntu com acesso root.
Como instalar o Typebot em uma VPS
Construtor de conversas auto-hospedado, com builder e viewer em subdomínios separados e armazenamento de arquivos.