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>
230 lines
6.2 KiB
Markdown
230 lines
6.2 KiB
Markdown
# 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.
|
|
|
|
```bash
|
|
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 Resource** → **Application**
|
|
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
|
|
|
|
```bash
|
|
curl https://shivao.exemplo.com/api/health
|
|
# {"ok":true,"ts":1730000000000}
|
|
```
|
|
|
|
### 3.2. Auth funcionando
|
|
|
|
```bash
|
|
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](https://t.me/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:
|
|
|
|
```bash
|
|
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.
|