Migrar para a Zenifra

Migrar do Heroku para a Zenifra

Este guia mostra onde encontrar cada configuração de um app no Heroku e onde informar o mesmo valor no console da Zenifra. Ele cobre o Procfile, as Config Vars, os buildpacks, a release phase, o Heroku Scheduler, o Heroku Postgres e o Heroku Key-Value Store. Para o roteiro geral, com cópia de dados e troca de DNS, veja Migrar para a Zenifra.

Mantenha o app do Heroku no ar enquanto você sobe e valida a aplicação na Zenifra. Só desligue os dynos depois de trocar o DNS.

Como os conceitos se traduzem

No HerokuNa Zenifra
AppProjeto HTTP
Processo web do ProcfileComando Start do projeto
Processo worker (ou outro nome)Outro projeto com o mesmo repositório, Exposição Privado e o comando do worker
Release phase (release:)Início do Comando Start ou um passo manual; veja Release phase
BuildpackRuntime e Versão (Node.js, Python, Bun, Go ou Java) ou Imagem OCI
Config VarsVariáveis de Ambiente
Quantidade de dynos webInstâncias Desejadas ou auto-scaling
Heroku SchedulerJobs agendados
Heroku PostgresPostgreSQL gerenciado
Heroku Key-Value StoreCache gerenciado ou Chave-Valor
Review AppsAmbientes de Preview
heroku maintenance:onUse no Heroku durante a cópia final dos dados

1. Copie as configurações no Heroku

Os passos abaixo usam a CLI do Heroku. Troque meu-app pelo nome do app.

Config Vars

No painel do Heroku, as Config Vars ficam na aba Settings do app. Para exportar todas de uma vez:

heroku config --shell -a meu-app > heroku.env

Use --json no lugar de --shell se preferir JSON. O arquivo tem segredos: não versione e apague depois da migração.

Ao revisar o arquivo:

  • DATABASE_URL e REDIS_URL foram criadas pelos add-ons e apontam para os bancos do Heroku. Na Zenifra, troque pelas URLs dos bancos novos.
  • Variáveis com prefixo HEROKU_ são da plataforma. Só copie se o seu código usa alguma delas, com um valor equivalente.
  • Variáveis de outros add-ons, como serviços de e-mail ou monitoramento, continuam valendo se você manter a conta no provedor do add-on.

Procfile

Abra o Procfile na raiz do repositório. Cada linha é tipo: comando:

Procfile
release: bundle exec rails db:migrate
web: bundle exec puma -C config/puma.rb
worker: bundle exec sidekiq

Anote o comando de cada tipo. Sem Procfile, o Heroku usa o padrão do buildpack, como o script start do package.json no Node.js.

Veja também quantos dynos de cada tipo estão ligados:

heroku ps -a meu-app

Buildpacks e versão da linguagem

heroku buildpacks -a meu-app

O buildpack da linguagem principal define o Runtime na Zenifra. A versão vem do próprio repositório:

LinguagemOnde o Heroku lê a versão
Node.jsengines.node no package.json
Python.python-version (ou runtime.txt, que o Heroku considera obsoleto)
GoLinha go do go.mod
Javajava.runtime.version no system.properties
RubyEntrada ruby no Gemfile

Domínios, deploy e Scheduler

  • Domínios: heroku domains -a meu-app lista os domínios e o destino DNS de cada um.
  • Deploy: na aba Deploy do app, veja se a integração com o GitHub está com Automatic deploys ligado e qual branch é publicada.
  • Scheduler: heroku addons:open scheduler -a meu-app abre a lista de tarefas agendadas. Anote o comando e a frequência de cada uma.
  • app.json: se o repositório tem um app.json, ele lista variáveis, add-ons e scripts usados pelos Review Apps.

2. Crie o projeto na Zenifra

No console, clique em + Criar projeto, escolha Aplicação HTTP e o plano. Em Configurações Avançadas, escolha Repositório Git em Origem do Projeto, o Provedor Git GitHub (ou Forgejo), o mesmo repositório e a branch publicada no Heroku.

