- seguranca_deploy_user.md: corrige Pilar 2 — adiciona aviso crítico sobre grupo docker em instalações rootless, documenta estado correto da VPS 1 e registra incidente de 2026-05-14 com causa raiz e comandos de correção - scoreodonto/deploy.md: adiciona seção de alerta Docker Duplo com sintoma porta 8020 bloqueada por docker-proxy zumbi e diagnóstico/solução - clube67/arquitetura.md: adiciona regra crítica de Docker Rootless na VPS 1 com tabela de restrições e verificação de saúde pós-manutenção Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.8 KiB
🚀 Deploy ScoreOdonto — Guia Completo (VPS 4 → VPS 1)
Este documento detalha o processo de deploy contínuo do ScoreOdonto e o sistema de versionamento automático.
🔁 Visão Geral do Pipeline
Developer (VPS 4)
└─► git push origin main
└─► Gitea Webhook → POST http://10.99.0.4:9002/webhook?token=...
└─► listener-scoreodonto.js (porta 9002, VPS 4)
└─► deploy-prod-scoreodonto.sh
├─► git pull (VPS 4)
├─► rsync → VPS 1 (10.99.0.1)
└─► ssh VPS 1 → docker compose up -d --build
└─► update-version.js (auto-bump patch)
└─► vite build → nginx:alpine
📦 Versionamento do Sistema
Arquivo de versão
frontend/constants.ts
export const APP_VERSION = 'V1.0.6';
Como funciona o auto-incremento
A cada docker compose up -d --build, o script update-version.js (na raiz do projeto) é chamado automaticamente pelo comando de build do frontend:
// frontend/package.json
"scripts": {
"build": "node ../update-version.js && vite build"
}
O script incrementa o patch (terceiro número) da versão:
V1.0.5→V1.0.6→V1.0.7→ ...
Warning
O incremento ocorre dentro do container Docker durante o build. Os arquivos no repositório Git não são modificados automaticamente. A nova versão aparece na interface em produção, mas o
constants.tsno Git permanece com o valor anterior ao build.
Tabela de tipos de versão
| Tipo | Exemplo | Quando usar | Como fazer |
|---|---|---|---|
| Patch (automático) | V1.0.5 → V1.0.6 |
Cada deploy/build | Automático — update-version.js cuida |
| Minor (manual) | V1.0.x → V1.1.0 |
Nova feature significativa ou sprint | Editar constants.ts, zerar patch, commitar |
| Major (manual) | V1.x.x → V2.0.0 |
Rewrite, mudança arquitetural grande | Editar constants.ts, zerar minor e patch, commitar |
Bumpar versão Minor ou Major manualmente
# 1. Editar o arquivo diretamente
nano /home/deploy/stack/scoreodonto.com/frontend/constants.ts
# Alterar: export const APP_VERSION = 'V1.1.0';
# 2. Commitar
cd /home/deploy/stack/scoreodonto.com
git add frontend/constants.ts
git commit -m "chore(version): bump para V1.1.0"
git push origin main
# → webhook dispara o deploy automaticamente
🤖 Webhook — Configuração
| Parâmetro | Valor |
|---|---|
| URL | http://10.99.0.4:9002/webhook?token=scoreodonto_deploy_token_9002 |
| Método | POST |
| Eventos | Push na branch main |
| Listener | /home/deploy/instrucoes/scoreodonto/listener-scoreodonto.js |
| Deploy script | /home/deploy/instrucoes/scoreodonto/deploy-prod-scoreodonto.sh |
Verificar se o listener está ativo
ps aux | grep listener-scoreodonto
# Deve aparecer: node /home/deploy/instrucoes/scoreodonto/listener-scoreodonto.js
Reiniciar o listener (se parou)
pkill -f listener-scoreodonto || true
nohup node /home/deploy/instrucoes/scoreodonto/listener-scoreodonto.js \
> /tmp/scoreodonto-webhook.log 2>&1 &
echo $! > /tmp/scoreodonto-webhook.pid
🛠️ Deploy Manual (sem webhook)
Use quando o webhook não está disponível ou para forçar um rebuild imediato:
# Na VPS 4
bash /home/deploy/instrucoes/scoreodonto/deploy-prod-scoreodonto.sh
O script executa:
git pull origin main— garante código atualizado na VPS 4rsync— sincroniza arquivos para VPS 1 (10.99.0.1), excluindonode_modules,.enve.gitdocker compose up -d --build— reconstrói e reinicia os containers na VPS 1
🐳 Arquitetura Docker (Produção)
Frontend
Dockerfile: frontend/Dockerfile
Build context: . (raiz do projeto)
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY update-version.js . # ← script de versionamento vem da raiz
COPY frontend/package*.json frontend/
WORKDIR /app/frontend
RUN npm install
COPY frontend/ .
RUN npm run build # → chama update-version.js + vite build
# Stage 2: Serve
FROM nginx:alpine
COPY --from=builder /app/frontend/dist /usr/share/nginx/html
EXPOSE 3013
Backend
Dockerfile: backend/Dockerfile
Porta: 8018
Runtime: Node.js 20
Nginx (Proxy)
Porta externa: 8020
Traefik labels: scoreodonto.com / www.scoreodonto.com → HTTPS (Let's Encrypt)
🔍 Verificação Pós-Deploy
# 1. Checar containers na VPS 1
ssh deploy@10.99.0.1 "docker ps | grep scoreodonto"
# 2. Checar versão em produção
curl -s https://scoreodonto.com | grep -o 'V[0-9]*\.[0-9]*\.[0-9]*' | head -1
# 3. Ver logs do último build
ssh deploy@10.99.0.1 "docker logs scoreodontocom-scoreodonto-frontend-1 --tail 30"
# 4. Ver logs do backend
ssh deploy@10.99.0.1 "docker logs scoreodontocom-scoreodonto-backend-1 --tail 30"
⚠️ Troubleshooting
| Problema | Diagnóstico | Solução |
|---|---|---|
| Webhook não dispara | `ps aux | grep listener` |
| Versão não atualiza na UI | Versão incrementa no container, não no git | Normal — a versão no git é a base; o build incrementa |
rsync falha |
ssh deploy@10.99.0.1 echo ok |
Checar chave SSH e VPN WireGuard |
| Docker build falha | docker logs na VPS 1 |
Ver logs do container; checar npm install |
| Frontend em branco | nginx config / dist vazia | Verificar se vite build completou sem erro |
| nginx não sobe, porta 8020 ocupada | sudo ss -tlnp | grep 8020 |
Ver seção abaixo — docker-proxy zumbi |
🔒 Alerta de Segurança — Docker Duplo (Rootless + Root)
Caution
A VPS 1 usa Docker Rootless. O daemon root (
docker.service) está desabilitado intencionalmente. Nunca o reative.
Por que o daemon root é perigoso aqui
O usuário deploy tem acesso sudo. Se o docker.service (root) estiver ativo e deploy estiver no grupo docker, qualquer docker compose up sem DOCKER_HOST cria containers como root — paralelos aos rootless, invisíveis ao docker ps normal, e inacessíveis ao Traefik (que monitora a rede rootless).
Sintoma: porta 8020 ocupada após docker rm -f
Quando um container nginx é force-removed enquanto o daemon root está ativo, o processo docker-proxy root pode ficar preso na porta:
# Diagnóstico
sudo ss -tlnp | grep 8020
# Se aparecer docker-proxy com PID root → daemon root estava ativo
# Solução de emergência
sudo kill <PID do docker-proxy>
cd ~/stack/scoreodonto.com
DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock docker compose rm -sf nginx
DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock docker compose up -d nginx
Estado correto da VPS 1
# Verificar que o daemon root está morto
sudo systemctl status docker # deve mostrar: inactive (dead)
# Verificar que deploy não está no grupo docker
groups deploy # não deve conter "docker"
# Verificar que rootless está respondendo
DOCKER_HOST=unix:///run/user/1000/docker.sock docker ps | grep scoreodonto
📌 Comandos Git Rápidos (fluxo diário)
cd /home/deploy/stack/scoreodonto.com
# Ver estado
git status
# Commitar e enviar (dispara deploy automaticamente)
git add -p # adicionar seletivamente
git commit -m "feat: descrição" # mensagem em português
git push origin main # → webhook → deploy automático
Tip
Quando trabalhando com Claude Code (worktrees), o merge para
mainacontece ao final da sessão. O push paramainé quem efetivamente dispara o deploy — não o commit em si.