CRITICAL fixes: - Restrict X-View-Tenant impersonation to global admin only (was any admin) - Add authorization to subscription endpoints (was open to any user) - Make webhook signature verification mandatory (was skippable) - Remove databaseName from JWT payload (resolve server-side with cache) - Reduce body size limit from 1GB to 10MB (50MB for bulk CFDI) - Restrict .env file permissions to 600 HIGH fixes: - Add authorization to SAT cron endpoints (global admin only) - Add Content-Security-Policy and Permissions-Policy headers - Centralize isGlobalAdmin() utility with caching - Add rate limiting on auth endpoints (express-rate-limit) - Require authentication on logout endpoint MEDIUM fixes: - Replace Math.random() with crypto.randomBytes for temp passwords - Remove console.log of temporary passwords in production - Remove DB credentials from admin notification email - Add escapeHtml() to email templates (prevent HTML injection) - Add file size validation on FIEL upload (50KB max) - Require TLS for SMTP connections - Normalize email to lowercase before uniqueness check - Remove hardcoded default for FIEL_ENCRYPTION_KEY Also includes: - Complete production deployment documentation - API reference documentation - Security audit report with remediation details - Updated README with v0.5.0 changelog - New client admin email template - Utility scripts (create-carlos, test-emails) - PM2 ecosystem config updates Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6.0 KiB
6.0 KiB
Guía de Despliegue en Producción - Horux360
Infraestructura
Servidor
- OS: Ubuntu 24.04 LTS
- RAM: 22GB
- CPU: 8 cores
- Dominio: horuxfin.com (DNS en AWS Route 53)
- SSL: Let's Encrypt (certificado real via DNS challenge)
- IP Interna: 192.168.10.212
Stack
| Componente | Tecnología | Puerto |
|---|---|---|
| Reverse Proxy | Nginx 1.24 | 80/443 |
| API | Node.js + Express + tsx | 4000 |
| Frontend | Next.js 14 | 3000 |
| Base de datos | PostgreSQL 16 | 5432 |
| Process Manager | PM2 | — |
Arquitectura de Red
Internet
│
▼
Nginx (443/SSL)
├── /api/* → 127.0.0.1:4000 (horux-api)
├── /api/auth/* → 127.0.0.1:4000 (rate limit: 5r/s)
├── /api/webhooks/* → 127.0.0.1:4000 (rate limit: 10r/s)
├── /health → 127.0.0.1:4000
└── /* → 127.0.0.1:3000 (horux-web)
PM2 - Gestión de Procesos
Configuración (ecosystem.config.js)
module.exports = {
apps: [
{
name: 'horux-api',
interpreter: 'node',
script: '/root/Horux/node_modules/.pnpm/tsx@4.21.0/node_modules/tsx/dist/cli.mjs',
args: 'src/index.ts',
cwd: '/root/Horux/apps/api',
instances: 1,
exec_mode: 'fork',
autorestart: true,
max_memory_restart: '1G',
kill_timeout: 5000,
listen_timeout: 10000,
env: { NODE_ENV: 'production', PORT: 4000 },
},
{
name: 'horux-web',
script: 'node_modules/next/dist/bin/next',
args: 'start',
cwd: '/root/Horux/apps/web',
instances: 1,
exec_mode: 'fork',
autorestart: true,
max_memory_restart: '512M',
kill_timeout: 5000,
env: { NODE_ENV: 'production', PORT: 3000 },
},
],
};
Notas
- La API usa
tsxen lugar detsccompilado porque@horux/sharedexporta TypeScript raw (ESM) quedist/no puede resolver. - Next.js usa la ruta directa
node_modules/next/dist/bin/nextporquenode_modules/.bin/nextes un shell script que PM2 no puede ejecutar como script Node.js.
Comandos Útiles
pm2 restart all # Reiniciar todo
pm2 logs horux-api # Ver logs del API
pm2 logs horux-web # Ver logs del frontend
pm2 monit # Monitor en tiempo real
pm2 save # Guardar estado actual
pm2 startup # Configurar inicio automático
Nginx
Archivo: /etc/nginx/sites-available/horux360.conf
Rate Limiting
| Zona | Límite | Burst | Uso |
|---|---|---|---|
auth |
5r/s | 10 | /api/auth/* |
webhook |
10r/s | 20 | /api/webhooks/* |
api |
30r/s | 50 | /api/* (general) |
Security Headers
Content-Security-Policy: Restrictivo (default-src 'self')Strict-Transport-Security: 1 año con includeSubDomainsX-Frame-Options: SAMEORIGINX-Content-Type-Options: nosniffPermissions-Policy: camera, microphone, geolocation deshabilitadosReferrer-Policy: strict-origin-when-cross-origin
Body Limits
- Global:
50M(Nginx) - API default:
10mb(Express) /api/cfdi/bulk:50mb(Express route-specific)
Renovar SSL
certbot renew --dry-run # Verificar
certbot renew # Renovar
PostgreSQL
Configuración de Rendimiento (postgresql.conf)
| Parámetro | Valor | Descripción |
|---|---|---|
max_connections |
300 | Para multi-tenant con pools por tenant |
shared_buffers |
4GB | ~18% de 22GB RAM |
work_mem |
16MB | Memoria por operación de sort/hash |
effective_cache_size |
16GB | ~72% de RAM |
maintenance_work_mem |
512MB | Para VACUUM, CREATE INDEX |
wal_buffers |
64MB | Write-ahead log buffers |
Arquitectura Multi-Tenant
Cada cliente tiene su propia base de datos PostgreSQL:
horux360 ← Base central (tenants, users, subscriptions)
horux_cas2408138w2 ← Base del admin global
horux_<rfc> ← Base de cada cliente
Backups
# Cron job: 0 1 * * * /root/Horux/scripts/backup.sh
# Ubicación: /var/horux/backups/
# Retención: 7 diarios + 4 semanales
Variables de Entorno
API (apps/api/.env)
NODE_ENV=production
PORT=4000
DATABASE_URL="postgresql://postgres:<password>@localhost:5432/horux360?schema=public"
JWT_SECRET=<min 32 chars>
JWT_EXPIRES_IN=15m
JWT_REFRESH_EXPIRES_IN=7d
CORS_ORIGIN=https://horuxfin.com
FRONTEND_URL=https://horuxfin.com
FIEL_ENCRYPTION_KEY=<min 32 chars, REQUERIDO>
FIEL_STORAGE_PATH=/var/horux/fiel
# MercadoPago
MP_ACCESS_TOKEN=<token>
MP_WEBHOOK_SECRET=<secret, REQUERIDO para producción>
# SMTP (Google Workspace)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=ivan@horuxfin.com
SMTP_PASS=<app-password>
SMTP_FROM=Horux360 <ivan@horuxfin.com>
# Admin
ADMIN_EMAIL=carlos@horuxfin.com
Web (apps/web/.env.local)
NEXT_PUBLIC_API_URL=https://horuxfin.com/api
Directorios Importantes
/root/Horux/ ← Código fuente
/var/horux/fiel/ ← Archivos FIEL encriptados (0700)
/var/horux/backups/ ← Backups de PostgreSQL
/etc/nginx/sites-available/ ← Config de Nginx
/etc/letsencrypt/live/ ← Certificados SSL
Despliegue de Cambios
# 1. Pull cambios
cd /root/Horux
git pull origin main
# 2. Instalar dependencias
pnpm install
# 3. Build
pnpm build
# 4. Reiniciar servicios
pm2 restart all
# 5. Si hay cambios en nginx:
cp deploy/nginx/horux360.conf /etc/nginx/sites-available/horux360.conf
nginx -t && systemctl reload nginx
Troubleshooting
API no inicia
pm2 logs horux-api --lines 50 # Ver logs de error
pm2 restart horux-api # Reiniciar
Puerto en uso
lsof -i :4000 # Ver quién usa el puerto
kill <PID> # Matar proceso
pm2 restart horux-api
Certificado SSL expirado
certbot renew
systemctl reload nginx
Base de datos lenta
sudo -u postgres psql -c "SELECT * FROM pg_stat_activity WHERE state = 'active';"