workspace/projects/gamilit/scripts/setup-ssl-certbot.sh
rckrdmrd 289c5a4ee5
Some checks are pending
CI Pipeline / changes (push) Waiting to run
CI Pipeline / core (push) Blocked by required conditions
CI Pipeline / trading-backend (push) Blocked by required conditions
CI Pipeline / trading-data-service (push) Blocked by required conditions
CI Pipeline / trading-frontend (push) Blocked by required conditions
CI Pipeline / erp-core (push) Blocked by required conditions
CI Pipeline / erp-mecanicas (push) Blocked by required conditions
CI Pipeline / gamilit-backend (push) Blocked by required conditions
CI Pipeline / gamilit-frontend (push) Blocked by required conditions
Gamilit: Backend fixes, frontend API updates, deployment guides and validations
Backend:
- Fix email verification and password recovery services
- Fix exercise submission and student progress services

Frontend:
- Update missions, password, and profile API services
- Fix ExerciseContentRenderer component

Docs & Scripts:
- Add SSL/Certbot deployment guide
- Add quick deployment guide
- Database scripts for testing and validations
- Migration and homologation reports
- Functions inventory documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 23:42:48 -06:00

483 lines
14 KiB
Bash
Executable File

#!/bin/bash
################################################################################
# GAMILIT Platform - Setup SSL con Certbot
################################################################################
#
# Este script configura SSL/HTTPS usando Let's Encrypt (Certbot) con Nginx.
#
# PREREQUISITOS:
# - Dominio apuntando al servidor (DNS A record)
# - Puertos 80 y 443 abiertos
# - Backend y Frontend corriendo en PM2
#
# USO:
# ./scripts/setup-ssl-certbot.sh gamilit.com
# ./scripts/setup-ssl-certbot.sh gamilit.com www.gamilit.com
#
# ALTERNATIVA (certificado auto-firmado sin dominio):
# ./scripts/setup-ssl-certbot.sh --self-signed
#
################################################################################
set -e # Exit on error
# Colores
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# Directorio raiz del proyecto
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# Variables
DOMAIN=""
EXTRA_DOMAINS=""
SELF_SIGNED=false
SERVER_IP="74.208.126.102" # Cambiar si es diferente
################################################################################
# FUNCIONES
################################################################################
print_header() {
echo -e "${BLUE}"
echo "============================================================================"
echo " GAMILIT Platform - Setup SSL/HTTPS"
echo "============================================================================"
echo -e "${NC}"
}
print_step() {
echo -e "${CYAN}$1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_error() {
echo -e "${RED}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}! $1${NC}"
}
check_root() {
if [ "$EUID" -ne 0 ]; then
print_error "Este script debe ejecutarse como root (sudo)"
exit 1
fi
}
check_prerequisites() {
print_step "Verificando prerequisitos..."
# Nginx
if ! command -v nginx &> /dev/null; then
print_warning "Nginx no instalado. Instalando..."
apt update && apt install -y nginx
fi
print_success "Nginx instalado"
# Certbot (solo si no es self-signed)
if [ "$SELF_SIGNED" = false ]; then
if ! command -v certbot &> /dev/null; then
print_warning "Certbot no instalado. Instalando..."
apt update && apt install -y certbot python3-certbot-nginx
fi
print_success "Certbot instalado"
fi
# PM2 procesos
if ! pm2 list 2>/dev/null | grep -q "gamilit"; then
print_warning "Procesos PM2 de GAMILIT no detectados"
print_warning "Asegurate de que backend y frontend esten corriendo"
else
print_success "Procesos PM2 activos"
fi
}
verify_dns() {
if [ "$SELF_SIGNED" = true ]; then
return 0
fi
print_step "Verificando DNS para $DOMAIN..."
RESOLVED_IP=$(dig +short "$DOMAIN" | head -1)
if [ -z "$RESOLVED_IP" ]; then
print_error "No se pudo resolver $DOMAIN"
print_error "Asegurate de que el DNS este configurado correctamente"
exit 1
fi
if [ "$RESOLVED_IP" != "$SERVER_IP" ]; then
print_warning "DNS resuelve a $RESOLVED_IP (esperado: $SERVER_IP)"
read -p "¿Continuar de todas formas? (y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
print_success "DNS configurado correctamente ($DOMAIN$RESOLVED_IP)"
}
create_nginx_config_http() {
print_step "Creando configuracion Nginx inicial (HTTP)..."
local SERVER_NAME="$DOMAIN"
if [ -n "$EXTRA_DOMAINS" ]; then
SERVER_NAME="$DOMAIN $EXTRA_DOMAINS"
fi
if [ "$SELF_SIGNED" = true ]; then
SERVER_NAME="$SERVER_IP"
fi
cat > /etc/nginx/sites-available/gamilit << EOF
# GAMILIT Platform - Nginx Configuration
# Generado por setup-ssl-certbot.sh
server {
listen 80;
server_name $SERVER_NAME;
# Frontend (/)
location / {
proxy_pass http://localhost: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 (/api)
location /api {
proxy_pass http://localhost: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 (/socket.io)
location /socket.io {
proxy_pass http://localhost:3006;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host \$host;
}
}
EOF
# Habilitar sitio
ln -sf /etc/nginx/sites-available/gamilit /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
# Verificar y reiniciar
nginx -t || { print_error "Configuracion Nginx invalida"; exit 1; }
systemctl restart nginx
print_success "Nginx configurado (HTTP)"
}
generate_self_signed_cert() {
print_step "Generando certificado auto-firmado..."
mkdir -p /etc/nginx/ssl
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=$SERVER_IP"
print_success "Certificado auto-firmado generado"
}
run_certbot() {
print_step "Ejecutando Certbot para obtener certificado SSL..."
local CERTBOT_DOMAINS="-d $DOMAIN"
if [ -n "$EXTRA_DOMAINS" ]; then
for d in $EXTRA_DOMAINS; do
CERTBOT_DOMAINS="$CERTBOT_DOMAINS -d $d"
done
fi
certbot --nginx $CERTBOT_DOMAINS --non-interactive --agree-tos --email admin@$DOMAIN
print_success "Certificado SSL obtenido"
# Verificar renovacion automatica
print_step "Verificando renovacion automatica..."
certbot renew --dry-run
print_success "Renovacion automatica configurada"
}
create_nginx_config_ssl_self_signed() {
print_step "Configurando Nginx con SSL auto-firmado..."
cat > /etc/nginx/sites-available/gamilit << EOF
# GAMILIT Platform - Nginx Configuration (Self-Signed SSL)
# Generado por setup-ssl-certbot.sh
# Redirect HTTP to HTTPS
server {
listen 80;
server_name $SERVER_IP;
return 301 https://\$server_name\$request_uri;
}
# HTTPS Server
server {
listen 443 ssl http2;
server_name $SERVER_IP;
# SSL (auto-firmado)
ssl_certificate /etc/nginx/ssl/gamilit.crt;
ssl_certificate_key /etc/nginx/ssl/gamilit.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# IMPORTANTE: NO agregar headers CORS aqui
# NestJS maneja CORS internamente
# Frontend (/)
location / {
proxy_pass http://localhost: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 (/api)
location /api {
proxy_pass http://localhost: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 (/socket.io)
location /socket.io {
proxy_pass http://localhost:3006;
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host \$host;
}
}
EOF
nginx -t || { print_error "Configuracion Nginx invalida"; exit 1; }
systemctl restart nginx
print_success "Nginx configurado con SSL auto-firmado"
}
update_env_files() {
print_step "Actualizando archivos .env..."
local PROTOCOL="https"
local HOST="$DOMAIN"
if [ "$SELF_SIGNED" = true ]; then
HOST="$SERVER_IP"
fi
# Backup
cp "$PROJECT_ROOT/apps/backend/.env.production" "$PROJECT_ROOT/apps/backend/.env.production.backup" 2>/dev/null || true
cp "$PROJECT_ROOT/apps/frontend/.env.production" "$PROJECT_ROOT/apps/frontend/.env.production.backup" 2>/dev/null || true
# Backend - actualizar CORS_ORIGIN y FRONTEND_URL
if [ -f "$PROJECT_ROOT/apps/backend/.env.production" ]; then
sed -i "s|^CORS_ORIGIN=.*|CORS_ORIGIN=https://$HOST|" "$PROJECT_ROOT/apps/backend/.env.production"
sed -i "s|^FRONTEND_URL=.*|FRONTEND_URL=https://$HOST|" "$PROJECT_ROOT/apps/backend/.env.production"
print_success "Backend .env.production actualizado"
else
print_warning "No se encontro apps/backend/.env.production"
fi
# Frontend - actualizar API y WS
if [ -f "$PROJECT_ROOT/apps/frontend/.env.production" ]; then
sed -i "s|^VITE_API_HOST=.*|VITE_API_HOST=$HOST|" "$PROJECT_ROOT/apps/frontend/.env.production"
sed -i "s|^VITE_API_PROTOCOL=.*|VITE_API_PROTOCOL=https|" "$PROJECT_ROOT/apps/frontend/.env.production"
sed -i "s|^VITE_WS_HOST=.*|VITE_WS_HOST=$HOST|" "$PROJECT_ROOT/apps/frontend/.env.production"
sed -i "s|^VITE_WS_PROTOCOL=.*|VITE_WS_PROTOCOL=wss|" "$PROJECT_ROOT/apps/frontend/.env.production"
print_success "Frontend .env.production actualizado"
else
print_warning "No se encontro apps/frontend/.env.production"
fi
}
rebuild_frontend() {
print_step "Rebuilding frontend con nuevas variables..."
cd "$PROJECT_ROOT/apps/frontend"
npm run build
cd "$PROJECT_ROOT"
print_success "Frontend rebuildeado"
}
restart_services() {
print_step "Reiniciando servicios PM2..."
pm2 restart all
sleep 3
print_success "Servicios PM2 reiniciados"
}
validate_ssl() {
print_step "Validando configuracion SSL..."
local HOST="$DOMAIN"
if [ "$SELF_SIGNED" = true ]; then
HOST="$SERVER_IP"
fi
# Verificar HTTPS
local HTTPS_STATUS=$(curl -sk -o /dev/null -w "%{http_code}" "https://$HOST" || echo "000")
if [ "$HTTPS_STATUS" == "200" ]; then
print_success "Frontend HTTPS: OK ($HTTPS_STATUS)"
else
print_warning "Frontend HTTPS: $HTTPS_STATUS"
fi
# Verificar API
local API_STATUS=$(curl -sk -o /dev/null -w "%{http_code}" "https://$HOST/api/health" || echo "000")
if [ "$API_STATUS" == "200" ]; then
print_success "Backend API HTTPS: OK ($API_STATUS)"
else
print_warning "Backend API HTTPS: $API_STATUS"
fi
# Verificar HTTP redirect
local HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "http://$HOST" || echo "000")
if [ "$HTTP_STATUS" == "301" ] || [ "$HTTP_STATUS" == "302" ]; then
print_success "HTTP redirect a HTTPS: OK"
else
print_warning "HTTP redirect: $HTTP_STATUS"
fi
}
print_summary() {
echo ""
echo -e "${GREEN}============================================================================${NC}"
echo -e "${GREEN} SSL CONFIGURADO EXITOSAMENTE${NC}"
echo -e "${GREEN}============================================================================${NC}"
echo ""
local HOST="$DOMAIN"
if [ "$SELF_SIGNED" = true ]; then
HOST="$SERVER_IP"
echo -e "${YELLOW}NOTA: Certificado auto-firmado. El navegador mostrara advertencia.${NC}"
echo ""
fi
echo " Frontend: https://$HOST"
echo " API: https://$HOST/api"
echo " Health: https://$HOST/api/health"
echo ""
echo " PM2: pm2 list"
echo " Logs: pm2 logs"
echo " Nginx: sudo systemctl status nginx"
echo ""
if [ "$SELF_SIGNED" = false ]; then
echo " Certificados: sudo certbot certificates"
echo " Renovar: sudo certbot renew"
fi
echo ""
echo -e "${GREEN}============================================================================${NC}"
}
show_help() {
echo "Uso: $0 <dominio> [dominios adicionales...]"
echo " $0 --self-signed"
echo ""
echo "Ejemplos:"
echo " $0 gamilit.com"
echo " $0 gamilit.com www.gamilit.com"
echo " $0 --self-signed"
echo ""
echo "Opciones:"
echo " --self-signed Generar certificado auto-firmado (sin dominio)"
echo " --help, -h Mostrar esta ayuda"
}
################################################################################
# MAIN
################################################################################
print_header
# Parsear argumentos
if [ $# -eq 0 ]; then
show_help
exit 1
fi
if [ "$1" == "--help" ] || [ "$1" == "-h" ]; then
show_help
exit 0
fi
if [ "$1" == "--self-signed" ]; then
SELF_SIGNED=true
else
DOMAIN="$1"
shift
EXTRA_DOMAINS="$*"
fi
# Verificar root
check_root
# Ejecutar pasos
check_prerequisites
verify_dns
if [ "$SELF_SIGNED" = true ]; then
create_nginx_config_http
generate_self_signed_cert
create_nginx_config_ssl_self_signed
else
create_nginx_config_http
run_certbot
fi
update_env_files
rebuild_frontend
restart_services
validate_ssl
print_summary
echo ""
print_success "Setup SSL completado"