Skip to content

Kamal ou PaaS? Onde fazer deploy de uma app Rails 8 em 2026

TL;DR

Para a maioria das apps Rails 8 em 2026, Kamal em uma ou duas VPS é o padrão que vale testar primeiro: vem com o Rails, custa uma fração de um PaaS e já está maduro. Escolha uma plataforma gerenciada quando ninguém no time quiser cuidar de backups, patches e plantão do próprio servidor.

O Heroku entrou em modo manutenção e o Rails 8 já vem com o Kamal. Veja como decidir entre sua própria VPS e uma plataforma gerenciada, com um deploy.yml pronto para produção.

Publicado em 8 min de leitura

Também disponível em English

Compartilhar

Duas coisas mudaram a conversa sobre deploy de Rails. Em 6 de fevereiro de 2026, o Heroku anunciou a transição para um "sustaining engineering model": a plataforma continua com suporte, mas não terá novas funcionalidades nem novos contratos Enterprise para novos clientes. Enquanto isso, o Kamal, que já vem em toda app Rails 8 nova, chegou à versão 2.12 em junho, com suporte nativo a OpenTelemetry nos logs de deploy.

Então a pergunta para uma app nova, ou para uma app no Heroku procurando a próxima casa, não é mais "qual PaaS?". É "eu quero ter um servidor ou não?"

Recentemente migrei este blog para Kamal em uma única VPS, com Postgres rodando como accessory do Kamal e imagens no Docker Hub. Este post é o framework de decisão que eu gostaria de ter tido antes de começar.

A resposta curta

  • Kamal na sua própria VPS se alguém do time domina Linux, SSH e backups, e você quer custo previsível.
  • Um PaaS gerenciado (Render, Fly.io, Heroku) se ninguém quer ser acordado porque um disco encheu, ou se você precisa de Postgres gerenciado com point-in-time recovery desde o primeiro dia.
  • Sua própria conta na nuvem (ECS, Beanstalk) se você já está na AWS com requisitos de compliance, VPC peering e um time de plataforma. O Kamal também faz deploy em EC2, mas os serviços gerenciados da AWS trazem autoscaling e integração com IAM.

O que o Kamal realmente entrega

O Kamal não é uma plataforma, é uma ferramenta de deploy. Ele acessa seus hosts via SSH, baixa a imagem Docker que você construiu, sobe o novo container, espera o health check e troca o tráfego pelo kamal-proxy sem downtime. O kamal-proxy também cuida dos certificados Let's Encrypt.

O que o Rails 8 já traz pronto:

  • Um Dockerfile de produção com jemalloc e Thruster na frente do Puma
  • config/deploy.yml e .kamal/secrets
  • A rota de health check /up
  • Solid Queue, Solid Cache e Solid Cable, então você não precisa de Redis para jobs, cache ou Action Cable

Esse último ponto importa mais que o próprio Kamal. Uma app Rails 8 com o trio Solid precisa de um container web e um banco de dados. Só isso. Menos peças móveis é o que torna uma única VPS realista.

O que um PaaS entrega e o Kamal não

Seja honesto com esta lista antes de escolher:

  1. Banco gerenciado. Backups automáticos, point-in-time recovery, failover, upgrades de versão menor. Com um accessory do Kamal, tudo isso é com você.
  2. Patches do sistema operacional. Alguém precisa rodar unattended-upgrades e reiniciar para correções de kernel.
  3. Autoscaling horizontal. O Kamal faz deploy nos hosts que você lista. Mais capacidade significa provisionar uma máquina e editar o deploy.yml.
  4. Observabilidade integrada. Log drains, métricas e alertas são um checkbox num PaaS. Numa VPS você mesmo configura o agente de APM e o envio de logs.
  5. Sem ponto único de falha por padrão. Uma VPS é uma máquina. Se ela morrer, você fica fora do ar até reconstruir.

Nada disso é difícil. É apenas trabalho, e num PaaS outra pessoa faz esse trabalho por você.

Um deploy.yml de produção

Este é próximo do que roda este blog: um host web, Postgres como accessory na mesma máquina, Solid Queue dentro do Puma.

service: myapp
image: myuser/myapp

servers:
  web:
    - 203.0.113.10

proxy:
  ssl: true
  host: myapp.com

registry:
  username: myuser
  password:
    - KAMAL_REGISTRY_PASSWORD

builder:
  arch: amd64

env:
  secret:
    - RAILS_MASTER_KEY
    - POSTGRES_PASSWORD
  clear:
    SOLID_QUEUE_IN_PUMA: true
    DB_HOST: myapp-db
    WEB_CONCURRENCY: 2

volumes:
  - "myapp_storage:/rails/storage"

asset_path: /rails/public/assets

accessories:
  db:
    image: postgres:17
    host: 203.0.113.10
    port: "127.0.0.1:5432:5432"
    env:
      clear:
        POSTGRES_USER: myapp
        POSTGRES_DB: myapp_production
      secret:
        - POSTGRES_PASSWORD
    directories:
      - data:/var/lib/postgresql/data

E o .kamal/secrets:

KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
RAILS_MASTER_KEY=$(cat config/master.key)
POSTGRES_PASSWORD=$POSTGRES_PASSWORD

Alguns detalhes que pegam muita gente:

  • DB_HOST: myapp-db: accessories entram na rede Docker kamal como <service>-<accessory>. Seu database.yml deve ler ENV["DB_HOST"].
  • Faça o bind do banco em 127.0.0.1. Publicar a 5432 em todas as interfaces coloca o Postgres na internet, e as regras de iptables do Docker passam por cima do UFW.
  • asset_path mantém os assets antigos com fingerprint disponíveis durante a troca, então quem está navegando no meio do deploy não recebe 404 no CSS.
  • builder.arch: amd64 importa no Apple Silicon. Sem isso, você gera uma imagem ARM para um servidor x86. Use um remote builder se a emulação local for lenta demais.

