SSD Nodes Learn
Guias Matt ConnorPor Matt Connor · Atualizado 2026-07-24

Como instalar Rocket.Chat com Docker Compose

Guia para rodar Rocket.Chat em VPS usando Docker Compose. Aprenda a configurar o MongoDB replica set obrigatório e evitar falhas de memória no Node.js.

O que você está construindo

Um chat privado para sua equipe com controle total: Rocket.Chat rodando em seu próprio VPS via Docker Compose, com terminação TLS e todas as mensagens armazenadas em um banco de dados MongoDB que você pode fazer backup e mover. O Rocket.Chat é uma alternativa madura e open-source ao Slack e Teams — canais, mensagens diretas, threads, compartilhamento de arquivos, além de voz e vídeo, tudo em hardware que você aluga e controla. A aplicação é um único container que inicia em minutos. Os problemas reais ocorrem no banco de dados adjacente, portanto, a maior parte deste guia é sobre MongoDB, especificamente sobre o requisito que surpreende a todos na primeira vez: o Rocket.Chat não funciona com um MongoDB standalone. Ele exige um replica set, mesmo que esse "set" seja composto por um único nó.

Pré-requisitos e o cálculo de RAM que ninguém te conta

Dimensionar o servidor com honestidade é essencial. O limite mínimo realista para uma equipe pequena é 2 vCPU e 4 GB de RAM. O processo Node.js do Rocket.Chat consome cerca de 1 a 1.5 GB sozinho, e o cache WiredTiger do MongoDB reserva metade da RAM restante por padrão. Em uma VPS de 2 GB, ambos iniciam normalmente, mas entram em conflito assim que o tráfego real chega: o cache do MongoDB cresce, o heap do Node cresce, o kernel fica sem páginas de memória e o out-of-memory killer encerra o maior processo — geralmente o mongod. O container exibe Killed, o Docker o reinicia e você terá um servidor de chat que cai a cada poucos minutos sob uma carga que deveria ser irrelevante. 2 GB é suficiente para testes com duas pessoas; não é um servidor para equipes. Comece com 4 GB e utilize 8 GB se esperar dezenas de usuários simultâneos, chamadas de vídeo ou um histórico de uploads crescente.

Você também precisa de três itens configurados antes de começar. Um domínio com um registro A apontando para o IP público da VPS — os recursos de tempo real e os clientes móveis do Rocket.Chat exigem um hostname estável, não apenas o IP. Portas 80 e 443 abertas tanto no firewall do servidor quanto no firewall de rede do seu provedor, que é um controle separado na maioria dos painéis. E uma VPS KVM Ubuntu 24.04 limpa com acesso root ou sudo. Se você ainda está decidindo se um servidor de chat é o serviço ideal para começar, o guia sobre o que vale a pena hospedar por conta própria em 2026 detalha os prós e contras.

Instale o Docker engine e o Compose plugin

Use o repositório apt oficial do Docker. Não use o pacote docker.io do Ubuntu nem o binário Python antigo docker-compose. O Compose moderno é um plugin do Docker invocado como docker compose — com espaço, não hífen. A versão antiga docker-compose v1 chegou ao fim do ciclo de vida e apresenta erros na sintaxe de healthcheck e dependências abaixo.

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Confirme se ambos os componentes estão presentes:

sudo docker version
sudo docker compose version

O comando docker compose version que retorna algo como Docker Compose version v2.x é a verificação necessária. Se ocorrer o erro docker: 'compose' is not a docker command, o plugin não foi instalado e você terá falhas confusas posteriormente — corrija o problema agora.

O arquivo compose: MongoDB como um replica set de um único nó

Esta é a parte onde as pessoas erram, então leia com atenção. O Rocket.Chat usa change streams do MongoDB para enviar novas mensagens aos clientes conectados em tempo real, e change streams só estão disponíveis em um replica set. Aponte o Rocket.Chat para um mongod standalone comum e ele conectará, falhará ao abrir um change stream e entrará em um loop de reinicialização infinito. A solução não é complexa: você executa um container MongoDB comum, mas o inicia com --replSet e depois inicializa um set de um único membro.

Crie um diretório de trabalho e um compose.yml:

