Como instalar o Discourse numa VPS com Docker
Aprenda a instalar o Discourse com o launcher Docker oficial: RAM e swap, dominio real, SMTP, app.yml, rebuild, TLS e configuracao para reverse proxy.
Instalar o Discourse numa VPS: um contentor, um ficheiro de configuração
Para instalar o Discourse numa VPS, execute o instalador do próprio projeto, responda a um assistente curto e aguarde a compilação. O Discourse é distribuído como um único contentor Docker que inclui a aplicação Rails, o PostgreSQL, o Redis e o nginx. Tudo o que alterar mais tarde fica no ficheiro /var/discourse/containers/app.yml, e cada alteração é aplicada ao site através de uma nova compilação.
A instalação oficial é discourse_docker: um script de shell launcher e um conjunto de modelos YAML. O Discourse não suporta um ficheiro Compose escrito por si, e o contentor não foi concebido para ser dividido manualmente. Se está habituado a executar serviços numa VPS com Docker Compose, espere uma estrutura diferente. Aqui não existe docker compose up -d, e ./launcher rebuild app é a implantação.
O que o Discourse exige antes de começar
Quatro requisitos costumam causar problemas, e cada um deles falha antes de chegar à página de login.
- Memória. Um contentor executa PostgreSQL, Redis, Sidekiq e um servidor web Ruby. A etapa de compilação dos assets precisa de mais memória do que o site em execução.
- Um nome de domínio real. A configuração de exemplo fornecida é explícita: "O Discourse não funciona com um endereço IP isolado."
- Um caminho de saída para correio eletrónico. A ativação de contas, as reposições de palavra-passe, os convites de administradores e o correio de resumo saem por SMTP (simple mail transfer protocol).
- As portas 80 e 443 livres no host, exceto se colocar deliberadamente o Discourse atrás de um proxy que já execute.
The data behind this chart
[
{
"label": "Documented minimum",
"ram_gb": 1,
"storage_gb": 10
},
{
"label": "Documented recommended",
"ram_gb": 2,
"storage_gb": 20
}
]O documento oficial de instalação estabelece o mínimo em 1 GB de RAM com swap e 10 GB de disco, e recomenda 2 GB de RAM com 20 GB de disco. Interprete a primeira linha como o valor que permite concluir o instalador, não como o valor pretendido para executar uma comunidade. A diferença é importante porque o pico de memória ocorre durante a compilação, não por causa do tráfego.
Aponte o domínio para o servidor antes de instalar
Crie um registo A para o hostname que vai utilizar e confirme-o a partir do próprio servidor.
dig +short forum.example.com
curl -4 -s https://ifconfig.coAmbos os comandos devem apresentar o mesmo endereço. Têm de coincidir porque o assistente de configuração testa a ligação ao hostname, e um registo que ainda aponte para outro local falha esse teste. Um registo criado há dois minutos também pode continuar em cache. Aguarde que o TTL (tempo de vida) antigo expire em vez de tentar contornar o assistente.
Decida agora se o registo será colocado atrás de um CDN. Um registo com proxy oculta o endereço do servidor, e o pedido de certificado do contentor falha porque o desafio ACME (ambiente de gestão automática de certificados) é respondido pelo proxy em vez de pelo Discourse. Mantenha o registo sem proxy durante a primeira instalação.
Executar o instalador oficial
Um comando instala o git, instala o Docker com o próprio script de instalação do Docker, clona discourse_docker em /var/discourse e inicia o assistente de configuração.
wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bashSe o Docker já estiver instalado no servidor e preferir ver cada passo, faça o mesmo trabalho manualmente.
sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setupExecute-o como root. Se for iniciado por um utilizador comum, discourse-setup termina imediatamente com This script must be run as root. Please sudo or log in as root first.. Se o Docker não estiver instalado no servidor, termina com Docker is not installed. Please install Docker first., porque a clonagem manual não instala nada por si.
O que o assistente de configuração pergunta e o que escreve
Em agosto de 2026, discourse-setup é um wrapper simples. Ele executa discourse/setup-wizard:release como um contentor, com a rede do host e o socket do Docker montado, para que o assistente possa inspecionar a máquina que está a configurar. O assistente pede o hostname e os endereços de email dos administradores e, em seguida, os dados SMTP. Escreve containers/app.yml e depois faz uma nova compilação.
É importante conhecer dois comportamentos antes de começar. Se a máquina tiver pouca memória e não tiver swap, o assistente para e oferece-se para criar uma: o wrapper cria um /swapfile de 2 GB, adiciona-o a /etc/fstab, define vm.swappiness = 10 em /etc/sysctl.d/30-discourse-swap.conf e inicia novamente o assistente. Quando o assistente termina, apresenta Rebuilding app in 5 seconds (Ctrl+C to cancel)... e executa ./launcher rebuild app no host. Essa compilação demora vários minutos numa VPS pequena. A primeira é a mais lenta porque todos os recursos são compilados de raiz.
./discourse-setup --help apresenta as opções relevantes quando existe um problema. --skip-rebuild escreve a configuração sem fazer a compilação, e --skip-connection-test ignora as verificações de DNS e de portas. Use --skip-connection-test apenas quando já souber por que motivo o teste falha, por exemplo, quando o host está atrás de uma firewall de rede que controla.
Leia o app.yml antes da primeira reconstrução
O assistente grava um ficheiro que passa a ser da sua responsabilidade. Abra-o com sudo nano /var/discourse/containers/app.yml. Estas são as partes que determinam quase tudo.
templates:
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
## Uncomment these two lines if you wish to add Lets Encrypt (https)
#- "templates/web.ssl.template.yml"
#- "templates/web.letsencrypt.ssl.template.yml"
expose:
- "80:80" # http
- "443:443" # https
env:
DISCOURSE_HOSTNAME: "forum.example.com"
DISCOURSE_DEVELOPER_EMAILS: "you@example.com"
DISCOURSE_SMTP_ADDRESS: smtp.example.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: user@example.com
DISCOURSE_SMTP_PASSWORD: "your-smtp-password"DISCOURSE_HOSTNAME é o endereço em que o site responde, e o Discourse cria as ligações a partir desse valor. Um valor incorreto faz com que o site carregue uma vez e depois o encaminhe para outro endereço. DISCOURSE_DEVELOPER_EMAILS é uma lista separada por vírgulas, e esses endereços tornam-se automaticamente administradores no primeiro registo. Insira o seu próprio endereço nessa lista e faça o registo com ele, porque é assim que a primeira conta de administrador é criada.
O ficheiro armazena a palavra-passe SMTP em texto simples. Por isso, restrinja o diretório com sudo chmod 700 /var/discourse/containers. O ficheiro também está em YAML, o que significa que os espaços em branco fazem parte da configuração. Uma chave desalinhada faz a reconstrução falhar com um erro de análise e deixa o site indisponível. Existe uma armadilha documentada no próprio ficheiro de exemplo. Um # dentro de uma palavra-passe sem aspas inicia um comentário. Por isso, coloque entre aspas qualquer palavra-passe que contenha esse caractere.
O email é a etapa que interrompe a maioria das instalações
Em agosto de 2026, o assistente permite ignorar o SMTP e usar logins do Discourse ID. O app.yml também inclui um parâmetro DISCOURSE_SKIP_EMAIL_SETUP correspondente, descrito nessa página como a opção para ignorar a validação da configuração de email. Ignorar esta etapa é aceitável para uma primeira avaliação do software. É uma escolha inadequada para uma comunidade, porque, sem email de saída, ninguém pode ativar uma conta ou repor uma palavra-passe.
O problema prático é que a maioria dos fornecedores de VPS bloqueia a porta de saída 25. Por isso, um servidor de email simples na máquina não conseguirá entregar mensagens. Use um relay autenticado na porta 587 ou na porta 465 com TLS implícito (transport layer security). Para a porta 465, defina DISCOURSE_SMTP_FORCE_TLS: true, conforme recomendado pela configuração de exemplo para essa porta. Teste a acessibilidade a partir do host antes de reconstruir a instalação.
nc -vz smtp.example.com 587Um resultado normal é uma única linha terminada em succeeded!. Se o comando ficar bloqueado e terminar depois com timeout, a porta está bloqueada no caminho de saída da sua VPS. Nenhuma configuração do Discourse corrige esse problema. Use uma porta permitida pelo fornecedor ou peça-lhe para desbloquear a porta.
Quando o site estiver ativo, envie uma mensagem de teste a partir da página Email, em Admin. Depois, consulte os separadores Skipped e Bounced nessa mesma página. É nesses separadores que o Discourse regista as mensagens que recusou enviar e as mensagens que o relay rejeitou. Os separadores indicam o motivo, o que é mais rápido do que ler os logs.
TLS: deixe o container obter o seu próprio certificado
Se o Discourse usar as portas 80 e 443, utilize o mecanismo de emissão integrado. Remova os comentários das duas linhas do template SSL mostradas acima e, em seguida, faça o rebuild. O template controla o acme.sh, armazena os certificados no volume partilhado em /shared/ssl, renova-os segundo um agendamento dentro do container e configura o Discourse para forçar HTTPS.
A porta 80 tem de continuar acessível a partir da Internet para isto funcionar, porque o desafio HTTP é respondido nessa porta. Uma firewall que permita apenas a porta 443 permite concluir o build, mas o certificado nunca é emitido. Verifique o resultado com ./launcher logs app imediatamente depois do rebuild.
Deve colocar nginx ou Caddy à frente?
Se o Discourse for o único serviço web no VPS, não. O contentor já executa um nginx ajustado, e um segundo proxy adiciona um salto, outro certificado para renovar e uma nova fonte de problemas nos cabeçalhos.
Coloque-o à frente quando o mesmo VPS servir outros sites. Adicione templates/web.socketed.template.yml à lista de templates, comente ambas as linhas expose e mantenha os dois templates SSL comentados. O contentor passa a escutar num socket Unix em /var/discourse/shared/standalone/nginx.http.sock e deixa de ocupar portas, libertando as portas 80 e 443 para o seu próprio proxy.
server {
listen 443 ssl;
server_name forum.example.com;
location / {
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
}
}Os dois-pontos no final de .sock fazem parte da sintaxe de socket Unix do nginx, e sudo nginx -t recusa a configuração sem eles. X-Forwarded-Proto também é obrigatório. O Discourse escreve links absolutos. Sem esse cabeçalho, gera links http:// numa página HTTPS, e os navegadores bloqueiam-nos como conteúdo misto. Com o contentor ligado ao socket, a gestão do TLS passa a ser sua. Emita o certificado no host com Certbot no Ubuntu 24.04 e nginx. Se ainda não escolheu um proxy, a comparação entre nginx, Caddy e Traefik apresenta os compromissos dessa escolha.
Rebuilds, atualizações e os comandos que você realmente vai usar
cd /var/discourse
./launcher rebuild apprebuild destrói o contentor em execução, cria um novo a partir de app.yml e inicia-o. O site fica offline durante toda a compilação, por isso trate cada alteração de configuração como uma indisponibilidade programada de alguns minutos.
Alterar apenas valores em env: não exige isso. ./launcher destroy app && ./launcher start app recria o contentor a partir da imagem que já compilou, o que demora alguns segundos. Qualquer alteração em templates: ou hooks: modifica a própria imagem, por isso exige a recompilação completa.
As atualizações chegam de duas formas. As versões de manutenção são aplicadas pela interface web em /admin/upgrade, fornecida pelo plugin docker_manager que app.yml clona durante a compilação. As alterações à imagem base ou aos templates vêm do git.
cd /var/discourse
git pull
./launcher rebuild appÉ durante as recompilações que os servidores pequenos falham, porque a compilação dos recursos é o pico de consumo de memória de todo o sistema. Se uma compilação parar a meio e dmesg mostrar uma linha como Out of memory: Killed process a identificar um processo ruby, o sistema ficou sem memória durante a compilação, mesmo que o site estivesse a funcionar corretamente antes. Adicione swap e execute novamente a recompilação.
./launcher logs app
./launcher enter app
./launcher cleanuplogs mostra a saída do contentor, enter abre uma shell dentro dele e cleanup remove os contentores que estão parados há mais de 24 horas. Execute cleanup periodicamente, porque cada recompilação deixa um contentor antigo e o disco de um VPS pequeno fica sem espaço sem que seja imediatamente evidente.
Backups e o ficheiro que o backup não contém
Crie backups na página Backups em Admin. O arquivo fica no host em /var/discourse/shared/standalone/backups/default/. A mesma tarefa pode ser executada numa shell.
cd /var/discourse
./launcher enter app
discourse backupdiscourse restore <filename> reverte o processo, e os restauros são recusados até executar discourse enable_restore. Essa proteção existe para impedir que um comando acidental substitua um fórum em produção.
Há duas lacunas que tem de resolver. O arquivo contém a base de dados e contém os ficheiros carregados apenas quando a definição de backup que inclui uploads está ativa. Verifique essa definição antes de confiar no backup. O arquivo nunca contém app.yml. Por isso, um restauro numa VPS nova ainda precisa do hostname e do bloco SMTP. Copie também esse ficheiro para fora do servidor.
O arquivo também fica no mesmo disco que o site que protege. Isso não é um backup. Transfira-o para outro local segundo um agendamento.
rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/Quanto custa um fórum ativo em RAM
O bootstrap define UNICORN_WORKERS e db_shared_buffers com base na memória e na CPU detetadas, e a configuração de exemplo limita os buffers partilhados a um quarto da memória total. Cada worker do unicorn é um processo Ruby completo, e o Sidekiq executa tarefas em segundo plano em paralelo com eles. Por isso, o consumo de memória acompanha os pedidos simultâneos, não o número de membros registados. Um fórum pouco ativo, com algumas centenas de membros, não representa uma carga elevada.
Não dimensione o servidor com base num número apresentado num artigo, incluindo este. Faça as suas próprias medições.
free -m
docker stats --no-streamO uso constante de swap juntamente com páginas lentas significa que há pouca RAM disponível. Memória estável com páginas lentas normalmente indica outro problema. Por isso, leia ./launcher logs app antes de contratar um plano maior. Adicione também uma verificação externa ao servidor, porque um fórum que fica sem memória às 3h falha silenciosamente: um monitor de estado Uptime Kuma autoalojado num host separado avisa-o antes dos seus membros.
Quando o Discourse é a escolha errada
O Discourse é uma aplicação grande, com uma instalação pesada e um ciclo de rebuild para cada definição que fica em app.yml. Esse custo proporciona ferramentas de moderação completas e uma pesquisa que continua a funcionar quando o arquivo é grande. Para trinta pessoas que apenas precisam de um espaço para conversar, é mais máquina do que a conversa necessita. Leia primeiro a comparação de software de fóruns self-hosted e escolha o Discourse porque precisa do que ele oferece, não por ser o nome que já conhecia.
FAQ
Posso instalar o Discourse num VPS sem um nome de domínio?
Não. A configuração distribuída indica que o Discourse não funciona com um endereço IP simples, e DISCOURSE_HOSTNAME é obrigatório. O Discourse cria links absolutos a partir desse nome de anfitrião, por isso um endereço IP nesse campo quebra os links e impede a emissão do certificado. Crie um registo A antes de começar e confirme com dig +short forum.example.com se ele resolve para o endereço do seu servidor.
Tenho de configurar o SMTP para concluir a instalação?
A partir de agosto de 2026, pode ignorá-lo. O assistente de configuração disponibiliza, em alternativa, logins do Discourse ID, e app.yml inclui uma opção que ignora a validação da configuração de email. Para qualquer utilização além de uma primeira avaliação, configure-o, porque a ativação de contas e as reposições de palavra-passe são enviadas por email. Use um relay autenticado na porta 587 ou 465, porque a maioria dos fornecedores de VPS bloqueia a porta 25 de saída.
Porque falhou a reconstrução do meu Discourse a meio?
A memória é a causa mais comum. A compilação de recursos durante a compilação precisa de mais memória do que o site em execução, por isso um servidor que serve o fórum sem problemas pode ainda assim falhar ao reconstruí-lo. Se dmesg mostrar Out of memory: Killed process com o nome de um processo Ruby, adicione swap (o ficheiro de swap do próprio assistente tem 2 GB) e execute ./launcher rebuild app novamente. Uma compilação que para devido a um erro YAML aponta, em vez disso, para um erro de indentação em app.yml.
O Discourse deve ficar atrás do meu próprio Nginx ou Caddy?
Apenas quando o VPS também aloja outros sites. Se estiver sozinho no servidor, deixe o contentor manter as portas 80 e 443 e emitir o seu próprio certificado. Isto reduz o número de componentes envolvidos. Para partilhar a máquina, adicione templates/web.socketed.template.yml, comente as linhas expose e encaminhe o tráfego para o socket Unix em /var/discourse/shared/standalone/nginx.http.sock. Encaminhe X-Forwarded-Proto, caso contrário o Discourse gera links http:// numa página HTTPS.
Como faço uma cópia de segurança de um Discourse autoalojado?
Use a página Backups no Admin ou execute discourse backup depois de ./launcher enter app. Os arquivos ficam no anfitrião em /var/discourse/shared/standalone/backups/default/. Confirme que a opção que inclui os uploads está ativada, copie /var/discourse/containers/app.yml juntamente com o arquivo e transfira ambos para outra máquina, porque uma cópia de segurança no mesmo disco do site não sobrevive à falha para a qual foi criada.