No HerokuNo console da Zenifra
Buildpack da linguagemRuntime
Versão no repositórioVersão, a mesma principal
Pasta do app no repositórioDiretório raiz. Use . para a raiz
Build automático do buildpackComando Build; veja a tabela abaixo
Linha web: do ProcfileComando Start
$PORTPorta e a variável PORT com o mesmo valor; veja Porta
Automatic deploys ligadoModo de deploy Automático por branch
Automatic deploys desligadoModo de deploy Manual
Config VarsVariáveis de Ambiente
Quantidade de dynos webInstâncias Desejadas

Comandos por linguagem

O Heroku roda alguns passos de build sozinho. Na Zenifra, cada passo fica explícito nos campos do projeto:

LinguagemComando BuildComando Start
Node.jsnpm run build se o package.json tem script build; vazio se não temLinha web: do Procfile ou npm start
Python (Django)python manage.py collectstatic --noinputgunicorn projeto.wsgi --bind 0.0.0.0:8000
Python (Flask, FastAPI)vazioLinha web: com --bind 0.0.0.0:8000 ou --host 0.0.0.0 --port 8000
Gogo build -o app ./cmd/server (pasta do pacote main)./app
Java (Maven)./mvnw -B -DskipTests package ou mvn -B -DskipTests packagejava -jar target/*.jar

Detalhes de cada runtime estão em Runtimes, Python, Django e APIs Node.js.

Node.js: scripts do Heroku

  • Scripts heroku-prebuild, heroku-build e heroku-postbuild não rodam na Zenifra. Coloque o que eles faziam no Comando Pré-build ou no Comando Build.
  • A Zenifra instala com npm ci e precisa de um package-lock.json versionado. Se o app usa Yarn ou pnpm, gere e versione um package-lock.json antes de migrar. Veja Dependências Node.js.
  • NPM_CONFIG_PRODUCTION não é necessária: as devDependencies ficam disponíveis na build.

Python: Poetry, uv e Pipenv

A Zenifra instala dependências Python a partir do requirements.txt. Se o Heroku usava poetry.lock, uv.lock ou Pipfile.lock, exporte e versione um requirements.txt:

poetry export -f requirements.txt --output requirements.txt
uv export --format requirements-txt > requirements.txt

Ruby, PHP e outras linguagens

Ruby, PHP, .NET e outras linguagens fora dos runtimes acima são publicadas como Imagem Docker: construa a imagem a partir de um Dockerfile, envie para um registry e informe a imagem no projeto. Veja Dockerfiles prontos e Deploy via imagem OCI. A GitHub Action automatiza a build e o deploy a cada push.

3. Ajuste o que muda entre as plataformas

Porta

No Heroku, o processo web escuta na porta da variável PORT, escolhida pela plataforma. Na Zenifra, a porta é o campo Porta do projeto. Como o código já lê PORT, defina os dois com o mesmo valor, por exemplo Porta 3000 e a variável PORT=3000. A aplicação precisa escutar em 0.0.0.0.

Release phase

No Heroku, a linha release: roda uma vez por release, antes de os dynos subirem. Na Zenifra não há uma etapa equivalente. Escolha uma destas opções:

  • Junto do start: npx prisma migrate deploy && npm start ou python manage.py migrate && gunicorn .... O comando roda a cada vez que uma instância inicia, então precisa ser idempotente, como as migrations da maioria dos frameworks. Com várias instâncias, todas executam o comando: prefira ferramentas que travam o banco durante a migration.
  • Manual: rode a migration a partir da sua máquina, apontando para o banco da Zenifra, antes de publicar a versão que depende dela. É o mais seguro para migrations longas.

Workers

Cada tipo de processo do Procfile além do web vira um projeto na Zenifra:

  1. Crie outro projeto HTTP com o mesmo repositório e a mesma branch.
  2. Em Exposição, escolha Privado - sem rota pública.
  3. Use o comando do worker no Comando Start, como bundle exec sidekiq ou celery -A app worker.
  4. Cadastre as mesmas variáveis do projeto web.

O processo clock, que agenda tarefas dentro de um dyno, pode virar um projeto privado do mesmo jeito ou ser trocado por Jobs agendados.

Heroku Scheduler

Cada tarefa do Scheduler vira um Job agendado. Crie o Job com Origem da tarefa Repositório GitHub, o mesmo Runtime, o comando da tarefa em Comando da tarefa e as variáveis de que ela precisa.

Frequência no SchedulerExpressão cron na Zenifra
A cada 10 minutos*/10 * * * *
A cada hora, no minuto 3030 * * * *
Todo dia às 06:00 UTC0 6 * * *