O primeiro deploy é kamal setup. Depois disso, kamal deploy. kamal app logs -f e kamal console (se você mantiver os aliases padrão) cobrem o dia a dia.

As partes que agora são suas

Se for de Kamal, faça isto no primeiro dia, não depois do primeiro incidente:

Backups fora da máquina. Um pg_dump noturno enviado para o S3 (ou qualquer object storage) é o mínimo. Teste um restore. Um banco como accessory sem backup externo está a um disco de perder tudo.

Active Storage fora da máquina. O volume myapp_storage serve para SQLite ou uma app de brinquedo. Para uploads de usuários em produção, aponte o Active Storage para o S3 e mantenha o servidor descartável.

Monitoramento. Envie métricas da app com o APM de sua preferência e adicione um uptime check externo no /up. O suporte a OpenTelemetry do Kamal 2.12 cobre os logs de deploy, não a telemetria da aplicação.

Patches. Ative atualizações de segurança automáticas e agende reboots. Mantenha o SSH só com chave.

Simulado de reconstrução. Uma vez, provisione uma VPS nova e faça deploy do zero. Se levar uma hora, seu RTO é uma hora.

Custo, por alto

Não vou citar preços exatos, porque eles mudam a cada poucos meses. O formato é estável: uma VPS intermediária na Hetzner, DigitalOcean ou similar costuma custar mais ou menos o mesmo que um dyno web pequeno somado a um banco gerenciado pequeno num PaaS, mas entrega várias vezes mais CPU e RAM. A diferença cresce conforme você adiciona workers e memória, porque num PaaS cada tipo de processo é cobrado separado e numa VPS todos dividem a máquina.

O custo escondido é o seu tempo. Se você cobra por hora, duas horas por mês cuidando do servidor podem apagar a economia de uma app pequena.

Saindo do Heroku para o Kamal: checklist

  1. Atualize para Rails 8 (ou adicione Kamal e um Dockerfile a uma app 7.1+ com bundle add kamal && kamal init).
  2. Troque as peças que dependem de Redis por Solid Queue, Solid Cache e Solid Cable se quiser um setup de dois containers. O Sidekiq continua funcionando bem como um role separado no Kamal, se preferir.
  3. Transforme seu Procfile em roles do Kamal: web, e job com cmd: bin/jobs se você não roda jobs dentro do Puma.
  4. Mova as config vars para o .kamal/secrets (vindas do 1Password, Bitwarden ou variáveis de ambiente, nunca commitadas).
  5. pg_dump do Heroku Postgres, pg_restore no accessory ou num banco gerenciado.
  6. Reduza o TTL do DNS um dia antes, faça o deploy, valide e só então troque o registro.
  7. Mantenha a app do Heroku com escala mínima, mas viva, por uma semana como caminho de rollback.

Onde um PaaS ainda ganha

Não deixe o entusiasmo com o Kamal te empurrar para cuidar de servidores que você não quer. Um PaaS é a melhor escolha quando:

  • Ninguém no time quer plantão de infraestrutura.
  • Você precisa de Postgres gerenciado com PITR e alta disponibilidade e não quer pagar um banco gerenciado separado ao lado da VPS (que, aliás, é um ótimo meio-termo).
  • O tráfego tem picos grandes o suficiente para o autoscaling economizar dinheiro de verdade.
  • Você precisa de latência multi-região, onde o modelo do Fly.io é realmente difícil de replicar com Kamal.

O Heroku em si não vai sumir amanhã. "Sustaining engineering" significa estável, não morto. Mas para uma app nova, escolher uma plataforma que parou publicamente de criar funcionalidades é difícil de justificar quando Render e Fly.io seguem em desenvolvimento ativo.

Minha recomendação

Comece apps Rails 8 novas com Kamal em uma VPS, um job de backup fora da máquina e S3 para uploads. Coloque o banco num serviço gerenciado no momento em que perder uma hora de dados passar a doer no negócio. Migre para um PaaS, ou para ECS na sua própria conta AWS, quando o tempo gasto com o servidor custar mais do que a fatura que você está evitando.

Fontes

  1. An Update on Heroku (blog do Heroku, 6 de fevereiro de 2026) www.heroku.com
  2. Simon Willison sobre o anúncio de sustaining engineering do Heroku simonwillison.net
  3. Releases do Kamal (v2.12.0) github.com
  4. Documentação do Kamal kamal-deploy.org

Perguntas frequentes

O Kamal está pronto para produção em 2026?

Sim. O Kamal vem em toda app Rails 8 nova, a 37signals roda os próprios produtos nele, e a versão 2.12 adicionou logs de deploy com OpenTelemetry, retry do lock de deploy e a opção stop_timeout.

O Heroku vai acabar?

Não. Em fevereiro de 2026 o Heroku passou para um modelo de sustaining engineering: continua com suporte, mas não desenvolve novas funcionalidades nem assina novos contratos Enterprise com novos clientes.

Posso rodar Postgres com o Kamal?

Sim, como um container accessory. Faça o bind em 127.0.0.1, conecte pelo hostname da rede Docker kamal e envie backups com pg_dump para fora do servidor. Para dados críticos, um banco gerenciado é mais seguro.

Preciso de Redis para fazer deploy de Rails 8 com Kamal?

Não. Solid Queue, Solid Cache e Solid Cable usam o seu banco, então um container web mais o Postgres bastam. Sidekiq e Redis continuam funcionando como roles e accessories extras no Kamal.

Comentários

Faça login com GitHub para comentar.

Ainda não há comentários.