O que você leva
Três scripts bash curtos, um helper de alertas compartilhado e os arquivos de configuração para ligar tudo. Dá para ler em dez minutos, e não há nada para instalar além das ferramentas que eles chamam.
| Arquivo | O que faz |
|---|---|
deploy.sh | Clona uma release, faz o build, roda o health check e dá rollback se algo falhar. Tem dois modos: restart (symlink mais restart do pm2) e bluegreen (zero requisições com falha no teste abaixo). No modo blue/green, deploy.sh rollback volta para a release anterior. |
backup.sh | Faz o dump dos bancos SQLite e Postgres do jeito seguro, depois roda o backup com restic (por padrão 7 diários, 4 semanais e 6 mensais) e verifica o repositório. Um dump corrompido interrompe a execução antes de qualquer snapshot. |
restore-test.sh | Restaura o último snapshot em um diretório temporário, confere os dumps dos bancos, roda uma verificação sua (opcional) e lê uma amostra dos dados. |
notify.sh | Manda uma mensagem no Telegram ou um POST de webhook quando qualquer script falha. Em silêncio quando tudo dá certo. |
| Configuração | kit.env.example, Caddyfile.example, ecosystem.config.js, cron.example |
Deploy sem downtime, com medições
No modo bluegreen, a nova release sobe na porta ociosa e passa por health check direto. Só então o Caddy é trocado para ela, com um reload graceful, e a release antiga é parada por último. Uma release que não está saudável nunca recebe tráfego.
Ambiente do teste: container Debian 12, Caddy 2.6.2 instalado via apt, pm2, um app Node que leva 1.5 segundos para subir e uma carga de 20 requisições por segundo passando pelo Caddy durante todo o deploy (uma a cada cinco requisições vai para um endpoint de 300 ms). Contamos como falha qualquer erro de conexão, timeout acima de 3 segundos ou status diferente de 200.
| Cenário | Requisições | Falhas | Tempo do deploy |
|---|---|---|---|
Modo restart, release boa | 116 | 32 (todas HTTP 502) | 2.4 s |
Modo restart, release quebrada (com rollback) | 380 | 67 (todas HTTP 502) | 16.8 s |
bluegreen, release boa | 211 | 0 | 7.6 s |
bluegreen, release quebrada (health retorna 500) | 373 | 0 | 16.6 s |
bluegreen, release que cai ao iniciar | 371 | 0 | 16.5 s |
bluegreen, rollback | 208 | 0 | 7.5 s |
No deploy blue/green bem-sucedido, a carga passou pelas duas versões (115 respostas da v1, depois 96 da v2), então o tráfego mudou de verdade. Em várias execuções, o modo restart falhou de 31 a 35 requisições, e o blue/green não falhou nenhuma.
Backups que você já restaurou
- Os bancos são exportados do jeito certo. O SQLite usa o backup online e uma checagem de integridade. O Postgres usa
pg_dump -Fcepg_restore -l. Copiar o arquivo de um banco em uso é a receita clássica de backup corrompido. - Dump ruim interrompe a execução. No teste, um arquivo SQLite corrompido abortou o backup sem criar snapshot.
- Dump antigo não volta escondido. Um banco que você tirou da configuração não continua aparecendo nos snapshots novos.
- O
restore-test.shcomprova. Ele restaura, confere os dumps e rodarestic checkem uma amostra. Agende uma vez por semana no cron. - Repositório remoto. Repositórios
sftp:funcionam nos dois scripts (testados contra um servidor OpenSSH local).
Alertas de falha
Defina TELEGRAM_BOT_TOKEN e TELEGRAM_CHAT_ID, ou NOTIFY_WEBHOOK_URL. Um deploy, backup ou teste de restauração que falha manda exatamente uma mensagem por canal, e uma execução bem-sucedida não manda nada. O token vai para o curl pela entrada padrão e nunca é impresso, e uma API de notificação fora do ar não altera o código de saída do script.
Configuração em cinco passos
- Instale
restic,git,curlepm2(maiscaddypara o blue/green esqlite3oupostgresql-client, conforme o seu banco). - Copie a pasta para o servidor, rode
cp kit.env.example kit.enve edite o arquivo. - Coloque a senha do repositório em um arquivo com modo 600.
- Rode
./backup.sh,./restore-test.she depois./deploy.sh. - Adicione ao cron as linhas de
cron.example.
Como foi testado
59 checks rodam em um container Debian 12 limpo (Node 22, restic, PostgreSQL 15, Caddy 2.6.2 e OpenSSH via apt, pm2). Eles cobrem: backup de pastas, SQLite e Postgres, restauração com comparação de linhas, repositório errado, banco corrompido, dump ausente, deploy e rollback nos dois modos sob carga, alertas contra uma API falsa local e restic via SFTP.
Para quem é
Para devs solo e times pequenos que rodam um ou dois apps Node ou Go em uma única VPS Linux e querem deploys e backups em que dê para confiar, sem partir para o Kubernetes.
Requisitos
Linux, bash, pm2, restic e, para o blue/green, Caddy. Seu app lê a porta da variável PORT. O blue/green mantém duas releases rodando lado a lado por alguns segundos, então as migrations de banco precisam ser retrocompatíveis.
Perguntas frequentes
Preciso do kit para ter deploy sem downtime?
Não. A técnica está descrita neste post com os comandos principais. O kit entrega tudo empacotado, com health check, rollback, controle de estado, alertas e a suíte de testes.
Que stack o kit pressupõe?
Linux, bash, pm2, Caddy para o blue/green, restic para os backups e um app que lê a porta da variável de ambiente PORT.
Funciona com Postgres e SQLite?
Funciona. Os dois têm dump e verificação.
Dá para usar em vários apps?
Use um kit.env por app e aponte KIT_CONF para o arquivo desejado.
Qual é a licença?
Uso nos seus próprios servidores. Não revenda os arquivos.
Changelog
- 0.3.0: deploys blue/green com rollback, alertas de falha (Telegram e webhook), repositórios SFTP testados, todas as mensagens em inglês.
- 0.2.0: dumps de SQLite e Postgres no
backup.sh, verificação dos dumps norestore-test.sh. - 0.1.0: primeira release.
Ler mais
- Zero-downtime deploys on one VPS with Caddy and pm2 (em inglês)
- restic forget and prune: how the keep flags decide (em inglês)
- A restic backup recipe for SQLite and Postgres on one VPS (em inglês)
- Monitoring backups so that silence never means success (em inglês)
- The 3-2-1 backup rule applied to a single VPS (em inglês)
Quero este
Pagamento, impostos e notas fiscais ficam com a Polar, que atua como merchant of record. Você recebe o link de download assim que concluir a compra.