← Blog

Self-host do Chatwoot com Postgres, Redis e Sidekiq

Railyard

11 de abril de 2026 · 10 min de leitura

Siga isso no seu próprio servidor. Comece grátis, sem cartão

O Chatwoot te dá uma caixa de entrada compartilhada e um widget de chat em tempo real sem uma conta SaaS por agente, mas o projeto em si tem quatro peças em movimento: um processo web Rails, um worker Sidekiq pra jobs em segundo plano, Postgres, e Redis. Errar qualquer uma delas (um FRONTEND_URL obsoleto, um worker que não consegue alcançar o Redis, um certificado que nunca é emitido) e você tem uma página de login que gira pra sempre em vez de uma caixa de suporte. No final deste guia você vai ter os quatro serviços rodando no seu próprio servidor, atrás de HTTPS, com backups e um caminho de upgrade que você consegue de fato repetir.

O que você vai precisar

  • Um servidor com pelo menos 4 vCPUs e 8 GB de RAM. A própria documentação de self-hosting do Chatwoot lista 2 núcleos / 4 GB como o mínimo absoluto, mas isso é só pro processo web; depois que você adiciona o worker Sidekiq, Postgres e Redis na mesma máquina, a documentação deles move a recomendação pra 4+ núcleos e 8 GB+. Um Hetzner CX33 (4 vCPU, 8 GB de RAM, 80 GB NVMe) encaixa nessa recomendação e custa atualmente €8,99/mês sem IVA.
  • Ubuntu 22.04 ou mais novo, com acesso root ou sudo.
  • Um nome de domínio pro qual você pode apontar um registro A (este guia usa chat.example.com).
  • Opcional mas recomendado: credenciais SMTP de um provedor de email transacional, pra o Chatwoot conseguir mandar redefinições de senha e notificações de agente. O Chatwoot vem sem SMTP configurado por padrão.

Passo 1: aponte o DNS pro servidor e abra o firewall

Crie um registro A pro seu subdomínio apontando pro endereço IPv4 público do servidor. A propagação de DNS é por isso que a etapa de HTTPS mais pra frente pode falhar se você apressar, então faça isso primeiro e deixe se estabelecer enquanto você trabalha no resto da configuração.

No próprio servidor, abra só as portas que você precisa:

ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

Você deve ver Status: active com essas três regras listadas quando você rodar ufw status.

Passo 2: instale o Docker

O deploy em Docker do Chatwoot precisa do Docker Engine e do plugin Compose. O script de instalação oficial configura os dois:

curl -fsSL https://get.docker.com | sh
usermod -aG docker $(whoami)

Saia e entre de novo pra mudança de grupo entrar em vigor, depois cheque se as duas partes estão presentes:

docker --version
docker compose version

Você deve ver uma versão do Docker e uma versão do Compose impressas, não um erro de “command not found”.

Passo 3: gere os secrets que você vai precisar

Três valores precisam existir antes de você escrever o arquivo compose: uma chave secreta do Rails, uma senha de Postgres, e uma senha de Redis. Gere os três agora pra você não ficar tentado a deixar um padrão no lugar:

openssl rand -hex 64   # SECRET_KEY_BASE
openssl rand -hex 24   # POSTGRES_PASSWORD
openssl rand -hex 24   # REDIS_PASSWORD

Guarde as três saídas em algum lugar de onde você possa colar depois. Coloque elas num arquivo .env do lado do arquivo compose em vez de fixar no código, então o próprio arquivo compose fica seguro pra manter no controle de versão:

mkdir -p /opt/chatwoot && cd /opt/chatwoot
cat > .env <<'EOF'
SECRET_KEY_BASE=paste-the-first-value-here
POSTGRES_PASSWORD=paste-the-second-value-here
REDIS_PASSWORD=paste-the-third-value-here
SMTP_ADDRESS=smtp.your-provider.com
SMTP_USERNAME=your-smtp-username
SMTP_PASSWORD=your-smtp-password
EOF
chmod 600 .env

Passo 4: escreva o arquivo Compose

