chore(deploy): nginx + entorno + runbook para testing.crm.aduanasoft.com
- deploy/nginx/testing.crm.aduanasoft.com.conf: reverse proxy TLS, app (:5173) y API (:8000) en el mismo origen, headers de seguridad, límite 30 MB de subida. - deploy/env.testing.example: plantilla de entorno SIN secretos, con banderas de seguridad (ENVIRONMENT=production, DEV_LOCAL_AUTH=false) y URLs del dominio. - deploy/README.md: runbook (acceso por llave, build de producción, migraciones, nginx+certbot, smoke test). Los secretos y las migraciones los ejecuta el operador. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
84
deploy/README.md
Normal file
84
deploy/README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Despliegue — testing.crm.aduanasoft.com (entorno de pruebas)
|
||||
|
||||
Guía para publicar el CRM Agente de Carga en el servidor de pruebas. El estándar
|
||||
Aduanasoft es desplegar vía **Jenkins (CI/CD)**; este runbook manual es para el
|
||||
levantamiento inicial o cuando el pipeline aún no está conectado.
|
||||
|
||||
> **Servidor:** `deploy@216.250.125.140:3232` · **DNS:** `testing.crm.aduanasoft.com` → `216.250.125.140`
|
||||
|
||||
## 0. Reglas de seguridad (no negociables)
|
||||
- `ENVIRONMENT=production` y `DEV_LOCAL_AUTH=false`. En `development` el RBAC
|
||||
auto-bootstrapea **super_admin** a cualquiera y se activa el login local — inaceptable
|
||||
en un dominio público.
|
||||
- Los secretos (DB, S3, `SECRET_KEY`, Keycloak) los captura **el operador en el servidor**,
|
||||
nunca se versionan ni se comparten por chat.
|
||||
- Las **migraciones** las ejecuta el operador/CI, no de forma automática. No correr
|
||||
migraciones contra producción.
|
||||
|
||||
## 1. Acceso por llave (una vez)
|
||||
Autoriza la llave pública del operador en el servidor (desde una máquina que ya entre):
|
||||
```bash
|
||||
ssh -p 3232 deploy@216.250.125.140 \
|
||||
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && echo '<TU_LLAVE_PUBLICA>' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
|
||||
```
|
||||
|
||||
## 2. Código y entorno
|
||||
```bash
|
||||
ssh -p 3232 deploy@216.250.125.140
|
||||
git clone https://git.aduanasoft.com/ADUANASOFT/CRM_AGENTES_CARGA.git
|
||||
cd CRM_AGENTES_CARGA
|
||||
git checkout feature/crm-cumplimiento-pdf # o la rama/tag liberado
|
||||
cp deploy/env.testing.example .env
|
||||
$EDITOR .env # rellenar TODOS los CHANGE_ME
|
||||
```
|
||||
|
||||
## 3. Build de producción (importante)
|
||||
El `docker-compose.yml` del repo está orientado a desarrollo (vite dev + `--reload`).
|
||||
Para un sitio público hay que servir la **build** de producción:
|
||||
- **Frontend:** `npm ci && npm run build` (adapter-node) y arrancar con `node build`
|
||||
escuchando en `5173`, con `ORIGIN=https://testing.crm.aduanasoft.com`.
|
||||
- **Backend:** `uvicorn main:app --host 0.0.0.0 --port 8000` **sin** `--reload`.
|
||||
- Publica los puertos SOLO en loopback (override):
|
||||
```yaml
|
||||
# docker-compose.testing.yml (ejemplo de override)
|
||||
services:
|
||||
backend:
|
||||
ports: ["127.0.0.1:8000:8000"]
|
||||
command: ["uvicorn","main:app","--host","0.0.0.0","--port","8000"]
|
||||
frontend:
|
||||
ports: ["127.0.0.1:5173:5173"]
|
||||
command: ["node","build"]
|
||||
```
|
||||
```bash
|
||||
docker compose -f docker-compose.yml -f docker-compose.testing.yml up -d --build
|
||||
```
|
||||
|
||||
## 4. Migraciones y datos base
|
||||
```bash
|
||||
docker compose exec backend alembic upgrade head
|
||||
# Catálogo de permisos + roles por carril (Ventas/Operaciones/Facturación/Consulta):
|
||||
docker compose exec backend python -c "from api.v1.modules.core.permissions.service import PermissionService; from core.database import CoreSessionLocal; PermissionService(CoreSessionLocal()).sync_permissions()"
|
||||
```
|
||||
> En producción NO se usa el auto-bootstrap de dev: asigna los roles a los usuarios
|
||||
> reales desde el módulo de Roles y permisos.
|
||||
|
||||
## 5. Nginx + TLS
|
||||
```bash
|
||||
sudo cp deploy/nginx/testing.crm.aduanasoft.com.conf /etc/nginx/sites-available/
|
||||
sudo ln -s /etc/nginx/sites-available/testing.crm.aduanasoft.com.conf /etc/nginx/sites-enabled/
|
||||
sudo mkdir -p /var/www/certbot
|
||||
sudo certbot certonly --webroot -w /var/www/certbot -d testing.crm.aduanasoft.com
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
## 6. Smoke test
|
||||
```bash
|
||||
curl -fsS https://testing.crm.aduanasoft.com/api/health && echo OK
|
||||
# Abre la app y valida login (Keycloak), listar clientes, y un flujo end-to-end.
|
||||
```
|
||||
|
||||
## Notas
|
||||
- App y API van en el **mismo origen** (`/` y `/api/`) para no requerir CORS entre hosts.
|
||||
- MinIO: si el navegador debe abrir URLs prefirmadas, `S3_ENDPOINT_URL` debe resolver a un
|
||||
host accesible públicamente (o publicar MinIO detrás de nginx en otro subdominio). Revisar
|
||||
según la política de red del entorno de pruebas.
|
||||
47
deploy/env.testing.example
Normal file
47
deploy/env.testing.example
Normal file
@@ -0,0 +1,47 @@
|
||||
# ==========================================================================
|
||||
# Plantilla de entorno para testing.crm.aduanasoft.com (entorno de PRUEBAS)
|
||||
# Copia este archivo como `.env` EN EL SERVIDOR y rellena los valores reales.
|
||||
# NO subas el .env con secretos al repositorio.
|
||||
# ==========================================================================
|
||||
|
||||
# ---- SEGURIDAD (CRÍTICO) ----
|
||||
# Debe ser 'production'. NUNCA 'development' en un dominio público: el RBAC
|
||||
# hace auto-bootstrap de super_admin al usuario en 'development' (cualquiera
|
||||
# quedaría como administrador total).
|
||||
ENVIRONMENT=production
|
||||
# NUNCA 'true' en público: activa el login local "Entrar como dev" y salta Keycloak.
|
||||
DEV_LOCAL_AUTH=false
|
||||
# Genera uno fuerte: openssl rand -hex 32
|
||||
SECRET_KEY=CHANGE_ME_openssl_rand_hex_32
|
||||
|
||||
# ---- Autenticación (Keycloak / Hub) ----
|
||||
HUB_URL=https://CHANGE_ME_hub_o_keycloak/
|
||||
# (agrega aquí los claims/realm/cliente que use tu integración real)
|
||||
|
||||
# ---- Base de datos (PostgreSQL) ----
|
||||
CORE_DB_HOST=postgres
|
||||
CORE_DB_PORT=5432
|
||||
CORE_DB_NAME=crm_core
|
||||
CORE_DB_USER=CHANGE_ME
|
||||
CORE_DB_PASSWORD=CHANGE_ME
|
||||
|
||||
# ---- Almacenamiento de objetos (MinIO / S3) ----
|
||||
S3_ENDPOINT_URL=http://minio:9000
|
||||
S3_ACCESS_KEY=CHANGE_ME
|
||||
S3_SECRET_KEY=CHANGE_ME
|
||||
S3_BUCKET=crm
|
||||
S3_REGION=us-east-1
|
||||
S3_USE_SSL=false
|
||||
|
||||
# ---- URLs públicas / CORS (mismo origen que nginx) ----
|
||||
APP_PUBLIC_URL=https://testing.crm.aduanasoft.com
|
||||
CORS_ORIGINS=https://testing.crm.aduanasoft.com
|
||||
|
||||
# ---- Frontend (SvelteKit adapter-node) ----
|
||||
# API en el mismo origen a través de nginx (/api/):
|
||||
VITE_API_URL=https://testing.crm.aduanasoft.com/api/
|
||||
# Llamadas servidor->servidor dentro de la red de Docker:
|
||||
BACKEND_URL=http://backend:8000
|
||||
INTERNAL_API_URL=http://backend:8000/api/
|
||||
# adapter-node valida el Origin contra ORIGIN; debe ser la URL pública:
|
||||
ORIGIN=https://testing.crm.aduanasoft.com
|
||||
81
deploy/nginx/testing.crm.aduanasoft.com.conf
Normal file
81
deploy/nginx/testing.crm.aduanasoft.com.conf
Normal file
@@ -0,0 +1,81 @@
|
||||
# nginx — testing.crm.aduanasoft.com
|
||||
# CRM Agente de Carga (entorno de PRUEBAS). App (SvelteKit adapter-node :5173) + API (FastAPI :8000)
|
||||
# servidas en el MISMO origen para evitar CORS. TLS con Let's Encrypt (certbot).
|
||||
#
|
||||
# Instalar en el servidor:
|
||||
# sudo cp testing.crm.aduanasoft.com.conf /etc/nginx/sites-available/
|
||||
# sudo ln -s /etc/nginx/sites-available/testing.crm.aduanasoft.com.conf /etc/nginx/sites-enabled/
|
||||
# sudo certbot certonly --webroot -w /var/www/certbot -d testing.crm.aduanasoft.com
|
||||
# sudo nginx -t && sudo systemctl reload nginx
|
||||
#
|
||||
# IMPORTANTE (seguridad): publica los puertos de la app SOLO en loopback del servidor
|
||||
# (127.0.0.1:5173 y 127.0.0.1:8000) para que nginx sea el único acceso público.
|
||||
|
||||
# ---- HTTP: reto ACME + redirección a HTTPS ----
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name testing.crm.aduanasoft.com;
|
||||
|
||||
# Renovación de certificados (webroot)
|
||||
location /.well-known/acme-challenge/ {
|
||||
root /var/www/certbot;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# ---- HTTPS ----
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
server_name testing.crm.aduanasoft.com;
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/testing.crm.aduanasoft.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/testing.crm.aduanasoft.com/privkey.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 1d;
|
||||
|
||||
# Encabezados de seguridad
|
||||
add_header Strict-Transport-Security "max-age=63072000" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
|
||||
# Subida de documentos (máx. 25 MB en la app) + margen
|
||||
client_max_body_size 30m;
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/javascript application/json image/svg+xml;
|
||||
gzip_min_length 1024;
|
||||
|
||||
# ---- API (FastAPI) — mismo origen: /api/... -> backend :8000 (conserva el path) ----
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
|
||||
# ---- App (SvelteKit adapter-node) — todo lo demás -> frontend :5173 ----
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:5173;
|
||||
proxy_http_version 1.1;
|
||||
# WebSocket / upgrade (SSR streaming y HMR si corriera en modo dev)
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user