Como fazer deploy de Docker sem precisar administrar um servidor
Siga isso no seu próprio servidor. Comece grátis, sem cartão
docker build funciona. docker run -p 3000:3000 myapp funciona no seu notebook. O que ainda não existe é tudo que fica entre “esse container roda” e “isso é um serviço de produção”: um reverse proxy na frente dele, um certificado que se renova sozinho, um processo que reinicia depois de travar, um servidor cujo sistema operacional recebe patches, e algo ou alguém observando se está mesmo no ar. Nada disso é específico da sua aplicação. Tudo isso é específico de rodar um servidor, que é justamente a parte que muita gente com um Dockerfile funcionando preferiria não aprender do zero.
Este guia é pra essa situação: você tem um Dockerfile, ele builda, e você quer ele rodando em produção sem se tornar a pessoa que mantém uma máquina Linux. Ele cobre o que “administrar um servidor” de fato envolve, a versão manual de fazer isso você mesmo (em resumo, porque não é esse o ponto), e depois o caminho que elimina essa parte.
O que “administrar um servidor” realmente significa
Cada um desses pontos, isolado, é um problema pequeno e bem conhecido. Juntos, pra um único container, representam uma quantidade de trabalho contínuo desproporcional:
- Atualizações do SO. Patches de segurança da própria instalação base de Ubuntu ou Debian, independente de qualquer coisa no seu Dockerfile, precisam ser aplicados numa certa cadência, e alguns deles exigem reboot pra valer.
- Instalar e manter o Docker. O Docker Engine no host é um software em si, com seu próprio caminho de upgrade, separado de qualquer imagem que você roda em cima dele.
- Um reverse proxy. Algo precisa terminar o HTTPS e repassar requisições pra porta do seu container; isso é configuração de nginx ou Caddy, escrita e mantida em sincronia com sua aplicação na mão.
- Renovação de certificado. Certificados do Let’s Encrypt expiram a cada 90 dias. Algo precisa pedir o primeiro, provar a propriedade do domínio e renová-lo antes que vença, indefinidamente, sem que ninguém precise lembrar de fazer isso.
- Monitoramento. Saber que o container está de fato servindo tráfego, não só que o
docker psmostra ele rodando, exige algo checando de fora da máquina. - Política de restart e regras de firewall. Uma falha precisa trazer o processo de volta sem um humano entrando via SSH, e a máquina precisa ter abertas pra internet só as portas que ela realmente serve.
Nada disso é difícil isoladamente. É o tipo de trabalho que fica invisível até a semana em que para de ser: um certificado expira silenciosamente, um CVE sem patch fica aberto por meses, ou uma falha às 2 da manhã simplesmente continua travada.
A versão manual, em resumo
Numa VPS Ubuntu 24.04, isso é Docker mais Caddy como reverse proxy:
curl -fsSL https://get.docker.com | sh
Um Caddyfile na frente do container:
myapp.example.com {
reverse_proxy localhost:3000
}
docker run -d --name myapp --restart unless-stopped -p 3000:3000 --env-file .env myapp:latest
caddy run --config Caddyfile
O Caddy pede e renova seu próprio certificado Let’s Encrypt automaticamente assim que o DNS aponta pro servidor e as portas 80/443 estão acessíveis, o que cobre a renovação de certificado. O --restart unless-stopped cobre a parte de recuperação de falhas. O que fica de fora, e o que essa versão resumida não resolve, é tudo da lista acima que não é o container em si: patches do SO numa cadência, os próprios upgrades do Docker, regras de ufw mantidas em sincronia com o que realmente está rodando, e algo externo checando se o site está mesmo acessível, nada disso vem de rodar Caddy e Docker corretamente.
O caminho que resolve o resto
Aponte o Railyard pro mesmo repositório, ou pra uma imagem já existente. A detecção de build do Railyard escolhe um Dockerfile automaticamente quando o repositório tem um que de fato builda a aplicação; uma imagem de desenvolvimento que só espera um bind mount é ignorada em vez de implantada; veja métodos de build. Pra uma imagem que já está num registro em vez de num repositório, image://ghcr.io/you/myapp:latest como origem funciona do mesmo jeito, e a porta que seu Dockerfile expõe via EXPOSE é lida direto do registro, sem configuração manual de porta; veja fazendo deploy de uma imagem Docker.
O que esse único passo substitui, em relação à lista manual acima:
- O reverse proxy e o certificado TLS não são algo que você escreve. Toda aplicação recebe
https://<name>.<server-ip>.sslip.iocom um certificado imediatamente; apontar seu próprio domínio pra ela adiciona um registro de DNS e uma verificação de propriedade (um registro TXT que o Railyard confere antes de emitir qualquer coisa, então ninguém consegue apontar um domínio que não controla pra sua aplicação), e o certificado a partir daí é automático. Veja domínios e HTTPS. - Atualizações do SO aparecem na própria página do servidor, com uma contagem de atualizações pendentes e quantas são especificamente de segurança; atualizações de segurança noturnas se aplicam sem intervenção, e nada reinicia a máquina sem você escolher isso. Veja manutenção de servidor.
- Política de restart não é uma flag que você precisa lembrar de adicionar. É simplesmente como o container de qualquer aplicação roda.
- Os próprios deploys não causam downtime: um container novo é baixado ou buildado, o comando de release (se você configurou um) roda, e o tráfego só troca pra ele quando o container novo de fato responde, o mesmo formato sem downtime, seja a imagem que mudou ou o código.
- Uma imagem baseada em registro que atualiza a própria tag pode fazer redeploy automaticamente: ative Deploy when the tag changes em Settings → Source, e o Railyard confere o registro a cada cinco minutos (ou instantaneamente, via um webhook que você adiciona ao registro) e refaz o deploy quando o digest muda, então dar
docker pushnuma novalatesté todo o processo de release. Veja fazendo deploy de uma imagem Docker.
Uma coisa que vale deixar precisa: o Railyard não é uma plataforma de containers serverless que possui o hardware por você. Você ainda adiciona um servidor, seja um que ele cria na sua conta DigitalOcean, Hetzner, Vultr, AWS ou OVH, seja qualquer máquina Ubuntu 22.04/24.04 que você já tem acesso SSH, e seu provedor de nuvem cobra você direto pela máquina em si. Veja adicionar um servidor. O que desaparece é tudo que fica em cima de possuir essa máquina: instalar o Docker nela, escrever e manter a configuração do reverse proxy, pedir e renovar certificados, e dar patch no SO na mão.
Variáveis e secrets
O que quer que seu container leia do ambiente, configure na aba Variables da aplicação; os valores são criptografados e aplicados no próximo deploy. Se sua imagem precisa de uma credencial que genuinamente tem que ser um arquivo em vez de uma variável (um JSON de service account, um certificado de cliente), Variables → File secrets monta ele como somente leitura dentro do container e expõe o caminho como uma variável de ambiente, então GOOGLE_APPLICATION_CREDENTIALS=${RAILYARD_SECRET_FILE_GCP_KEY_JSON} resolve sem precisar copiar o arquivo pro servidor na mão. Veja variáveis e secrets.
Solução de problemas
O deploy dá certo, mas a aplicação nunca aparece no domínio. Confira o status do domínio na aba Domains da aplicação: unverified significa que o registro TXT de propriedade ainda não foi encontrado (propagação de DNS, ou um erro de digitação no registro), misconfigured significa que a emissão do certificado falhou e o card explica por quê, e unrouted significa que o domínio foi verificado mas a aplicação não fez redeploy desde então, o que um redeploy resolve.
Um Dockerfile que funciona localmente falha ao buildar. A diferença mais comum entre builds locais e builds no Railyard é uma imagem que assume um diretório de código montado via bind mount em vez de fazer COPY da aplicação pra dentro da imagem; esse padrão é exatamente o que a detecção de build do Railyard trata como imagem de desenvolvimento e ignora. Confirme que o Dockerfile builda uma imagem autossuficiente com docker build . e sem flags -v antes de investigar mais.
O build fica sem memória. Builds grandes são automaticamente encaixados num servidor de build temporário e maior quando o provedor permite, então isso é raro, mas quando acontece a página de deploy avisa diretamente e sugere o próximo passo em vez de falhar silenciosamente.
Perguntas frequentes
Eu ainda preciso saber Docker? Sim, no sentido de que você ainda escreve o Dockerfile; o que isso elimina é tudo que vem depois de uma imagem funcionando, não a imagem em si. Se seu Dockerfile já builda e roda localmente, essa parte do trabalho está feita.
Isso é o mesmo que uma plataforma de containers serverless como o Cloud Run? Não. Essas plataformas rodam seu container numa infraestrutura que elas possuem e cobram por requisição ou por segundo de compute. O Railyard roda ele num servidor que você adiciona à sua própria conta de nuvem (ou numa máquina que você já tem), cobrado pelo seu provedor, e automatiza o que rodar um servidor em cima dessa máquina envolve.
E se minha imagem precisar de mais de uma porta, como um endpoint de métricas junto da aplicação principal? Settings → General → More public ports aceita pares name:port adicionais, cada um recebendo seu próprio endereço HTTPS e certificado do mesmo jeito que o principal; veja networking.
Meu container precisa rodar como root? Não, e é melhor que não rode; isso é uma característica do seu próprio Dockerfile, não algo que o Railyard exige de um jeito ou de outro. Uma configuração separada e opcional, Hardened isolation, em Settings → General, restringe ainda mais o que um container pode alcançar num servidor compartilhado com outras aplicações, vale testar contra uma imagem que não assume root.
O que acontece de fato num deploy, passo a passo? A imagem é baixada ou buildada, qualquer comando de release que você configurou roda contra ela, e só quando o container novo responde é que o tráfego troca pra ele; o container antigo continua no ar até essa transição dar certo, então um deploy ruim não derruba a versão anterior que estava funcionando.
O Dockerfile nunca foi a parte difícil. Tudo que vem depois dele, a máquina onde ele roda continuar com patches, o certificado continuar válido, e o processo voltar depois de travar, é o que “administrar um servidor” significa na prática, e também é a parte que não tem nada a ver com o que seu container realmente faz.
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.