Essa é a parte que a maioria dos guias passa por cima: o Chatwoot precisa exatamente das mesmas variáveis de ambiente tanto no container web quanto no container Sidekiq, porque o Sidekiq roda a mesma aplicação Rails, só com um processo diferente. Esquecer uma no worker e os jobs em segundo plano (envios de email, webhooks, pesquisas de CSAT) falham silenciosamente mesmo que a interface web pareça bem.

services:
  postgres:
    image: pgvector/pgvector:0.8.7-pg16
    restart: always
    environment:
      POSTGRES_USER: chatwoot
      POSTGRES_DB: chatwoot
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data

  redis:
    image: redis:7.4.11-alpine
    restart: always
    command: ["redis-server", "--requirepass", "${REDIS_PASSWORD}"]
    volumes:
      - redis-data:/data

  rails:
    image: chatwoot/chatwoot:v4.18.0
    restart: always
    depends_on:
      - postgres
      - redis
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      RAILS_ENV: production
      NODE_ENV: production
      INSTALLATION_ENV: docker
      SECRET_KEY_BASE: ${SECRET_KEY_BASE}
      FRONTEND_URL: https://chat.example.com
      REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379
      POSTGRES_HOST: postgres
      POSTGRES_USERNAME: chatwoot
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DATABASE: chatwoot
      SMTP_ADDRESS: ${SMTP_ADDRESS}
      SMTP_PORT: "587"
      SMTP_USERNAME: ${SMTP_USERNAME}
      SMTP_PASSWORD: ${SMTP_PASSWORD}
      SMTP_AUTHENTICATION: plain
      SMTP_DOMAIN: example.com
      MAILER_SENDER_EMAIL: support@example.com
    command: >
      bash -c "bundle exec rails db:chatwoot_prepare && bundle exec rails s -p 3000 -b 0.0.0.0"
    volumes:
      - storage-data:/app/storage

  sidekiq:
    image: chatwoot/chatwoot:v4.18.0
    restart: always
    depends_on:
      - postgres
      - redis
    environment:
      RAILS_ENV: production
      NODE_ENV: production
      INSTALLATION_ENV: docker
      SECRET_KEY_BASE: ${SECRET_KEY_BASE}
      FRONTEND_URL: https://chat.example.com
      REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379
      POSTGRES_HOST: postgres
      POSTGRES_USERNAME: chatwoot
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DATABASE: chatwoot
      SMTP_ADDRESS: ${SMTP_ADDRESS}
      SMTP_PORT: "587"
      SMTP_USERNAME: ${SMTP_USERNAME}
      SMTP_PASSWORD: ${SMTP_PASSWORD}
      SMTP_AUTHENTICATION: plain
      SMTP_DOMAIN: example.com
      MAILER_SENDER_EMAIL: support@example.com
    command: bundle exec sidekiq -C config/sidekiq.yml
    volumes:
      - storage-data:/app/storage

volumes:
  postgres-data:
  redis-data:
  storage-data:

Note que o container Rails só vincula a 127.0.0.1:3000, não a interface pública. O Caddy, que você vai configurar a seguir, é o que de fato enfrenta a internet; o container da aplicação nunca deveria ser acessível diretamente.

Substitua chat.example.com e support@example.com pelo seu domínio real antes de continuar. Cheque se o arquivo é interpretado corretamente:

docker compose config

Você deve ver a configuração completa resolvida impressa de volta sem erro, e nenhum placeholder ${...} sobrando na saída.

Passo 5: suba a stack

docker compose up -d

O comando do container rails roda db:chatwoot_prepare antes de iniciar o servidor web, que cria o banco de dados, carrega o schema, e popula os dados iniciais na primeira inicialização. Observe isso acontecer:

docker compose logs -f rails

Você deve ver a saída de migration seguida de Listening on http://0.0.0.0:3000. Depois confirme que os quatro containers de fato estão de pé:

docker compose ps

Você deve ver postgres, redis, rails e sidekiq todos num estado running ou healthy, não restarting.

Passo 6: coloque o Caddy na frente com HTTPS automático

Instale o Caddy e dê a ele um bloco de site só. O Caddy solicita e renova o certificado por conta própria na primeira vez que inicia, desde que o DNS já esteja apontando pro servidor:

apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install -y caddy

Substitua /etc/caddy/Caddyfile por:

chat.example.com {
	reverse_proxy localhost:3000
}

