From d21e02dc96627fb1fc62fe735b37664197509f6f Mon Sep 17 00:00:00 2001 From: Eduardo Lopes <155753879+eduardolopesx03@users.noreply.github.com> Date: Tue, 10 Feb 2026 13:42:03 -0300 Subject: [PATCH] docs: ajustar deploy para VPS sem node usando docker compose --- docker-compose.frontend.yml | 17 +++++++ docker/nginx.frontend.conf | 11 +++++ docs/DEPLOY_VPS.md | 99 +++++++++++++++---------------------- 3 files changed, 69 insertions(+), 58 deletions(-) create mode 100644 docker-compose.frontend.yml create mode 100644 docker/nginx.frontend.conf diff --git a/docker-compose.frontend.yml b/docker-compose.frontend.yml new file mode 100644 index 0000000..7bf7aab --- /dev/null +++ b/docker-compose.frontend.yml @@ -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 diff --git a/docker/nginx.frontend.conf b/docker/nginx.frontend.conf new file mode 100644 index 0000000..79fd959 --- /dev/null +++ b/docker/nginx.frontend.conf @@ -0,0 +1,11 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/docs/DEPLOY_VPS.md b/docs/DEPLOY_VPS.md index 59496ea..7c8e8d5 100644 --- a/docs/DEPLOY_VPS.md +++ b/docs/DEPLOY_VPS.md @@ -1,19 +1,31 @@ # 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 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**. --- -## Bloco A — preparação + build +## Bloco A — preparação + build (usando Docker, sem npm/node no host) > Copiar/colar no VPS @@ -35,53 +47,26 @@ export const environment = { }; EOT -# 3) instalar dependências e build de produção -npm ci -npm run build +# 3) build de produção via container Node +docker compose -f docker-compose.frontend.yml run --rm frontend-builder -# 4) validar que o build estático foi gerado +# 4) validar saída estática ls -lah dist/line-gestao-frontend/browser ``` --- -## Bloco B — publicação (simples e confiável com Nginx container) - -> Estratégia: publicar somente o build estático em um container Nginx, na porta 8081. +## Bloco B — publicação (Nginx container do front + Caddy da API) ```bash set -e -# 1) criar pasta de publicação estática -sudo mkdir -p /opt/line-gestao-frontend -sudo rsync -av --delete ~/apps/line-gestao-frontend/dist/line-gestao-frontend/browser/ /opt/line-gestao-frontend/ +cd ~/apps/line-gestao-frontend -# 2) subir Nginx estático com fallback de SPA -cat > /tmp/line-frontend-nginx.conf <<'EOT' -server { - listen 80; - server_name _; +# 1) subir/atualizar Nginx estático do front +docker compose -f docker-compose.frontend.yml up -d frontend-nginx - root /usr/share/nginx/html; - 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 +# 2) backup e ajuste do Caddyfile da API para mesmo domínio 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' @@ -95,9 +80,9 @@ linegestao.inglinesystems.com.br { } EOT -# 4) recarregar caddy (stack da API) +# 3) recarregar apenas o caddy 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 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 -# 4) conferir logs rápidos -sudo docker logs --tail 50 line-gestao-frontend-nginx -sudo docker compose -f ~/apps/line-gestao-api/docker-compose.domain.yml logs --tail 50 caddy +# 4) logs rápidos +docker logs --tail 50 line-gestao-frontend-nginx +docker compose -f ~/apps/line-gestao-api/docker-compose.domain.yml logs --tail 50 caddy ``` No navegador: 1. Abrir `https://linegestao.inglinesystems.com.br`. 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 -Se aparecer erro de CORS: - ```bash -# 1) validar headers CORS no endpoint real +# 1) validar preflight curl -i -X OPTIONS 'https://linegestao.inglinesystems.com.br/auth/login' \ -H 'Origin: https://linegestao.inglinesystems.com.br' \ -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 grep FRONTEND_PUBLIC_URL ~/apps/line-gestao-api/.env -# 3) deve estar exatamente assim: +# deve ser: # 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 -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 é: -- URL do front diferente da configurada no `.env` da API; -- requisição indo para domínio/porta diferente; -- endpoint fora do matcher `@api` no Caddy. +Se continuar CORS, normalmente é: +- front abrindo em URL diferente da permitida; +- requisição indo para outro host/porta; +- rota faltando no matcher `@api` do Caddy. --- @@ -160,6 +143,6 @@ Se continuar CORS, geralmente é: - [ ] Front abre em `https://linegestao.inglinesystems.com.br`. - [ ] 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 401 inesperado após login (apenas 401 esperado antes de autenticar). +- [ ] Sem 401 inesperado após login (401 só antes de autenticar).