As duas plataformas usam UTC. Na Zenifra, a expressão cron aceita qualquer horário, como 0 9 * * 1-5 para dias úteis às 09:00 UTC.

Arquivos enviados por usuários

No Heroku, arquivos gravados no disco do dyno somem quando ele reinicia. Na Zenifra, você pode guardar arquivos no armazenamento persistente ou no Armazém, compatível com S3. Se o app já usa um bucket S3, ele continua funcionando com as mesmas variáveis.

HTTPS e proxy

Como no Heroku, a Zenifra encerra o HTTPS antes de encaminhar a requisição. Mantenha as configurações de proxy confiável do framework, como app.set('trust proxy', 1) no Express, config.force_ssl no Rails ou --proxy-headers no uvicorn.

4. Migre os bancos

Heroku Postgres

Crie o PostgreSQL gerenciado na Zenifra antes da aplicação. Para copiar os dados, você pode usar um backup do Heroku:

heroku pg:backups:capture -a meu-app
heroku pg:backups:download -a meu-app   # gera latest.dump
pg_restore --list latest.dump > /dev/null && echo "dump ok"

E restaurar na Zenifra com a URI do console:

pg_restore --no-owner --no-acl --jobs=4 \
  --dbname="postgresql://usuario:senha@host:porta/banco?sslmode=verify-full&sslrootcert=system" \
  latest.dump

O próprio Heroku recomenda os backups para bancos de até 20 GB. Para bancos maiores, ou para fazer a cópia direto, pegue a URL do banco do Heroku e use pg_dump:

heroku pg:credentials:url DATABASE -a meu-app
pg_dump --format=custom --no-owner --no-acl "URL_DO_HEROKU?sslmode=require" > dump.pgdump

Use um pg_dump da mesma versão principal do banco ou mais nova. Veja Migrar o banco de dados para validar a cópia.

Heroku Key-Value Store

Crie um cache gerenciado ou um banco Chave-Valor na Zenifra e troque a REDIS_URL. Dados de cache e de sessões costumam ser recriados pela aplicação. Se o Key-Value Store guarda filas, como as do Sidekiq ou do Celery, deixe os workers do Heroku esvaziarem a fila antes da troca.

5. Valide e troque o DNS

  1. Abra a URL *.clients.zenifra.com do projeto e teste login, fluxos principais, e-mails, workers e webhooks.
  2. Confira em Logs de build e nos logs da aplicação se não há erros.
  3. No horário da troca, ligue o modo de manutenção do Heroku para congelar as escritas: heroku maintenance:on -a meu-app.
  4. Faça a cópia final do banco, adicione o domínio na Zenifra e atualize o DNS. Siga o checklist do dia da troca.
  5. Mantenha o app do Heroku por alguns dias para rollback. Depois, desligue os dynos e remova os add-ons para parar a cobrança.

Problemas comuns

SintomaCausa provávelCorreção
npm ci falhaApp usa Yarn ou pnpm, sem package-lock.jsonGere e versione um package-lock.json
Build Python não instala dependênciasProjeto usa Poetry, uv ou PipenvExporte um requirements.txt
URL pública não respondeApp escuta em localhost ou em outra portaEscute em 0.0.0.0, na porta do campo Porta, e defina PORT
Tabelas não existemA release phase não roda na ZenifraRode as migrations; veja Release phase
Tarefas em segundo plano paradasWorker não foi criadoCrie um projeto privado para cada processo além do web
assets ou staticfiles faltandoO buildpack fazia esse passo sozinhoColoque o comando, como collectstatic ou assets:precompile, no Comando Build

Precisa de ajuda?

Escreva para [email protected] com o seu Procfile e a lista de add-ons ou fale pelo WhatsApp +55 (11) 5199-3013.

Última atualização em

Nessa página