Depois recarregue:

systemctl reload caddy

Visite https://chat.example.com num navegador. Você deve ver um cadeado válido e a tela de configuração do Chatwoot, não um aviso de certificado.

Passo 7: faça backup do Postgres num horário agendado

Tudo que importa (conversas, contatos, contas de agente) mora no volume postgres. Um dump diário que você move pra fora do servidor é o backup mínimo viável:

cat > /opt/chatwoot/backup.sh <<'EOF'
#!/bin/sh
cd /opt/chatwoot
docker compose exec -T postgres pg_dump -U chatwoot chatwoot | gzip > /opt/chatwoot/backups/chatwoot-$(date +%F).sql.gz
find /opt/chatwoot/backups -mtime +14 -delete
EOF
chmod +x /opt/chatwoot/backup.sh
mkdir -p /opt/chatwoot/backups
(crontab -l 2>/dev/null; echo "0 3 * * * /opt/chatwoot/backup.sh") | crontab -

Copie pelo menos um desses arquivos .sql.gz pra fora do servidor (pra object storage, outra máquina, qualquer lugar que não seja essa VPS) pra um disco perdido não levar os seus backups junto. Rode ls /opt/chatwoot/backups na manhã seguinte; você deve ver um arquivo novo com data.

Passo 8: fazendo upgrade pra uma versão nova do Chatwoot

Todo upgrade do Chatwoot precisa do comando de migration rodado de novo, do mesmo jeito que a primeira inicialização fez. Baixe a tag nova, rode a migration uma vez, depois reinicie os dois containers que usam a imagem:

docker compose pull rails sidekiq
docker compose run --rm rails bundle exec rails db:chatwoot_prepare
docker compose up -d rails sidekiq

Cheque docker compose logs -f rails de novo. Você deve ver a string da versão nova no log de boot e nenhum erro de migration.

O caminho mais rápido: faça isso com a Railyard

Tudo acima (a instância Postgres, a instância Redis com uma senha, o processo web, o worker Sidekiq lendo exatamente o mesmo ambiente, o volume de storage compartilhado entre eles, HTTPS no seu domínio) também está disponível como um template no próprio catálogo de templates da Railyard. Escolha Chatwoot ali e os quatro serviços sobem já conectados entre si: Postgres e Redis são conectados tanto ao processo web quanto ao worker Sidekiq automaticamente, então não existe copiar e colar variáveis de ambiente entre dois containers e esperar não ter esquecido uma. Você ainda adiciona o seu próprio provedor de SMTP depois, já que a Railyard também não configura um pra você. Se você preferir começar do seu próprio fork ou uma versão modificada da stack, deploying from a repository e the deploy button funcionam do mesmo jeito. Backups pro serviço Postgres são cobertos em databases and backups, e se essa é a sua primeira vez na Railyard, the quickstart cobre a configuração de conta antes de qualquer coisa disso. Pra ter uma ideia do que uma máquina assim custa entre provedores, veja hosting costs.

Resolução de problemas

“Port is already allocated” no docker compose up. Alguma outra coisa no servidor já está usando a porta 3000, ou você rodou docker compose up duas vezes sem parar a primeira execução. Cheque com ss -tlnp | grep 3000 e pare o que quer que esteja ocupando ela, ou mude o lado esquerdo do mapeamento de porta do serviço rails.

A página de login carrega mas redirecionamentos ou links estão errados. FRONTEND_URL tem que ser a URL HTTPS exata que agentes e clientes vão usar, definida tanto nos containers rails quanto sidekiq. Uma incompatibilidade (http em vez de https, uma barra no final, o subdomínio errado) quebra links de redefinição de senha, callbacks de webhook e as próprias URLs de asset do widget mesmo que a própria aplicação suba bem.

O certificado nunca é emitido, os logs do Caddy mostram “challenge failed” repetido. Isso quase sempre é DNS, não o Caddy. O registro A ou ainda não se propagou ou não aponta pro IP desse servidor. Rode dig chat.example.com +short a partir da sua própria máquina e confirme que ele retorna o IP público real do servidor antes de recarregar o Caddy de novo.

