shivao-projeto/DEPLOY.md
PontualTech / Karlão 5b02feae50 chore: initial commit + security hardening (4 runs squad shivao-melhoria)
Importação inicial do projeto Shivão (Diário de Bordo do veleiro) em estado
pronto pra produção, já incluindo as 5 mudanças de hardening implementadas
pela squad shivao-melhoria em 2026-04-27.

Mudanças de hardening (HANDOFF.md seção " Pronto"):

1. **Rate limiting nos 3 endpoints públicos de share**
   - express-rate-limit ^8.4.1, 60 req/min/IP
   - server/src/index.js linhas 38, 262, 271, 279

2. **Tamanho de upload reduzido pra 50MB** (era 200MB)
   - multer linha 84

3. **Validação Zod nos endpoints autenticados** (POST /api/data e /zones)
   - novo arquivo server/src/schemas/index.js
   - middleware validate() retorna 400 com top 5 issues

4. **Audit log de ações sensíveis**
   - nova tabela audit_log + funções db.audit() e db.recentAudit()
   - 6 endpoints instrumentados (state_set, media_insert/delete, share_create/revoke/zones_update)
   - novo endpoint GET /api/audit (autenticado)

5. **Catch silencioso de webhook em zona PROIBIDA tratado**
   - app/diario-bordo.html + server/public/index.html linha 3280
   - agora loga erro + exibe toast ao usuário

Status final do HANDOFF:
- 🔴 Críticos restantes: 1 (CORS — decisão consciente single-tenant, não-acionável)
- 🟡 Importantes: 4 itens (testes, vigia reconnect, refator frontend, demais catches)
- 🟢 Bom-ter: 5 itens

Stack: Node 20 ESM + Express + better-sqlite3 + Docker (Coolify)
Single-tenant pessoal · single-file frontend HTML · offline-first

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:24:08 -03:00

6.2 KiB

DEPLOY — Coolify (Hetzner VPS)

Guia passo-a-passo para colocar o shivao-cloud em produção no Coolify.

Pré-requisitos

  • VPS Hetzner com Coolify instalado e acessível
  • Domínio (ou subdomínio) apontando para o IP do servidor
    • Ex: shivao.exemplo.com → IP da VPS
  • DNS propagado (verifique com dig shivao.exemplo.com)

Passo 1 — Subir o código para Git

Recomendado: criar repo privado no GitHub/GitLab.

cd shivao-projeto/server
git init
git add .
git commit -m "Initial commit"
git remote add origin git@github.com:OWNER/shivao-cloud.git
git push -u origin main

Alternativa: usar a opção "Deploy from Docker Image" do Coolify e fazer build local + push para um registry. Mas Git é mais simples.

Passo 2 — No Coolify

2.1. Criar a aplicação

  1. + New ResourceApplication
  2. Selecione Public/Private Repository (with GitHub App) ou Public/Private Repository
  3. Cole a URL do repo
  4. Branch: main
  5. Build Pack: Dockerfile
  6. Base Directory: deixe em branco (o Dockerfile está na raiz)
  7. Dockerfile location: /Dockerfile
  8. Port: 3000
  9. Salvar

2.2. Configurar domínio

  1. Aba Domains
  2. Adicione: https://shivao.exemplo.com
  3. Generate Let's Encrypt (automático)
  4. Salvar

2.3. Variáveis de ambiente

Aba Environment Variables → adicionar:

Mínimo obrigatório

BOAT_TOKEN=<gere com: openssl rand -hex 32>

Pelo menos um canal de notificação

Telegram (recomendado, grátis):

TELEGRAM_BOT_TOKEN=<token do BotFather>
TELEGRAM_CHAT_IDS=<seus chat IDs separados por vírgula>

E-mail (Gmail com app password):

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=seu-email@gmail.com
SMTP_PASS=<senha de app de 16 chars>
SMTP_FROM=Shivao <seu-email@gmail.com>
SMTP_TO=destinatario@exemplo.com,outro@exemplo.com

ntfy.sh (push grátis sem cadastro):

NTFY_TOPIC=<algo aleatório, ex: shivao-alertas-x7k9p2>

Veja server/.env.example para todas as opções (Twilio, webhook, etc).

Opcionais

HEARTBEAT_TIMEOUT_SEC=300       # 5 min — tempo até dead-man disparar
NODE_ENV=production

2.4. Volume persistente

