## Scripts de Base de Datos (12 archivos) - init-database.sh: Inicializacion completa con usuario y BD - init-database-v3.sh: Version con dotenv-vault - reset-database.sh: Reset BD manteniendo usuario - recreate-database.sh: Recreacion completa - cleanup-duplicados.sh, fix-duplicate-triggers.sh - verify-users.sh, verify-missions-status.sh - load-users-and-profiles.sh, DB-127-validar-gaps.sh ## Scripts de Produccion (5 archivos) - build-production.sh: Compilar backend y frontend - deploy-production.sh: Desplegar con PM2 - pre-deploy-check.sh: Validaciones pre-deploy - repair-missing-data.sh: Reparar datos faltantes - migrate-missing-objects.sh: Migrar objetos SQL ## Documentacion (7 archivos) - GUIA-DESPLIEGUE-PRODUCCION-COMPLETA.md - GUIA-ACTUALIZACION-PRODUCCION.md - GUIA-VALIDACION-PRODUCCION.md - GUIA-DEPLOYMENT-AGENTE-PRODUCCION.md - GUIA-SSL-NGINX-PRODUCCION.md - GUIA-SSL-AUTOFIRMADO.md - DIRECTIVA-DEPLOYMENT.md ## Actualizaciones DDL/Seeds - 99-post-ddl-permissions.sql: Permisos actualizados - LOAD-SEEDS-gamification_system.sh: Seeds completos ## Nuevos archivos - PROMPT-AGENTE-PRODUCCION.md: Prompt para agente productivo - FLUJO-CARGA-LIMPIA.md: Documentacion de carga limpia Resuelve: Problema de carga de BD entre dev y produccion Cumple: DIRECTIVA-POLITICA-CARGA-LIMPIA.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1201 lines
38 KiB
Markdown
1201 lines
38 KiB
Markdown
# Guia Completa de Despliegue en Produccion - GAMILIT
|
|
|
|
> **Version:** 1.0.0
|
|
> **Fecha:** 2025-12-18
|
|
> **Servidor:** 74.208.126.102
|
|
> **Autor:** Documentacion generada por analisis de configuracion existente
|
|
|
|
---
|
|
|
|
## Indice
|
|
|
|
1. [Resumen Ejecutivo](#1-resumen-ejecutivo)
|
|
2. [Arquitectura de Produccion](#2-arquitectura-de-produccion)
|
|
3. [Pre-requisitos del Servidor](#3-pre-requisitos-del-servidor)
|
|
4. [Configuracion de Base de Datos](#4-configuracion-de-base-de-datos)
|
|
5. [Configuracion de Aplicaciones](#5-configuracion-de-aplicaciones)
|
|
6. [Proceso de Despliegue con PM2](#6-proceso-de-despliegue-con-pm2)
|
|
7. [Configuracion HTTPS con Certbot](#7-configuracion-https-con-certbot)
|
|
8. [Comandos de Referencia Rapida](#8-comandos-de-referencia-rapida)
|
|
9. [Troubleshooting](#9-troubleshooting)
|
|
|
|
---
|
|
|
|
## 1. Resumen Ejecutivo
|
|
|
|
### Componentes Desplegados
|
|
|
|
| Componente | Puerto | Instancias | Tecnologia |
|
|
|------------|--------|------------|------------|
|
|
| **Backend API** | 3006 | 2 (cluster) | NestJS + TypeORM |
|
|
| **Frontend** | 3005 | 1 (fork) | React + Vite |
|
|
| **PostgreSQL** | 5432 | 1 | PostgreSQL 16+ |
|
|
|
|
### URLs de Acceso
|
|
|
|
```
|
|
Frontend: http://74.208.126.102:3005
|
|
Backend API: http://74.208.126.102:3006/api
|
|
API Docs: http://74.208.126.102:3006/api/docs (deshabilitado en produccion)
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Arquitectura de Produccion
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ SERVIDOR 74.208.126.102 │
|
|
│ │
|
|
Usuario │ ┌──────────────┐ ┌──────────────────────────────┐ │
|
|
│ │ │ Frontend │ │ Backend API │ │
|
|
│ │ │ (Vite) │ │ (NestJS) │ │
|
|
│ │ │ :3005 │ │ :3006 │ │
|
|
▼ │ │ │ │ ┌────────┐ ┌────────┐ │ │
|
|
┌──────┐ │ │ 1 instancia │ │ │ Inst 1 │ │ Inst 2 │ │ │
|
|
│ HTTP │──────────┼───┤ │◄─────┼──┤ Cluster│ │ Cluster│ │ │
|
|
└──────┘ │ └──────────────┘ │ └────────┘ └────────┘ │ │
|
|
│ └──────────────┬───────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌──────────────────────────────┐ │
|
|
│ │ PostgreSQL 16+ │ │
|
|
│ │ :5432 │ │
|
|
│ │ DB: gamilit_platform │ │
|
|
│ └──────────────────────────────┘ │
|
|
│ │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ PM2 │ │
|
|
│ │ - Gestion de procesos │ │
|
|
│ │ - Auto-restart │ │
|
|
│ │ - Cluster mode (backend) │ │
|
|
│ │ - Logs centralizados │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 3. Pre-requisitos del Servidor
|
|
|
|
### Software Requerido
|
|
|
|
| Software | Version Minima | Comando de Verificacion |
|
|
|----------|---------------|------------------------|
|
|
| Node.js | 18.0.0+ | `node -v` |
|
|
| npm | 9.0.0+ | `npm -v` |
|
|
| PostgreSQL | 16+ | `psql --version` |
|
|
| PM2 | Latest | `pm2 -v` |
|
|
| Git | Latest | `git --version` |
|
|
|
|
### Instalacion de PM2 (si no esta instalado)
|
|
|
|
```bash
|
|
npm install -g pm2
|
|
```
|
|
|
|
### Verificacion Pre-Deploy
|
|
|
|
```bash
|
|
# Verificar Node.js
|
|
node -v # Debe ser >= 18.0.0
|
|
|
|
# Verificar npm
|
|
npm -v # Debe ser >= 9.0.0
|
|
|
|
# Verificar PostgreSQL
|
|
psql --version
|
|
|
|
# Verificar PM2
|
|
pm2 -v
|
|
|
|
# Verificar espacio en disco
|
|
df -h
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Configuracion de Base de Datos
|
|
|
|
### 4.1 Estructura de Schemas
|
|
|
|
La base de datos contiene **17 schemas**:
|
|
|
|
| Schema | Descripcion |
|
|
|--------|-------------|
|
|
| `auth` | Autenticacion (Supabase-compatible) |
|
|
| `auth_management` | Gestion de usuarios, perfiles, roles |
|
|
| `educational_content` | Modulos, ejercicios, rubricas |
|
|
| `gamification_system` | XP, ML Coins, logros, rangos, tienda |
|
|
| `progress_tracking` | Progreso de usuarios, intentos |
|
|
| `social_features` | Escuelas, aulas, amistades |
|
|
| `notifications` | Sistema de notificaciones |
|
|
| `content_management` | Gestion de contenido |
|
|
| `communication` | Mensajeria entre usuarios |
|
|
| `audit_logging` | Logs de auditoria |
|
|
| `system_configuration` | Feature flags, parametros |
|
|
| `admin_dashboard` | Vistas administrativas |
|
|
| `lti_integration` | Learning Tools Interoperability |
|
|
| `storage` | Almacenamiento de archivos |
|
|
| `gamilit` | Funciones compartidas |
|
|
| `public` | Schema legacy |
|
|
|
|
### 4.2 Credenciales de Base de Datos
|
|
|
|
```bash
|
|
# Variables de entorno requeridas
|
|
DB_HOST=localhost
|
|
DB_PORT=5432
|
|
DB_NAME=gamilit_platform
|
|
DB_USER=gamilit_user
|
|
DB_PASSWORD=<CONTRASEÑA_SEGURA>
|
|
```
|
|
|
|
### 4.3 Crear Base de Datos desde Cero
|
|
|
|
#### Opcion A: Creacion Limpia (Recomendado para primer despliegue)
|
|
|
|
```bash
|
|
cd apps/database
|
|
|
|
# Definir URL de conexion
|
|
export DATABASE_URL="postgresql://gamilit_user:<PASSWORD>@localhost:5432/gamilit_platform"
|
|
|
|
# Ejecutar script de creacion
|
|
./create-database.sh "$DATABASE_URL"
|
|
```
|
|
|
|
#### Opcion B: Drop y Recreacion (Para reset completo)
|
|
|
|
```bash
|
|
cd apps/database
|
|
|
|
# ADVERTENCIA: Esto ELIMINARA toda la data existente
|
|
export DATABASE_URL="postgresql://gamilit_user:<PASSWORD>@localhost:5432/gamilit_platform"
|
|
|
|
./drop-and-recreate-database.sh "$DATABASE_URL"
|
|
```
|
|
|
|
### 4.4 Fases de Creacion de Base de Datos
|
|
|
|
El script `create-database.sh` ejecuta **16 fases** en orden:
|
|
|
|
| Fase | Descripcion | Contenido |
|
|
|------|-------------|-----------|
|
|
| 0 | Extensions | pgcrypto, uuid-ossp |
|
|
| 1 | Prerequisites | Schemas y ENUMs base |
|
|
| 2 | Funciones Compartidas | Schema gamilit |
|
|
| 3 | Auth Schema | Autenticacion Supabase |
|
|
| 4 | Storage Schema | Almacenamiento |
|
|
| 5 | Auth Management | Usuarios, perfiles |
|
|
| 6 | Educational Content | Modulos, ejercicios |
|
|
| 6.5 | Notifications | Sistema de notificaciones |
|
|
| 7 | Gamification System | XP, rangos, logros |
|
|
| 8 | Progress Tracking | Progreso usuarios |
|
|
| 9 | Social Features | Escuelas, aulas |
|
|
| 9.5 | FK Constraints | Dependencias circulares |
|
|
| 10 | Content Management | Gestion contenido |
|
|
| 10.5 | Communication | Mensajeria |
|
|
| 11 | Audit Logging | Logs auditoria |
|
|
| 12-15 | Otros | Config, Admin, LTI |
|
|
| 16 | **Seeds PROD** | **57 archivos de datos iniciales** |
|
|
|
|
### 4.5 Seeds de Produccion (57 archivos)
|
|
|
|
Los seeds de produccion cargan:
|
|
|
|
| Categoria | Registros | Descripcion |
|
|
|-----------|-----------|-------------|
|
|
| **Usuarios** | 48 | 3 testing + 45 produccion |
|
|
| **Modulos** | 5 | Modulos educativos (M1-M5) |
|
|
| **Ejercicios** | 23 | M1: 5, M2: 5, M3: 5, M4: 5, M5: 3 |
|
|
| **Logros** | 30 | Achievement system |
|
|
| **Rangos Maya** | 5 | Ajaw, Nacom, Ah K'in, Halach Uinic, K'uk'ulkan |
|
|
| **Tienda** | 25 | 5 categorias, 20 items |
|
|
| **Misiones** | 11 | Templates de misiones |
|
|
| **Feature Flags** | 26 | Configuracion de features |
|
|
| **Escuelas** | 2+ | Demo + produccion |
|
|
| **Aulas** | 4+ | Aulas de prueba |
|
|
|
|
---
|
|
|
|
## 5. Configuracion de Aplicaciones
|
|
|
|
### 5.1 Backend - `.env.production`
|
|
|
|
Ubicacion: `apps/backend/.env.production`
|
|
|
|
```bash
|
|
# ============================================================================
|
|
# GAMILIT Backend - Production Environment
|
|
# Servidor: 74.208.126.102
|
|
# ============================================================================
|
|
|
|
# Server
|
|
NODE_ENV=production
|
|
PORT=3006
|
|
API_PREFIX=api
|
|
|
|
# Database
|
|
DB_HOST=localhost
|
|
DB_PORT=5432
|
|
DB_NAME=gamilit_platform
|
|
DB_USER=gamilit_user
|
|
DB_PASSWORD=${DB_PASSWORD}
|
|
DB_SYNCHRONIZE=false
|
|
DB_LOGGING=false
|
|
|
|
# JWT (IMPORTANTE: Cambiar a valor seguro)
|
|
# Generar con: openssl rand -base64 32
|
|
JWT_SECRET=${JWT_SECRET}
|
|
JWT_EXPIRES_IN=15m
|
|
JWT_REFRESH_EXPIRES_IN=7d
|
|
|
|
# CORS
|
|
CORS_ORIGIN=http://74.208.126.102:3005,http://74.208.126.102,http://74.208.126.102:80
|
|
ENABLE_CORS=true
|
|
ENABLE_SWAGGER=false
|
|
|
|
# Logging
|
|
LOG_LEVEL=warn
|
|
LOG_TO_FILE=true
|
|
|
|
# Rate Limiting
|
|
RATE_LIMIT_TTL=60
|
|
RATE_LIMIT_MAX=100
|
|
|
|
# Session
|
|
SESSION_SECRET=${SESSION_SECRET}
|
|
SESSION_MAX_AGE=86400000
|
|
|
|
# Email
|
|
EMAIL_FROM=noreply@gamilit.com
|
|
EMAIL_REPLY_TO=support@gamilit.com
|
|
|
|
# Frontend URL
|
|
FRONTEND_URL=http://74.208.126.102:3005
|
|
```
|
|
|
|
### 5.2 Frontend - `.env.production`
|
|
|
|
Ubicacion: `apps/frontend/.env.production`
|
|
|
|
```bash
|
|
# ============================================================================
|
|
# GAMILIT Frontend - Production Environment
|
|
# Servidor: 74.208.126.102
|
|
# ============================================================================
|
|
|
|
# Application
|
|
VITE_APP_NAME=GAMILIT Platform
|
|
VITE_APP_VERSION=1.0.0
|
|
VITE_APP_ENV=production
|
|
VITE_ENV=production
|
|
|
|
# API Configuration
|
|
VITE_API_HOST=74.208.126.102:3006
|
|
VITE_API_PROTOCOL=http
|
|
VITE_API_VERSION=v1
|
|
VITE_API_TIMEOUT=30000
|
|
|
|
# WebSocket
|
|
VITE_WS_HOST=74.208.126.102:3006
|
|
VITE_WS_PROTOCOL=ws
|
|
|
|
# Authentication
|
|
VITE_JWT_EXPIRATION=7d
|
|
|
|
# Feature Flags
|
|
VITE_ENABLE_GAMIFICATION=true
|
|
VITE_ENABLE_SOCIAL_FEATURES=true
|
|
VITE_ENABLE_ANALYTICS=true
|
|
VITE_ENABLE_DEBUG=false
|
|
VITE_ENABLE_STORYBOOK=false
|
|
VITE_MOCK_API=false
|
|
|
|
# External Services (configurar en produccion)
|
|
VITE_GOOGLE_ANALYTICS_ID=
|
|
VITE_SENTRY_DSN=
|
|
|
|
# Logging
|
|
VITE_LOG_LEVEL=error
|
|
```
|
|
|
|
### 5.3 PM2 - `ecosystem.config.js`
|
|
|
|
Ubicacion: Raiz del proyecto
|
|
|
|
```javascript
|
|
module.exports = {
|
|
apps: [
|
|
// BACKEND - NestJS API
|
|
{
|
|
name: 'gamilit-backend',
|
|
cwd: './apps/backend',
|
|
script: 'dist/main.js',
|
|
node_args: '-r tsconfig-paths/register',
|
|
instances: 2, // 2 instancias en cluster
|
|
exec_mode: 'cluster',
|
|
autorestart: true,
|
|
watch: false,
|
|
max_memory_restart: '1G',
|
|
env_production: {
|
|
NODE_ENV: 'production',
|
|
PORT: 3006,
|
|
},
|
|
env_file: './.env.production',
|
|
error_file: '../../logs/backend-error.log',
|
|
out_file: '../../logs/backend-out.log',
|
|
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
|
merge_logs: true,
|
|
min_uptime: '10s',
|
|
max_restarts: 10,
|
|
kill_timeout: 5000,
|
|
wait_ready: true,
|
|
listen_timeout: 10000,
|
|
},
|
|
|
|
// FRONTEND - Vite Preview
|
|
{
|
|
name: 'gamilit-frontend',
|
|
cwd: './apps/frontend',
|
|
script: 'npx',
|
|
args: 'vite preview --port 3005 --host 0.0.0.0',
|
|
instances: 1,
|
|
exec_mode: 'fork',
|
|
autorestart: true,
|
|
watch: false,
|
|
max_memory_restart: '512M',
|
|
env_production: {
|
|
NODE_ENV: 'production',
|
|
VITE_ENV: 'production',
|
|
},
|
|
env_file: './.env.production',
|
|
error_file: '../../logs/frontend-error.log',
|
|
out_file: '../../logs/frontend-out.log',
|
|
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
|
|
merge_logs: true,
|
|
min_uptime: '10s',
|
|
max_restarts: 10,
|
|
kill_timeout: 5000,
|
|
},
|
|
],
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Proceso de Despliegue con PM2
|
|
|
|
### 6.1 Flujo Completo de Despliegue
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ PROCESO DE DESPLIEGUE PRODUCCION │
|
|
├─────────────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ PASO 1: Preparacion │
|
|
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ 1.1 git pull origin main │ │
|
|
│ │ 1.2 Verificar pre-requisitos │ │
|
|
│ │ 1.3 Configurar variables de entorno (.env.production) │ │
|
|
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ PASO 2: Base de Datos (si es necesario) │
|
|
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ 2.1 cd apps/database │ │
|
|
│ │ 2.2 export DATABASE_URL="postgresql://..." │ │
|
|
│ │ 2.3 ./create-database.sh "$DATABASE_URL" (o drop-and-recreate) │ │
|
|
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ PASO 3: Build de Aplicaciones │
|
|
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ 3.1 cd apps/backend && npm install && npm run build │ │
|
|
│ │ 3.2 cd apps/frontend && npm install && npm run build:prod │ │
|
|
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ PASO 4: Despliegue PM2 │
|
|
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ 4.1 pm2 start ecosystem.config.js --env production │ │
|
|
│ │ 4.2 pm2 save │ │
|
|
│ │ 4.3 pm2 startup (para auto-inicio) │ │
|
|
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ PASO 5: Verificacion │
|
|
│ ┌────────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ 5.1 pm2 status │ │
|
|
│ │ 5.2 curl http://74.208.126.102:3006/api/health │ │
|
|
│ │ 5.3 Acceder a http://74.208.126.102:3005 │ │
|
|
│ └────────────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 6.2 Comandos Paso a Paso
|
|
|
|
#### Paso 1: Preparacion
|
|
|
|
```bash
|
|
# Ir al directorio del proyecto
|
|
cd /path/to/gamilit
|
|
|
|
# Obtener ultimos cambios
|
|
git pull origin main
|
|
```
|
|
|
|
#### Paso 2: Base de Datos (Solo si es necesario)
|
|
|
|
```bash
|
|
# Ir al directorio de database
|
|
cd apps/database
|
|
|
|
# Configurar URL de conexion
|
|
export DATABASE_URL="postgresql://gamilit_user:TU_PASSWORD@localhost:5432/gamilit_platform"
|
|
|
|
# OPCION A: Crear base de datos nueva
|
|
./create-database.sh "$DATABASE_URL"
|
|
|
|
# OPCION B: Reset completo (ELIMINA TODA LA DATA)
|
|
./drop-and-recreate-database.sh "$DATABASE_URL"
|
|
|
|
# Volver al directorio raiz
|
|
cd ../..
|
|
```
|
|
|
|
#### Paso 3: Build de Aplicaciones
|
|
|
|
```bash
|
|
# Build Backend
|
|
cd apps/backend
|
|
npm install
|
|
npm run build
|
|
|
|
# Verificar build exitoso
|
|
ls -la dist/main.js
|
|
|
|
# Build Frontend
|
|
cd ../frontend
|
|
npm install
|
|
npm run build:prod
|
|
|
|
# Verificar build exitoso
|
|
ls -la dist/
|
|
|
|
# Volver al directorio raiz
|
|
cd ../..
|
|
```
|
|
|
|
#### Paso 4: Despliegue con PM2
|
|
|
|
```bash
|
|
# Crear directorio de logs
|
|
mkdir -p logs
|
|
|
|
# Detener procesos anteriores (si existen)
|
|
pm2 delete gamilit-backend gamilit-frontend 2>/dev/null || true
|
|
|
|
# Iniciar aplicaciones
|
|
pm2 start ecosystem.config.js --env production
|
|
|
|
# Guardar configuracion
|
|
pm2 save
|
|
|
|
# Configurar inicio automatico (primera vez)
|
|
pm2 startup
|
|
# Ejecutar el comando que muestre el output anterior
|
|
```
|
|
|
|
#### Paso 5: Verificacion
|
|
|
|
```bash
|
|
# Ver estado de procesos
|
|
pm2 status
|
|
|
|
# Verificar health del backend
|
|
curl http://74.208.126.102:3006/api/health
|
|
|
|
# Ver logs en tiempo real
|
|
pm2 logs
|
|
|
|
# Acceder al frontend en el navegador
|
|
# http://74.208.126.102:3005
|
|
```
|
|
|
|
### 6.3 Script Automatizado
|
|
|
|
Existe un script que automatiza el proceso:
|
|
|
|
```bash
|
|
# Ejecutar script de despliegue
|
|
./scripts/deploy-production.sh
|
|
```
|
|
|
|
Este script:
|
|
1. Verifica que PM2 este instalado
|
|
2. Verifica que los builds existan
|
|
3. Verifica archivos `.env.production`
|
|
4. Crea directorio de logs
|
|
5. Detiene procesos PM2 existentes
|
|
6. Inicia backend (2 instancias cluster)
|
|
7. Inicia frontend (1 instancia)
|
|
8. Guarda configuracion PM2
|
|
9. Muestra resumen final
|
|
|
|
---
|
|
|
|
## 7. Configuracion HTTPS con Certbot
|
|
|
|
### 7.1 Arquitectura HTTPS
|
|
|
|
```
|
|
ARQUITECTURA HTTPS PRODUCCION
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ │
|
|
│ Usuario │
|
|
│ │ │
|
|
│ │ HTTPS (443) │
|
|
│ ▼ │
|
|
│ ┌────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ NGINX REVERSE PROXY │ │
|
|
│ │ (Terminacion SSL) │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────────┐ ┌─────────────────────────────────┐ │ │
|
|
│ │ │ SSL Certificate │ │ Rutas: │ │ │
|
|
│ │ │ (Certbot/LE) │ │ / → Frontend :3005 │ │ │
|
|
│ │ │ │ │ /api → Backend :3006 │ │ │
|
|
│ │ │ /etc/letsencrypt/ │ │ /socket.io → Backend :3006 │ │ │
|
|
│ │ └─────────────────────┘ └─────────────────────────────────┘ │ │
|
|
│ └────────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │ │
|
|
│ │ HTTP (interno) │ HTTP (interno) │
|
|
│ ▼ ▼ │
|
|
│ ┌──────────────────┐ ┌──────────────────────┐ │
|
|
│ │ Frontend │ │ Backend │ │
|
|
│ │ (Vite) │ │ (NestJS) │ │
|
|
│ │ :3005 │ │ :3006 │ │
|
|
│ │ interno │ │ interno │ │
|
|
│ └──────────────────┘ └──────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Concepto clave:** Nginx actua como terminador SSL. Las aplicaciones (Backend/Frontend) siguen corriendo en HTTP internamente, pero todo el trafico externo usa HTTPS.
|
|
|
|
### 7.2 Requisitos para HTTPS
|
|
|
|
| Requisito | Descripcion | Estado |
|
|
|-----------|-------------|--------|
|
|
| **Dominio** | Necesario para Certbot/Let's Encrypt | Opcional (IP requiere certificado autofirmado) |
|
|
| **Nginx** | Reverse proxy y terminador SSL | Requerido |
|
|
| **Certbot** | Cliente ACME para Let's Encrypt | Requerido (con dominio) |
|
|
| **Puertos abiertos** | 80 (HTTP), 443 (HTTPS) | Requerido |
|
|
|
|
### 7.3 Instalacion de Nginx y Certbot
|
|
|
|
```bash
|
|
# Actualizar repositorios
|
|
sudo apt update
|
|
|
|
# Instalar Nginx
|
|
sudo apt install nginx -y
|
|
|
|
# Verificar Nginx
|
|
sudo systemctl status nginx
|
|
|
|
# Instalar Certbot con plugin Nginx
|
|
sudo apt install certbot python3-certbot-nginx -y
|
|
|
|
# Verificar Certbot
|
|
certbot --version
|
|
```
|
|
|
|
### 7.4 Opcion A: HTTPS con Dominio (Recomendado)
|
|
|
|
#### Paso 1: Configurar DNS
|
|
|
|
Asegurar que el dominio apunte a la IP del servidor:
|
|
```
|
|
A Record: gamilit.com → 74.208.126.102
|
|
A Record: www.gamilit.com → 74.208.126.102
|
|
A Record: api.gamilit.com → 74.208.126.102 (opcional)
|
|
```
|
|
|
|
#### Paso 2: Configurar Nginx inicial (HTTP)
|
|
|
|
Crear `/etc/nginx/sites-available/gamilit`:
|
|
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
server_name gamilit.com www.gamilit.com;
|
|
|
|
# Frontend - React App
|
|
location / {
|
|
proxy_pass http://127.0.0.1:3005;
|
|
proxy_http_version 1.1;
|
|
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 $scheme;
|
|
proxy_cache_bypass $http_upgrade;
|
|
}
|
|
|
|
# Backend API
|
|
location /api {
|
|
proxy_pass http://127.0.0.1:3006;
|
|
proxy_http_version 1.1;
|
|
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 $scheme;
|
|
proxy_cache_bypass $http_upgrade;
|
|
|
|
# Timeouts para API
|
|
proxy_connect_timeout 60s;
|
|
proxy_send_timeout 60s;
|
|
proxy_read_timeout 60s;
|
|
}
|
|
|
|
# WebSocket
|
|
location /socket.io {
|
|
proxy_pass http://127.0.0.1:3006;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
|
|
# Timeouts para WebSocket
|
|
proxy_connect_timeout 7d;
|
|
proxy_send_timeout 7d;
|
|
proxy_read_timeout 7d;
|
|
}
|
|
}
|
|
```
|
|
|
|
Habilitar sitio:
|
|
|
|
```bash
|
|
# Crear symlink
|
|
sudo ln -s /etc/nginx/sites-available/gamilit /etc/nginx/sites-enabled/
|
|
|
|
# Eliminar default si existe
|
|
sudo rm /etc/nginx/sites-enabled/default 2>/dev/null || true
|
|
|
|
# Verificar configuracion
|
|
sudo nginx -t
|
|
|
|
# Recargar Nginx
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
#### Paso 3: Obtener Certificado SSL con Certbot
|
|
|
|
```bash
|
|
# Obtener certificado (automatico)
|
|
sudo certbot --nginx -d gamilit.com -d www.gamilit.com
|
|
|
|
# Durante el proceso:
|
|
# 1. Ingresar email para notificaciones
|
|
# 2. Aceptar terminos de servicio
|
|
# 3. Elegir si redirigir HTTP a HTTPS (recomendado: SI)
|
|
```
|
|
|
|
Certbot automaticamente:
|
|
- Obtiene el certificado de Let's Encrypt
|
|
- Modifica la configuracion de Nginx
|
|
- Configura renovacion automatica
|
|
|
|
#### Paso 4: Verificar Configuracion Nginx (Post-Certbot)
|
|
|
|
Despues de ejecutar certbot, el archivo se vera asi:
|
|
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
server_name gamilit.com www.gamilit.com;
|
|
return 301 https://$server_name$request_uri;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name gamilit.com www.gamilit.com;
|
|
|
|
# Certificados generados por Certbot
|
|
ssl_certificate /etc/letsencrypt/live/gamilit.com/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/gamilit.com/privkey.pem;
|
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
|
|
|
# Frontend - React App
|
|
location / {
|
|
proxy_pass http://127.0.0.1:3005;
|
|
proxy_http_version 1.1;
|
|
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 $scheme;
|
|
}
|
|
|
|
# Backend API
|
|
location /api {
|
|
proxy_pass http://127.0.0.1:3006;
|
|
proxy_http_version 1.1;
|
|
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 $scheme;
|
|
}
|
|
|
|
# WebSocket (wss://)
|
|
location /socket.io {
|
|
proxy_pass http://127.0.0.1:3006;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_set_header Host $host;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 7.5 Opcion B: HTTPS con IP (Sin Dominio)
|
|
|
|
Si no tienes dominio, necesitas certificado autofirmado:
|
|
|
|
```bash
|
|
# Crear directorio para certificados
|
|
sudo mkdir -p /etc/nginx/ssl
|
|
|
|
# Generar certificado autofirmado (valido 365 dias)
|
|
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
|
-keyout /etc/nginx/ssl/gamilit.key \
|
|
-out /etc/nginx/ssl/gamilit.crt \
|
|
-subj "/C=MX/ST=Estado/L=Ciudad/O=Gamilit/CN=74.208.126.102"
|
|
```
|
|
|
|
Configuracion Nginx para IP con SSL:
|
|
|
|
```nginx
|
|
server {
|
|
listen 80;
|
|
server_name 74.208.126.102;
|
|
return 301 https://$server_name$request_uri;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl http2;
|
|
server_name 74.208.126.102;
|
|
|
|
# Certificado autofirmado
|
|
ssl_certificate /etc/nginx/ssl/gamilit.crt;
|
|
ssl_certificate_key /etc/nginx/ssl/gamilit.key;
|
|
|
|
# Configuracion SSL
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_prefer_server_ciphers on;
|
|
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
|
|
ssl_session_cache shared:SSL:10m;
|
|
|
|
# Frontend
|
|
location / {
|
|
proxy_pass http://127.0.0.1:3005;
|
|
proxy_http_version 1.1;
|
|
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 $scheme;
|
|
}
|
|
|
|
# Backend API
|
|
location /api {
|
|
proxy_pass http://127.0.0.1:3006;
|
|
proxy_http_version 1.1;
|
|
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 $scheme;
|
|
}
|
|
|
|
# WebSocket
|
|
location /socket.io {
|
|
proxy_pass http://127.0.0.1:3006;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_set_header Host $host;
|
|
}
|
|
}
|
|
```
|
|
|
|
**Nota:** Los navegadores mostraran advertencia de certificado no confiable.
|
|
|
|
### 7.6 Actualizar Variables de Entorno para HTTPS
|
|
|
|
#### Backend `.env.production`
|
|
|
|
```bash
|
|
# ANTES (HTTP)
|
|
CORS_ORIGIN=http://74.208.126.102:3005,http://74.208.126.102
|
|
FRONTEND_URL=http://74.208.126.102:3005
|
|
|
|
# DESPUES (HTTPS con dominio)
|
|
CORS_ORIGIN=https://gamilit.com,https://www.gamilit.com,https://74.208.126.102
|
|
FRONTEND_URL=https://gamilit.com
|
|
|
|
# DESPUES (HTTPS con IP)
|
|
CORS_ORIGIN=https://74.208.126.102
|
|
FRONTEND_URL=https://74.208.126.102
|
|
```
|
|
|
|
#### Frontend `.env.production`
|
|
|
|
```bash
|
|
# ANTES (HTTP)
|
|
VITE_API_HOST=74.208.126.102:3006
|
|
VITE_API_PROTOCOL=http
|
|
VITE_WS_HOST=74.208.126.102:3006
|
|
VITE_WS_PROTOCOL=ws
|
|
|
|
# DESPUES (HTTPS con Nginx proxy - RECOMENDADO)
|
|
# Nginx maneja SSL, frontend accede via proxy
|
|
VITE_API_HOST=gamilit.com
|
|
VITE_API_PROTOCOL=https
|
|
VITE_WS_HOST=gamilit.com
|
|
VITE_WS_PROTOCOL=wss
|
|
|
|
# DESPUES (HTTPS con IP)
|
|
VITE_API_HOST=74.208.126.102
|
|
VITE_API_PROTOCOL=https
|
|
VITE_WS_HOST=74.208.126.102
|
|
VITE_WS_PROTOCOL=wss
|
|
```
|
|
|
|
### 7.7 Rebuild y Reinicio
|
|
|
|
Despues de cambiar las variables de entorno:
|
|
|
|
```bash
|
|
# 1. Rebuild del Frontend (variables VITE_ se embeben en build)
|
|
cd apps/frontend
|
|
npm run build:prod
|
|
|
|
# 2. Reiniciar servicios
|
|
pm2 restart all
|
|
|
|
# 3. Verificar Nginx
|
|
sudo nginx -t
|
|
sudo systemctl reload nginx
|
|
```
|
|
|
|
### 7.8 Renovacion Automatica de Certificados
|
|
|
|
Certbot configura renovacion automatica. Verificar:
|
|
|
|
```bash
|
|
# Ver timer de renovacion
|
|
sudo systemctl status certbot.timer
|
|
|
|
# Probar renovacion (dry-run)
|
|
sudo certbot renew --dry-run
|
|
|
|
# Forzar renovacion si es necesario
|
|
sudo certbot renew --force-renewal
|
|
```
|
|
|
|
Los certificados de Let's Encrypt expiran cada 90 dias. Certbot los renueva automaticamente.
|
|
|
|
### 7.9 URLs Finales con HTTPS
|
|
|
|
#### Con Dominio
|
|
```
|
|
Frontend: https://gamilit.com
|
|
Backend API: https://gamilit.com/api
|
|
WebSocket: wss://gamilit.com/socket.io
|
|
Health Check: https://gamilit.com/api/health
|
|
```
|
|
|
|
#### Con IP (certificado autofirmado)
|
|
```
|
|
Frontend: https://74.208.126.102
|
|
Backend API: https://74.208.126.102/api
|
|
WebSocket: wss://74.208.126.102/socket.io
|
|
Health Check: https://74.208.126.102/api/health
|
|
```
|
|
|
|
### 7.10 Verificacion HTTPS
|
|
|
|
```bash
|
|
# Verificar certificado SSL
|
|
curl -vI https://gamilit.com 2>&1 | grep -E "SSL|certificate|subject"
|
|
|
|
# Verificar API sobre HTTPS
|
|
curl -s https://gamilit.com/api/health | jq
|
|
|
|
# Verificar que HTTP redirige a HTTPS
|
|
curl -I http://gamilit.com
|
|
|
|
# Verificar WebSocket (requiere wscat)
|
|
npm install -g wscat
|
|
wscat -c wss://gamilit.com/socket.io
|
|
```
|
|
|
|
### 7.11 Checklist HTTPS
|
|
|
|
- [ ] Nginx instalado y corriendo
|
|
- [ ] Certbot instalado
|
|
- [ ] Dominio configurado en DNS (o usar IP)
|
|
- [ ] Configuracion Nginx creada en sites-available
|
|
- [ ] Symlink creado en sites-enabled
|
|
- [ ] `nginx -t` sin errores
|
|
- [ ] Certificado SSL obtenido (certbot o autofirmado)
|
|
- [ ] `CORS_ORIGIN` actualizado con https://
|
|
- [ ] `FRONTEND_URL` actualizado con https://
|
|
- [ ] `VITE_API_PROTOCOL=https` en frontend
|
|
- [ ] `VITE_WS_PROTOCOL=wss` en frontend
|
|
- [ ] Frontend recompilado (`npm run build:prod`)
|
|
- [ ] PM2 reiniciado (`pm2 restart all`)
|
|
- [ ] Nginx recargado (`sudo systemctl reload nginx`)
|
|
- [ ] Health check responde sobre HTTPS
|
|
- [ ] Frontend carga sin errores de mixed content
|
|
- [ ] WebSocket conecta sobre wss://
|
|
|
|
---
|
|
|
|
## 8. Comandos de Referencia Rapida
|
|
|
|
### PM2 - Operaciones Basicas
|
|
|
|
```bash
|
|
# Ver estado
|
|
pm2 status
|
|
pm2 list
|
|
|
|
# Logs
|
|
pm2 logs # Todos los logs
|
|
pm2 logs gamilit-backend # Solo backend
|
|
pm2 logs gamilit-frontend # Solo frontend
|
|
|
|
# Monitoreo
|
|
pm2 monit # Monitor interactivo
|
|
|
|
# Reinicio
|
|
pm2 restart all # Reiniciar todo
|
|
pm2 restart gamilit-backend # Solo backend
|
|
pm2 reload gamilit-backend # Zero-downtime reload
|
|
|
|
# Detener
|
|
pm2 stop all
|
|
pm2 stop gamilit-backend
|
|
|
|
# Eliminar
|
|
pm2 delete all
|
|
pm2 delete gamilit-backend
|
|
```
|
|
|
|
### PM2 - Operaciones Avanzadas
|
|
|
|
```bash
|
|
# Informacion detallada
|
|
pm2 show gamilit-backend
|
|
|
|
# Flush logs
|
|
pm2 flush
|
|
|
|
# Guardar configuracion
|
|
pm2 save
|
|
|
|
# Restaurar procesos guardados
|
|
pm2 resurrect
|
|
|
|
# Configurar inicio automatico
|
|
pm2 startup
|
|
|
|
# Actualizar PM2
|
|
pm2 update
|
|
```
|
|
|
|
### Base de Datos
|
|
|
|
```bash
|
|
# Variables
|
|
export DATABASE_URL="postgresql://gamilit_user:PASSWORD@localhost:5432/gamilit_platform"
|
|
|
|
# Crear estructura DDL + Seeds
|
|
./create-database.sh "$DATABASE_URL"
|
|
|
|
# Drop y recrear (RESET TOTAL)
|
|
./drop-and-recreate-database.sh "$DATABASE_URL"
|
|
|
|
# Conectar a PostgreSQL
|
|
psql "$DATABASE_URL"
|
|
|
|
# Backup
|
|
pg_dump -U gamilit_user -d gamilit_platform -F c -f backup_$(date +%Y%m%d).dump
|
|
|
|
# Restore
|
|
pg_restore -U gamilit_user -d gamilit_platform -c backup_20251218.dump
|
|
```
|
|
|
|
### Build
|
|
|
|
```bash
|
|
# Backend
|
|
cd apps/backend && npm run build
|
|
|
|
# Frontend (produccion)
|
|
cd apps/frontend && npm run build:prod
|
|
|
|
# Frontend (desarrollo)
|
|
cd apps/frontend && npm run build
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Troubleshooting
|
|
|
|
### Problema: Backend no inicia
|
|
|
|
```bash
|
|
# Ver logs de error
|
|
pm2 logs gamilit-backend --err --lines 50
|
|
|
|
# Verificar que el build existe
|
|
ls -la apps/backend/dist/main.js
|
|
|
|
# Verificar conexion a base de datos
|
|
psql "$DATABASE_URL" -c "SELECT 1"
|
|
|
|
# Verificar puerto no ocupado
|
|
sudo lsof -i :3006
|
|
```
|
|
|
|
### Problema: Frontend no inicia
|
|
|
|
```bash
|
|
# Ver logs de error
|
|
pm2 logs gamilit-frontend --err --lines 50
|
|
|
|
# Verificar que el build existe
|
|
ls -la apps/frontend/dist/
|
|
|
|
# Verificar puerto no ocupado
|
|
sudo lsof -i :3005
|
|
```
|
|
|
|
### Problema: Error de conexion a BD
|
|
|
|
```bash
|
|
# Verificar PostgreSQL corriendo
|
|
sudo systemctl status postgresql
|
|
|
|
# Reiniciar PostgreSQL
|
|
sudo systemctl restart postgresql
|
|
|
|
# Verificar usuario y permisos
|
|
psql -U postgres -c "\\du"
|
|
psql -U postgres -c "\\l"
|
|
```
|
|
|
|
### Problema: Puerto ocupado
|
|
|
|
```bash
|
|
# Encontrar proceso usando el puerto
|
|
sudo lsof -i :3006
|
|
sudo lsof -i :3005
|
|
|
|
# Matar proceso
|
|
sudo kill -9 <PID>
|
|
|
|
# O usar fuser
|
|
sudo fuser -k 3006/tcp
|
|
```
|
|
|
|
### Problema: Memoria alta
|
|
|
|
```bash
|
|
# Ver uso de memoria PM2
|
|
pm2 monit
|
|
|
|
# Reiniciar con limite de memoria
|
|
pm2 restart gamilit-backend --max-memory-restart 500M
|
|
```
|
|
|
|
### Problema: CORS
|
|
|
|
```bash
|
|
# Verificar CORS_ORIGIN en backend
|
|
grep CORS_ORIGIN apps/backend/.env.production
|
|
|
|
# Debe incluir el origen del frontend
|
|
# CORS_ORIGIN=http://74.208.126.102:3005,http://74.208.126.102
|
|
```
|
|
|
|
---
|
|
|
|
## Checklist de Despliegue
|
|
|
|
### Pre-Despliegue
|
|
- [ ] Verificar version de Node.js >= 18
|
|
- [ ] Verificar version de npm >= 9
|
|
- [ ] Verificar PostgreSQL corriendo
|
|
- [ ] Verificar PM2 instalado
|
|
- [ ] Actualizar codigo: `git pull origin main`
|
|
|
|
### Base de Datos
|
|
- [ ] Configurar DATABASE_URL
|
|
- [ ] Ejecutar `create-database.sh` (o `drop-and-recreate`)
|
|
- [ ] Verificar que los seeds cargaron correctamente
|
|
|
|
### Configuracion
|
|
- [ ] Configurar `apps/backend/.env.production`
|
|
- [ ] Configurar `apps/frontend/.env.production`
|
|
- [ ] Verificar JWT_SECRET es seguro
|
|
- [ ] Verificar CORS_ORIGIN correcto
|
|
|
|
### Build
|
|
- [ ] Build backend: `npm run build`
|
|
- [ ] Build frontend: `npm run build:prod`
|
|
- [ ] Verificar archivos en `dist/`
|
|
|
|
### Despliegue
|
|
- [ ] Ejecutar `pm2 start ecosystem.config.js --env production`
|
|
- [ ] Verificar `pm2 status` - ambos online
|
|
- [ ] Ejecutar `pm2 save`
|
|
- [ ] Configurar `pm2 startup` (primera vez)
|
|
|
|
### Verificacion
|
|
- [ ] Verificar health: `curl http://74.208.126.102:3006/api/health`
|
|
- [ ] Acceder a frontend: http://74.208.126.102:3005
|
|
- [ ] Probar login con usuario de prueba
|
|
- [ ] Verificar logs sin errores: `pm2 logs`
|
|
|
|
---
|
|
|
|
## Contacto y Soporte
|
|
|
|
Para problemas de despliegue:
|
|
1. Revisar logs: `pm2 logs`
|
|
2. Consultar esta documentacion
|
|
3. Verificar `docs/DEPLOYMENT.md` para mas detalles
|
|
4. Revisar `docs/95-guias-desarrollo/DEPLOYMENT-GUIDE.md` para HTTPS
|
|
|
|
---
|
|
|
|
> **Nota:** Esta documentacion fue generada automaticamente analizando los archivos de configuracion existentes en el proyecto. Mantener actualizada cuando haya cambios en la arquitectura.
|