docs: ajustar deploy para VPS sem node usando docker compose

This commit is contained in:
Eduardo Lopes 2026-02-10 13:42:03 -03:00
parent 118c6adf31
commit d21e02dc96
3 changed files with 69 additions and 58 deletions

View File

@ -0,0 +1,17 @@
services:
frontend-builder:
image: node:22-alpine
working_dir: /app
volumes:
- ./:/app
command: sh -lc "npm ci && npm run build"
frontend-nginx:
image: nginx:alpine
container_name: line-gestao-frontend-nginx
restart: unless-stopped
ports:
- "127.0.0.1:8081:80"
volumes:
- ./dist/line-gestao-frontend/browser:/usr/share/nginx/html:ro
- ./docker/nginx.frontend.conf:/etc/nginx/conf.d/default.conf:ro

View File

@ -0,0 +1,11 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}

View File

@ -1,19 +1,31 @@
# Deploy rápido do Front-end no mesmo VPS (API já em produção) # Deploy rápido do Front-end no mesmo VPS (API já em produção)
## 0) Detecção automática de stack do front ## 0) Detecção automática de stack do front (sem Node instalado no host)
No VPS (ou local), rode no diretório do front: No VPS, rode no diretório do front:
```bash ```bash
cd ~/apps/line-gestao-frontend cd ~/apps/line-gestao-frontend
node -e "const p=require('./package.json');const s=p.scripts||{};if(s.ng||s.start?.includes('ng serve'))console.log('Stack detectada: Angular CLI');else if(s.dev?.includes('vite'))console.log('Stack detectada: Vite');else if(s.dev?.includes('next')||s.start?.includes('next'))console.log('Stack detectada: Next.js');else console.log('Stack não identificada automaticamente');" python3 - <<'PY'
import json
p=json.load(open('package.json'))
s=p.get('scripts',{})
if 'ng' in s or 'ng serve' in s.get('start',''):
print('Stack detectada: Angular CLI')
elif 'vite' in s.get('dev',''):
print('Stack detectada: Vite')
elif 'next' in s.get('dev','') or 'next' in s.get('start',''):
print('Stack detectada: Next.js')
else:
print('Stack não identificada automaticamente')
PY
``` ```
Para este projeto, a stack detectada é **Angular**. Para este projeto, a stack detectada é **Angular**.
--- ---
## Bloco A — preparação + build ## Bloco A — preparação + build (usando Docker, sem npm/node no host)
> Copiar/colar no VPS > Copiar/colar no VPS
@ -35,53 +47,26 @@ export const environment = {
}; };
EOT EOT
# 3) instalar dependências e build de produção # 3) build de produção via container Node
npm ci docker compose -f docker-compose.frontend.yml run --rm frontend-builder
npm run build
# 4) validar que o build estático foi gerado # 4) validar saída estática
ls -lah dist/line-gestao-frontend/browser ls -lah dist/line-gestao-frontend/browser
``` ```
--- ---
## Bloco B — publicação (simples e confiável com Nginx container) ## Bloco B — publicação (Nginx container do front + Caddy da API)
> Estratégia: publicar somente o build estático em um container Nginx, na porta 8081.
```bash ```bash
set -e set -e
# 1) criar pasta de publicação estática cd ~/apps/line-gestao-frontend
sudo mkdir -p /opt/line-gestao-frontend
sudo rsync -av --delete ~/apps/line-gestao-frontend/dist/line-gestao-frontend/browser/ /opt/line-gestao-frontend/
# 2) subir Nginx estático com fallback de SPA # 1) subir/atualizar Nginx estático do front
cat > /tmp/line-frontend-nginx.conf <<'EOT' docker compose -f docker-compose.frontend.yml up -d frontend-nginx
server {
listen 80;
server_name _;
root /usr/share/nginx/html; # 2) backup e ajuste do Caddyfile da API para mesmo domínio
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
EOT
sudo docker rm -f line-gestao-frontend-nginx 2>/dev/null || true
sudo docker run -d \
--name line-gestao-frontend-nginx \
--restart unless-stopped \
-p 127.0.0.1:8081:80 \
-v /opt/line-gestao-frontend:/usr/share/nginx/html:ro \
-v /tmp/line-frontend-nginx.conf:/etc/nginx/conf.d/default.conf:ro \
nginx:alpine
# 3) adicionar roteamento no Caddy da API (mesmo domínio)
# OBS: manter /health e /api no backend; enviar restante para o front
sudo cp ~/apps/line-gestao-api/Caddyfile ~/apps/line-gestao-api/Caddyfile.bkp.$(date +%F-%H%M%S) sudo cp ~/apps/line-gestao-api/Caddyfile ~/apps/line-gestao-api/Caddyfile.bkp.$(date +%F-%H%M%S)
sudo tee ~/apps/line-gestao-api/Caddyfile >/dev/null <<'EOT' sudo tee ~/apps/line-gestao-api/Caddyfile >/dev/null <<'EOT'
@ -95,9 +80,9 @@ linegestao.inglinesystems.com.br {
} }
EOT EOT
# 4) recarregar caddy (stack da API) # 3) recarregar apenas o caddy
cd ~/apps/line-gestao-api cd ~/apps/line-gestao-api
sudo docker compose -f docker-compose.domain.yml up -d caddy docker compose -f docker-compose.domain.yml up -d caddy
``` ```
--- ---
@ -113,27 +98,25 @@ curl -I https://linegestao.inglinesystems.com.br
# 2) health da API continua OK # 2) health da API continua OK
curl -sS https://linegestao.inglinesystems.com.br/health curl -sS https://linegestao.inglinesystems.com.br/health
# 3) endpoint de auth (ajuste rota se necessário) # 3) endpoint de auth (esperado: 401/405/200 conforme regra da API)
curl -i https://linegestao.inglinesystems.com.br/auth/login || true curl -i https://linegestao.inglinesystems.com.br/auth/login || true
# 4) conferir logs rápidos # 4) logs rápidos
sudo docker logs --tail 50 line-gestao-frontend-nginx docker logs --tail 50 line-gestao-frontend-nginx
sudo docker compose -f ~/apps/line-gestao-api/docker-compose.domain.yml logs --tail 50 caddy docker compose -f ~/apps/line-gestao-api/docker-compose.domain.yml logs --tail 50 caddy
``` ```
No navegador: No navegador:
1. Abrir `https://linegestao.inglinesystems.com.br`. 1. Abrir `https://linegestao.inglinesystems.com.br`.
2. Abrir DevTools (F12) > Network. 2. Abrir DevTools (F12) > Network.
3. Confirmar que as chamadas vão para o mesmo domínio e retornam 2xx/401 esperado no login. 3. Confirmar que as chamadas de API estão no mesmo domínio e com respostas esperadas.
--- ---
## Bloco D — troubleshooting rápido de CORS ## Bloco D — troubleshooting rápido de CORS
Se aparecer erro de CORS:
```bash ```bash
# 1) validar headers CORS no endpoint real # 1) validar preflight
curl -i -X OPTIONS 'https://linegestao.inglinesystems.com.br/auth/login' \ curl -i -X OPTIONS 'https://linegestao.inglinesystems.com.br/auth/login' \
-H 'Origin: https://linegestao.inglinesystems.com.br' \ -H 'Origin: https://linegestao.inglinesystems.com.br' \
-H 'Access-Control-Request-Method: POST' -H 'Access-Control-Request-Method: POST'
@ -141,18 +124,18 @@ curl -i -X OPTIONS 'https://linegestao.inglinesystems.com.br/auth/login' \
# 2) confirmar FRONTEND_PUBLIC_URL na API # 2) confirmar FRONTEND_PUBLIC_URL na API
grep FRONTEND_PUBLIC_URL ~/apps/line-gestao-api/.env grep FRONTEND_PUBLIC_URL ~/apps/line-gestao-api/.env
# 3) deve estar exatamente assim: # deve ser:
# FRONTEND_PUBLIC_URL=https://linegestao.inglinesystems.com.br # FRONTEND_PUBLIC_URL=https://linegestao.inglinesystems.com.br
# 4) reiniciar API/caddy após ajuste de env # 3) reaplicar API/Caddy após ajuste de .env
cd ~/apps/line-gestao-api cd ~/apps/line-gestao-api
sudo docker compose -f docker-compose.domain.yml up -d --force-recreate api caddy docker compose -f docker-compose.domain.yml up -d --force-recreate api caddy
``` ```
Se continuar CORS, geralmente é: Se continuar CORS, normalmente é:
- URL do front diferente da configurada no `.env` da API; - front abrindo em URL diferente da permitida;
- requisição indo para domínio/porta diferente; - requisição indo para outro host/porta;
- endpoint fora do matcher `@api` no Caddy. - rota faltando no matcher `@api` do Caddy.
--- ---
@ -160,6 +143,6 @@ Se continuar CORS, geralmente é:
- [ ] Front abre em `https://linegestao.inglinesystems.com.br`. - [ ] Front abre em `https://linegestao.inglinesystems.com.br`.
- [ ] Login funciona com usuário válido. - [ ] Login funciona com usuário válido.
- [ ] Executa 1 fluxo principal do sistema (ex.: carregar dashboard/listagem). - [ ] Executa 1 fluxo principal (ex.: dashboard/listagem).
- [ ] Sem erro de CORS no console. - [ ] Sem erro de CORS no console.
- [ ] Sem 401 inesperado após login (apenas 401 esperado antes de autenticar). - [ ] Sem 401 inesperado após login (401 só antes de autenticar).