services:
  mongodb:
    image: mongo:8.0
    restart: always
    command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--oplogSize", "128"]
    volumes:
      - mongodb_data:/data/db
      - mongodb_config:/data/configdb
    healthcheck:
      test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping')"]
      interval: 10s
      timeout: 10s
      retries: 12

  rocketchat:
    image: registry.rocket.chat/rocketchat/rocket.chat:8.5.1
    restart: always
    depends_on:
      mongodb:
        condition: service_healthy
    environment:
      MONGO_URL: "mongodb://mongodb:27017/rocketchat?replicaSet=rs0"
      MONGO_OPLOG_URL: "mongodb://mongodb:27017/local?replicaSet=rs0"
      ROOT_URL: "https://chat.example.com"
      PORT: "3000"
    ports:
      - "127.0.0.1:3000:3000"

volumes:
  mongodb_data:
  mongodb_config:

Algumas escolhas aqui são deliberadas. A porta do Rocket.Chat é publicada em 127.0.0.1:3000, não em 0.0.0.0 — o app em si não possui TLS, portanto apenas o reverse proxy na mesma máquina deve alcançá-lo; vinculá-lo a todas as interfaces exporia uma página de login em texto puro diretamente na internet pública. O MongoDB não é publicado no host; ele é acessível apenas pela rede interna do Compose sob o nome mongodb, que é exatamente o hostname que o MONGO_URL utiliza. O MONGO_URL inclui o ?replicaSet=rs0 — sem isso, o driver trata o servidor como standalone mesmo sendo um replica set, e os change streams continuam falhando. O MONGO_OPLOG_URL aponta para o banco de dados local onde o oplog reside; versões modernas do Rocket.Chat preferem change streams, mas definir isso é inofensivo e mantém códigos legados funcionando. O depends_on usa condition: service_healthy, então o Compose aguarda o MongoDB responder a um ping antes de iniciar o Rocket.Chat — essa é a função do healthcheck.

Fixe tags de versão reais em ambas as imagens — mongo:8.0 e uma versão explícita do Rocket.Chat como 8.5.1 aqui — e nunca use :latest, que transforma uma docker pull não supervisionada em um upgrade acidental e não migrável. Verifique a versão estável atual do Rocket.Chat e as versões do MongoDB que ela suporta antes de fixar as tags. O Rocket.Chat publica um documento de informações legível por máquina para cada release: curl -s https://releases.rocket.chat/8.5.1/info | jq '{compatibleMongoVersions, lts}' retorna compatibleMongoVersions: ["8.0"] para a 8.5.1, portanto mongo:8.0 é o único motor suportado, além de uma flag lts que informa se aquela release é uma build de longo suporte (LTS) que vale a pena fixar para um servidor que você não deseja monitorar manualmente.

Inicialize o replica set

Suba a stack:

sudo docker compose up -d

O Rocket.Chat começará a crashar imediatamente e o Docker continuará reiniciando o container — isso é esperado, pois o replica set ainda não existe. Crie-o manualmente:

sudo docker compose exec mongodb mongosh --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "mongodb:27017"}]})'

O resultado correto é { ok: 1 }. Em poucos segundos, o nó único se elegerá como primary; confirme com:

sudo docker compose exec mongodb mongosh --quiet --eval 'rs.status().members[0].stateStr'

O resultado esperado é PRIMARY. O detalhe mais importante desta página é o argumento host: "mongodb:27017". Se você executar um comando rs.initiate() sem a lista de membros, o MongoDB anunciará o replica set usando o hostname interno do container — um hash aleatório como a1b2c3d4e5f6. O Rocket.Chat, conectando-se de seu próprio container, não consegue resolver esse nome; o driver do MongoDB falha na resolução de DNS e entra em loop registrando MongoServerSelectionError: getaddrinfo ENOTFOUND a1b2c3d4e5f6. Sempre inicie com o nome de serviço explícito que corresponda ao seu MONGO_URL.

Primeiro boot: monitore a inicialização

Assim que o set estiver como primary, o próximo restart do Rocket.Chat conectará corretamente e iniciará as migrações de primeiro uso. Acompanhe os logs:

sudo docker compose logs -f rocketchat

A linha que você deve aguardar é o banner de inicialização:

+--------------------------------------------+
        SERVER RUNNING
   Rocket.Chat Version: 8.5.1
        NodeJS Version: 22.22.3 - x64
+--------------------------------------------+

O primeiro boot é lento — o app executa migrações de banco de dados e constrói índices, portanto, aguarde um ou dois minutos antes de se preocupar. Se o log repetir MongoServerSelectionError: Server selection timed out after 30000 ms com uma descrição de topologia do tipo ReplicaSetNoPrimary, o replica set não foi iniciado; se repetir getaddrinfo ENOTFOUND com um hash aleatório, foi iniciado com o host incorreto. Em ambos os casos, volte um passo. Assim que vir SERVER RUNNING, o Rocket.Chat estará escutando em 127.0.0.1:3000 e será hora de configurar um hostname real e TLS à frente dele.

Coloque atrás de TLS

Nunca exponha o Rocket.Chat via HTTP simples. Fazer login via http:// uma única vez entrega sua senha de admin a qualquer pessoa no caminho. Termine o TLS em um reverse proxy na mesma máquina e encaminhe para 127.0.0.1:3000. Dois pontos são importantes: o proxy deve encaminhar os headers de upgrade do WebSocket, pois o Rocket.Chat é em tempo real e para de funcionar sem eles, e o ROOT_URL do container deve corresponder exatamente ao endereço HTTPS público digitado pelos usuários.

Comece com um server block nginx em HTTP simples que faz o proxy para o app e encaminha os headers de upgrade. Salve como /etc/nginx/sites-available/rocketchat, crie um symlink em sites-enabled e recarregue:

server {
    listen 80;
    server_name chat.example.com;

    client_max_body_size 100M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Mantenha na porta 80 por enquanto — um bloco com listen 443 ssl; e sem certificado nem passará no sudo nginx -t. Recarregue o nginx (sudo nginx -t && sudo systemctl reload nginx) e depois emita o certificado. O caminho mais limpo no Ubuntu é Certificados TLS Let's Encrypt com Certbot e nginx: o certbot --nginx reescreve o bloco acima, adicionando listen 443 ssl;, as linhas ssl_certificate e um redirecionamento automático de 80 para 443, além de agendar a renovação para você. Se você já roda vários containers atrás de um único proxy, Traefik com TLS automático para vários apps Docker é a opção mais organizada — adicione labels de router e service ao serviço rocketchat e o Traefik solicita e renova o certificado para você, sem necessidade de bloco nginx. De qualquer forma, defina ROOT_URL como https://chat.example.com em compose.yml e execute o sudo docker compose up -d novamente para que o container aplique a mudança. Se você deseja que o servidor seja acessível apenas pela sua rede interna em vez da internet pública, coloque um WireGuard VPN self-hosted na VPS na frente e vincule o proxy ao endereço do túnel.

O assistente de configuração inicial

Acesse https://chat.example.com e o Rocket.Chat iniciará um assistente curto. Primeiro, a conta de admin — nome real, username, email e uma senha forte; esta é a única conta existente, portanto, não a perca. Em seguida, informações da organização e do servidor — nome, setor, tamanho, nome do site e idioma padrão; são dados cosméticos, preencha-os e prossiga. Depois, a escolha importante: registrar este workspace no Rocket.Chat Cloud ou manter como standalone.

O registro habilita notificações push para dispositivos móveis via gateway do Rocket.Chat e o marketplace de add-ons, mas estabelece uma relação de control-plane com a nuvem do Rocket.Chat. O modo standalone mantém o servidor totalmente privado e sem dependências, mas as notificações push de iOS e Android param de funcionar, pois a Apple e o Google não permitem que um app customizado gerencie os certificados de push — os apps oficiais utilizam o gateway da nuvem. Escolha standalone se a privacidade for o objetivo principal e seus usuários utilizarem apenas o web app; escolha o registro se notificações push móveis forem indispensáveis. Você pode alterar essa configuração posteriormente em Admin.

Restrinja o acesso antes de convidar usuários

O Rocket.Chat vem com open registration on — por padrão, o Registration Form está definido como Public, permitindo que qualquer pessoa com a URL crie uma conta. Em um hostname público, isso é uma vulnerabilidade. Vá em Admin → Settings → Accounts → Registration e altere o Registration Form para Disabled, para criar contas manualmente ou via link de convite, ou para Secret URL. Aproveite para desativar Allow Anonymous Read e Allow Anonymous Write, a menos que você precise de um canal público apenas para leitura.

Defina também o destino dos uploads. O armazenamento padrão do File Upload é o GridFS, que armazena cada imagem e anexo dentro do próprio MongoDB. Isso é simples, mas significa que seu banco de dados — e cada mongodump que você tirar — crescerá sem limites conforme os usuários colarem screenshots. Em Admin → Settings → File Upload, você pode alterar o armazenamento para o filesystem local ou um bucket compatível com S3, além de definir um tamanho máximo de arquivo razoável. Para equipes pequenas, o GridFS é suficiente; apenas esteja ciente de que seus backups ficarão maiores com o tempo.

Backups com mongodump

Todos os seus dados residem no volume mongodb_data. Não copie o volume com o banco de dados em execução — realize um dump consistente com mongodump, enviando o stream para um arquivo no host:

sudo docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > rocketchat-$(date +%F).archive.gz

Este arquivo único em formato gzipped contém todo o seu workspace: usuários, canais, mensagens, configurações e — se você configurou uploads no GridFS — os arquivos também. Se você moveu os uploads para o filesystem ou S3, faça o backup desse armazenamento separadamente. Para restaurar em uma nova instalação, inicialize o replica set primeiro e depois execute:

sudo docker compose exec -T mongodb mongorestore --archive --gzip --drop < rocketchat-2026-07-15.archive.gz

Copie o arquivo para fora da máquina — use object storage, outro servidor ou qualquer local onde a falha da VPS não leve o backup junto — e execute o dump via cron todas as noites. Um backup que você nunca restaurou é apenas uma esperança, não um backup; pratique a restauração em uma VPS descartável para garantir que o processo funciona antes que você realmente precise dele.

Upgrades: pin tags, read the notes, respect the Mongo matrix

Duas regras garantem que os upgrades sejam simples. Primeiro, atualize o Rocket.Chat uma versão major por vez. O sistema executa migrações de schema na inicialização e não permite saltos entre versões major; tentar ir da 6.x direto para a 8.x causará um erro de migração em vez de corromper os dados. Atualize a tag da imagem para a última release da próxima major, leia as notas de release para identificar breaking changes, execute docker compose up -d e monitore os logs até que a migração termine antes de prosseguir. Segundo, respeite a matriz de suporte do MongoDB. Cada release do Rocket.Chat suporta um conjunto específico de versões do MongoDB, e o curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions informa quais são. Ao atualizar o MongoDB — por exemplo, de 7.0 para 8.0 — faça o processo uma versão major por vez e defina a feature-compatibility version após cada salto. No MongoDB 8.0, esse comando exige um confirm: true explícito, caso contrário o sistema retornará um erro solicitando a execução com a flag de confirmação:

sudo docker compose exec mongodb mongosh --eval 'db.adminCommand({setFeatureCompatibilityVersion: "8.0", confirm: true})'

Faça um mongodump antes de cada upgrade de qualquer um dos componentes. Essa é a sua única garantia.

Modos de falha, com as strings exatas

O Rocket.Chat entra em loop de reinicialização logo após o docker compose up, e o docker compose logs rocketchat fica cheio de MongoServerSelectionError. O MongoDB está rodando, mas o driver não consegue selecionar um primary, e a string exata indica o erro cometido. Server selection timed out after 30000 ms com um topology type de ReplicaSetNoPrimary significa que você não executou o rs.initiate() — o set ainda não possui configuração. getaddrinfo ENOTFOUND seguido por um hash aleatório significa que você iniciou sem o host: "mongodb:27017" explícito, então o MongoDB anunciou um hostname de container irresolvível. Diagnostique com sudo docker compose exec mongodb mongosh --eval 'rs.status()': se ocorrer o erro MongoServerError: no replset config has been received, inicie o set; se mostrar um membro cujo name é um hash aleatório, reinicie usando o nome do serviço.

A interface web carrega, mas o login fica carregando infinitamente e nunca termina. Abra o console do navegador e você verá WebSocket connection to 'wss://chat.example.com/websocket' failed. Isso quase sempre é um mismatch de ROOT_URL ou um proxy que não está encaminhando os upgrade headers. Confirme se o ROOT_URL é igual ao endereço público exato, incluindo o https://, e se o seu bloco nginx location define Upgrade e Connection "upgrade" com proxy_http_version 1.1. Altere qualquer um deles e execute o docker compose up -d novamente.

Um container continua morrendo e o docker compose ps mostra que ele Restarting. O docker compose logs corta no meio da linha e o sudo dmesg | tail mostra Out of memory: Killed process 12345 (mongod) do oom-killer; o exit code é 137. O servidor está sem RAM. A solução definitiva é um VPS maior — mínimo de 4 GB. Como medida temporária, adicione swap e limite o cache do MongoDB com --wiredTigerCacheSizeGB 1 em seu command, mas o swap apenas adia o próximo OOM sob carga real:

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

docker compose up falha com Error response from daemon: driver failed programming external connectivity ... bind: address already in use. Algo já está utilizando a porta 3000 — geralmente um container anterior do Rocket.Chat que não parou corretamente, ou outro app. Localize o processo com sudo ss -ltnp | grep :3000, pare esse processo ou container, ou altere o lado do host do mapeamento para 127.0.0.1:3001:3000 e atualize o proxy_pass do seu proxy para corresponder.

FAQ

O Rocket.Chat realmente precisa de um MongoDB replica set?

Sim, mesmo para um servidor único com um nó de banco de dados. O Rocket.Chat entrega mensagens em tempo real usando MongoDB change streams, e change streams são um recurso exclusivo de replica-set — um mongod standalone não consegue abrir um. Você não precisa de várias máquinas; execute um container MongoDB iniciado com --replSet rs0 e inicialize um set de um único membro com rs.initiate(). Se pular essa etapa, o driver não encontrará um primary, o que fará o Rocket.Chat entrar em loop de reinicialização com MongoServerSelectionError: Server selection timed out e nunca terminar o boot.

Quanto de RAM o Rocket.Chat self-hosted precisa?

Planeje 4 GB como o mínimo prático e 8 GB para uma equipe ativa. O processo Node do Rocket.Chat usa cerca de 1 a 1.5 GB e o MongoDB reserva aproximadamente metade da RAM restante para o cache WiredTiger. Em uma máquina de 2 GB, ambos colidem e o out-of-memory killer encerra o mongod sob qualquer carga real, exibindo Killed nos logs e exit code 137. Dois GB são suficientes apenas para avaliar o software com alguns usuários de teste.

Como colocar o Rocket.Chat atrás de HTTPS?

Execute um reverse proxy na mesma VPS para encerrar o TLS e encaminhar para o 127.0.0.1:3000, e configure o ROOT_URL do container para o seu endereço público https://. O proxy deve encaminhar os headers de upgrade do WebSocket, caso contrário o login travará. Certbot com nginx é a configuração mais simples para um único app; Traefik é mais limpo se você rodar vários containers atrás de um único proxy e desejar gerenciamento automático de certificados.

Como fazer backup do Rocket.Chat self-hosted?

Faça um dump consistente do banco de dados com mongodump em vez de copiar o volume: docker compose exec -T mongodb mongodump --db rocketchat --archive --gzip > backup.archive.gz. Esse arquivo contém usuários, canais, mensagens e configurações, além de arquivos enviados se o armazenamento estiver no GridFS. Copie o backup para fora do servidor, automatize via cron diariamente e teste um mongorestore em uma máquina descartável para garantir que a restauração funciona.

Como atualizar o Rocket.Chat sem corromper o MongoDB?

Atualize o Rocket.Chat uma versão major por vez — o sistema executa migrações no boot e não permite pular versões major — e leia as notas de cada release antes de alterar a tag da imagem. Verifique quais versões do MongoDB a sua versão de destino suporta com curl -s https://releases.rocket.chat/<version>/info | jq .compatibleMongoVersions. Ao mover o MongoDB, atualize uma versão major por vez e configure o setFeatureCompatibilityVersion com confirm: true após cada salto. Sempre faça um mongodump antes.