Uploads de arquivo ou avatares falham com erros de permissão. O volume chatwoot-storage precisa ser gravável pelo usuário com o qual o processo Rails roda dentro do container. Se você mudou o mount do volume ou está migrando de um bind mount, cheque a propriedade com docker compose exec rails ls -la /app/storage em vez de adivinhar.

O container Sidekiq continua reiniciando ou jobs nunca processam. Cheque docker compose logs sidekiq primeiro. Um worker morto pelo OOM aparece como o container reiniciando sem erro claro no log, caso em que a correção é mais memória pra máquina, não uma mudança de configuração. Se ele está de pé mas jobs simplesmente nunca rodam, confirme que REDIS_URL no serviço sidekiq corresponde exatamente ao serviço rails, caractere por caractere, incluindo a senha.

Nenhum email é enviado, nunca. O Chatwoot vem sem SMTP configurado. Se você pulou as variáveis de SMTP no Passo 4, redefinições de senha, convites de agente e notificações de conversa todas silenciosamente não fazem nada. Adicione credenciais SMTP reais e reinicie os containers rails e sidekiq.

Perguntas frequentes

Eu consigo rodar o Chatwoot sem Sidekiq? Não. Jobs em segundo plano (envio de email, webhooks, CSAT, regras de automação) dependem dele; sem ele a aplicação roda mas grandes partes dela silenciosamente param de funcionar.

O Chatwoot precisa do Redis pra alguma coisa além do Sidekiq? Sim, ele também é usado pra cache e ActionCable (as atualizações em tempo real no painel do agente), então é obrigatório mesmo que você não pense em si mesmo como usando jobs em segundo plano diretamente.

Postgres e Redis conseguem rodar num servidor separado e menor do que o web e o worker? Sim, e a própria documentação do Chatwoot menciona isso como uma opção quando você quer usar serviços de banco de dados gerenciados em vez de containers. Pra uma equipe pequena só, manter os quatro numa máquina só é mais simples de operar e é o que este guia cobre.

Qual é a diferença entre a especificação básica de 2 núcleos / 4 GB e a de 4 núcleos / 8 GB? O número menor é pro processo web por si só. O maior é a própria recomendação do Chatwoot depois que Postgres, Redis e o worker Sidekiq todos competem por CPU e memória na mesma máquina, que é o caso normal pra uma instalação self-hosted.

Eu preciso usar exatamente as tags de imagem deste guia? Não, tags mais novas são lançadas regularmente. Este guia fixa chatwoot/chatwoot:v4.18.0 porque essa é a versão de fato verificada de ponta a ponta; cheque as notas de release do projeto antes de mudar pra uma tag mais nova, e rode a etapa de migration de novo de qualquer jeito.

Uma instalação funcional do Chatwoot é quatro peças pequenas e bem entendidas conversando entre si corretamente, não uma coisa complicada só. Depois que o DNS, as variáveis de ambiente e a etapa de migration estão certas, sobra muito pouco pra manter além de backups e uma atualização de versão ocasional.

Por que escolhem o Railyard para isso

  • Sua própria conta de cloud. Faça deploy no DigitalOcean, Hetzner, Vultr, AWS, OVHcloud, ou em qualquer servidor Linux via SSH, cobrado direto pelo seu provedor, sem markup.
  • Um preço fixo por equipe. O Free é grátis para sempre: um servidor mais um servidor de banco de dados, três apps, sem cartão. O Pro custa US$19 por mês para até cinco servidores e apps ilimitados. O Team custa US$49 por mês com servidores ilimitados. Sem cobrança por app, por deploy, por assento ou por gigabyte.
  • Templates de um clique. Faça deploy de apps open source, como bancos de dados, analytics e ferramentas de dev, no seu próprio servidor em um clique.
  • Bancos de dados gerenciados. Postgres, MySQL e Redis com backups programados, verificados por restauração, e recuperação point-in-time.
  • Push-to-deploy. Faça deploy a partir do GitHub, GitLab ou da CLI, com HTTPS automático e releases sem downtime.

Pule a configuração de servidor

Escolha Chatwoot no catálogo de templates da Railyard e tenha os mesmos quatro serviços conectados e implantados sem tocar num terminal.

Plano grátis, sem cartão, e 14 dias de Pro para cada equipe nova. Um preço fixo por equipe.