Crítico — sem isso, ao reiniciar o container você perde tudo.

  1. Aba Storages
  2. + Add
  3. Tipo: Persistent Storage ou Volume
  4. Name: shivao-data
  5. Mount Path: /data
  6. Salvar

2.5. Deploy

  1. Aba principal da aplicação
  2. Deploy (canto superior direito)
  3. Acompanhar logs do build (~2-3 minutos primeira vez)

Se tudo der certo, ao final:

Shivao Cloud rodando em :3000
Canais configurados: telegram, email, ...
Dead-man switch: 300s

Passo 3 — Verificar

3.1. Health check público

curl https://shivao.exemplo.com/api/health
# {"ok":true,"ts":1730000000000}

3.2. Auth funcionando

curl -H "Authorization: Bearer SEU_TOKEN" https://shivao.exemplo.com/api/info
# {"channels":["telegram","email"],"heartbeatTimeoutSec":300,"version":"1.0"}

3.3. Acessar o app

Abra https://shivao.exemplo.com/ no navegador. O frontend deve carregar.

3.4. Testar notificação

No app: Arquivo → preencha servidor + token → Disparar mensagem de teste

Você deve receber a mensagem em todos os canais configurados.

Passo 4 — Configurar Telegram (5 minutos)

Se ainda não fez:

  1. No Telegram, fale com @BotFather
  2. /newbot → escolha nome e username → ele dá um token
  3. Copie o token (tipo 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11)
  4. Inicie conversa com o bot recém-criado (envie qualquer coisa)
  5. Acesse https://api.telegram.org/bot<SEU_TOKEN>/getUpdates
  6. No JSON retornado, procure "chat":{"id":123456789,...} → esse é seu CHAT_ID
  7. Cole TELEGRAM_BOT_TOKEN e TELEGRAM_CHAT_IDS no Coolify
  8. Redeploy
  9. Teste no app

Para grupo: adicione o bot ao grupo, mande uma mensagem lá, repita o passo 5 (o chat_id do grupo é negativo).

Passo 5 — Conectar o app ao servidor

No celular:

  1. Abrir https://shivao.exemplo.com/ no Chrome
  2. Menu (⋮) → Adicionar à tela inicial (vira "app")
  3. Abrir o app, ir em Arquivo
  4. Seção ☁️ Sincronização na nuvem:
    • Servidor: https://shivao.exemplo.com
    • Token: o BOAT_TOKEN definido no Coolify
  5. Testar conexão → deve receber notificação de teste
  6. ↑ Enviar tudo para nuvem (primeira vez)

A partir daí, o app sincroniza automaticamente. Se trocar de celular, basta colar a URL + token e tocar em ↓ Baixar da nuvem.

Atualizando o código

Sempre que houver mudanças:

git push origin main

No Coolify:

  • Deploy → ele puxa, builda, e troca o container
  • A migração de schema do SQLite é automática (CREATE TABLE IF NOT EXISTS)

Backup

O volume /data contém:

  • shivao.db (SQLite com todos os dados)
  • media/ (fotos, áudios, vídeos)

Recomendado: configurar backup periódico do volume no Coolify ou sincronizar /data para um S3 com restic ou borgbackup via cronjob.

Troubleshooting

"BOAT_TOKEN não configurado"

Variável de ambiente faltando ou < 16 chars. Veja Passo 2.3.

"Failed to fetch" no app

  • DNS não propagou ainda
  • Token errado
  • Coolify não está expondo SSL (verificar Domains)

"Webhooks falham mas Telegram funciona"

Discord/genérico podem ter rate limits. O servidor faz fan-out independente, então um falhar não afeta os outros.

"GPS não funciona no app"

Geolocation API só funciona em HTTPS. Coolify configura HTTPS automaticamente — mas verifique se está acessando https://... e não http://.

"Dead-man switch não dispara"

  • Verificar logs do servidor: docker logs <container>
  • Dead-man só dispara se houve /api/anchor/start antes
  • Default é 5 min sem heartbeat — pode ajustar em HEARTBEAT_TIMEOUT_SEC

Container reinicia em loop

Verificar logs. Causa comum: BOAT_TOKEN muito curto (mínimo 16 chars).

Custos esperados

  • Hetzner CX22 (2 vCPU, 4 GB RAM): ~6€/mês — sobra recurso
  • Domínio: ~10€/ano
  • Telegram, ntfy, Open-Meteo: grátis
  • Twilio (se ativar SMS): ~$1/mês + ~$0.05 por SMS no Brasil
  • Windy Point Forecast: o dono já tem premium pessoal

Total mínimo: ~7€/mês.