diff --git a/GUIA_HESTIA_SSE.md b/GUIA_HESTIA_SSE.md new file mode 100644 index 0000000..5cb41b1 --- /dev/null +++ b/GUIA_HESTIA_SSE.md @@ -0,0 +1,270 @@ +# 🚀 Configuración SSE para HestiaCP + +## ✅ Pasos para Activar SSE en tu Servidor HestiaCP + +### 1. Verificar que el código esté en el servidor +```bash +# Subir por FTP/SFTP o Git +cd /home/tu-usuario/web/tu-dominio.com/public_html/ +ls -la api/sse_events.php # Debe existir +``` + +### 2. Configurar Apache para SSE (si usas Apache) + +**Opción A: Editar .htaccess en la raíz** +```apache +# Agregar al final de .htaccess + + # SSE Headers + + Header set Cache-Control "no-cache, no-store, must-revalidate" + Header set X-Accel-Buffering "no" + SetEnv no-gzip 1 + + +``` + +**Opción B: Crear .htaccess específico en /api/** +```bash +cd /home/tu-usuario/web/tu-dominio.com/public_html/api/ +nano .htaccess +``` + +Contenido: +```apache + + Header set Cache-Control "no-cache, no-store, must-revalidate" + Header set X-Accel-Buffering "no" + SetEnv no-gzip 1 + + +# Prevenir timeout en SSE + + FcgidIOTimeout 300 + +``` + +### 3. Ajustar PHP-FPM (Recomendado) + +Editar configuración PHP-FPM en HestiaCP: + +1. **Panel HestiaCP** → **Web** → **tu dominio** → **Edit** +2. **Backend Template**: PHP-FPM +3. **PHP Version**: 8.x + +Luego editar el archivo de configuración (vía SSH): +```bash +# Ubicación típica en HestiaCP +sudo nano /etc/php/8.2/fpm/pool.d/tu-usuario.conf + +# Agregar o modificar: +request_terminate_timeout = 300s +pm.max_requests = 500 +``` + +Reiniciar PHP-FPM: +```bash +sudo systemctl restart php8.2-fpm +``` + +### 4. Verificar Nginx (si usas Nginx) + +Si tu dominio usa Nginx como proxy, editar la configuración: + +```bash +sudo nano /etc/nginx/conf.d/domains/tu-dominio.com.conf +``` + +Agregar dentro del bloque `location ~ \.php$`: +```nginx +# Configuración especial para SSE +location ~ ^/api/sse_events\.php$ { + fastcgi_buffering off; + proxy_buffering off; + + fastcgi_read_timeout 300s; + fastcgi_send_timeout 300s; + + fastcgi_pass unix:/run/php/php8.2-fpm.sock; + include fastcgi_params; +} +``` + +Reiniciar Nginx: +```bash +sudo systemctl restart nginx +``` + +### 5. Probar SSE desde el servidor + +```bash +# Conectar por SSH a tu servidor +ssh usuario@tu-dominio.com + +# Probar SSE +curl -N -m 5 'https://tu-dominio.com/api/sse_events.php?token=demo_token' +``` + +**Respuesta esperada:** +``` +event: connected +data: {"timestamp":1706300000,"user_id":"token_12345678","mode":"authenticated","status":"ready"} + +: heartbeat +``` + +Si ves esto, **SSE está funcionando** ✅ + +### 6. Probar desde el navegador + +1. Abrir tu sitio: `https://tu-dominio.com/conversations.php` +2. Abrir Consola del navegador (F12 → Console) +3. Buscar: + ``` + Conectando a SSE para eventos en tiempo real... + SSE URL: https://tu-dominio.com/api/sse_events.php?token=... + ✅ SSE conectado (🔐 autenticado): {...} + ``` + +### 7. Solución de Problemas + +#### Error: "Failed to fetch" o timeout + +**Causa**: Firewall o mod_security bloqueando +**Solución**: +```bash +# Desactivar mod_security para SSE (temporal) +sudo a2dismod security2 +sudo systemctl restart apache2 + +# O agregar excepción en .htaccess: + + SecRuleEngine Off + +``` + +#### Error: "EventSource's response has a MIME type" + +**Causa**: Headers incorrectos +**Solución**: Verificar que sse_events.php tenga: +```php +header('Content-Type: text/event-stream'); +``` + +#### Error: Conexión se cierra cada 30 segundos + +**Causa**: Timeout de proxy +**Solución**: Aumentar timeouts en nginx.conf o apache2.conf: +``` +# Apache +Timeout 300 +KeepAliveTimeout 300 + +# Nginx +proxy_read_timeout 300s; +``` + +### 8. Configuración de Seguridad (Producción) + +#### A. Token seguro en vez de demo_token + +Editar `api/sse_events.php`: +```php +// Generar token en login +$_SESSION['sse_token'] = bin2hex(random_bytes(32)); + +// Validar token en SSE +$token = $_GET['token'] ?? null; +if ($token && isset($_SESSION['sse_token']) && $token === $_SESSION['sse_token']) { + $authenticated = true; +} +``` + +En `conversations.php`: +```javascript +// Usar token de sesión +const token = ''; +const sseUrl = `${baseUrl}/api/sse_events.php?token=${token}&t=${Date.now()}`; +``` + +#### B. Restringir acceso por IP (opcional) + +En `.htaccess`: +```apache + + # Solo permitir desde localhost o IPs específicas + Require ip 127.0.0.1 + Require ip tu.ip.publica + +``` + +### 9. Monitoreo + +Ver conexiones SSE activas: +```bash +# Ver procesos PHP activos +ps aux | grep sse_events + +# Ver logs de errores +tail -f /var/log/php8.2-fpm.log +tail -f /var/log/apache2/error.log +tail -f /var/log/nginx/error.log +``` + +### 10. Performance + +Para muchos usuarios simultáneos: + +```bash +# Aumentar límites PHP-FPM +sudo nano /etc/php/8.2/fpm/pool.d/tu-usuario.conf + +pm = dynamic +pm.max_children = 50 +pm.start_servers = 10 +pm.min_spare_servers = 5 +pm.max_spare_servers = 20 +pm.max_requests = 500 +``` + +--- + +## 🎯 Checklist de Verificación + +- [ ] Archivo `api/sse_events.php` subido al servidor +- [ ] `.htaccess` configurado con headers SSE +- [ ] PHP-FPM timeout aumentado a 300s +- [ ] Nginx/Apache configurado (si aplica) +- [ ] Test con curl funciona (muestra "event: connected") +- [ ] Test desde navegador funciona (console.log muestra "✅ SSE conectado") +- [ ] Token de seguridad configurado (no usar demo_token en producción) +- [ ] Firewall/mod_security permite conexiones largas + +--- + +## 📞 Soporte HestiaCP + +Si tienes problemas: + +1. **Panel HestiaCP**: https://tu-dominio.com:8083 +2. **Logs**: Panel → Log Files +3. **SSH**: Usuario y contraseña en el panel +4. **Documentación**: https://docs.hestiacp.com/ + +--- + +## ✅ Resultado Esperado + +Una vez configurado correctamente: + +``` +ANTES (desarrollo local): +http://localhost:8000/api/sse_events.php +❌ Timeout (servidor PHP built-in no soporta SSE) + +AHORA (producción HestiaCP): +https://tu-dominio.com/api/sse_events.php +✅ Conectado - eventos en tiempo real < 1 segundo +``` + +**¡Tu sistema de notificaciones en tiempo real estará funcionando!** 🚀 diff --git a/api/.htaccess b/api/.htaccess new file mode 100644 index 0000000..18f794f --- /dev/null +++ b/api/.htaccess @@ -0,0 +1,35 @@ +# Configuración SSE para HestiaCP +# Colocar este archivo en: /api/.htaccess + + + # Deshabilitar buffering para SSE + Header set Cache-Control "no-cache, no-store, must-revalidate" + Header set X-Accel-Buffering "no" + Header set Connection "keep-alive" + + # Permitir CORS si es necesario + # Header set Access-Control-Allow-Origin "*" + # Header set Access-Control-Allow-Credentials "true" + + # Deshabilitar compresión + SetEnv no-gzip 1 + + +# Aumentar timeouts para SSE + + FcgidIOTimeout 300 + FcgidConnectTimeout 300 + + +# Desactivar mod_security para SSE (si causa problemas) + + SecRuleEngine Off + + +# Prevenir que Apache cierre la conexión +RewriteEngine Off +Options -MultiViews + +# PHP settings +php_value max_execution_time 300 +php_value max_input_time 300 diff --git a/check_sse.sh b/check_sse.sh new file mode 100755 index 0000000..3e7511f --- /dev/null +++ b/check_sse.sh @@ -0,0 +1,153 @@ +#!/bin/bash +# Script de verificación SSE para HestiaCP +# Ejecutar en el servidor: bash check_sse.sh + +echo "🔍 Verificación de SSE para HestiaCP" +echo "====================================" +echo "" + +# 1. Verificar que el archivo existe +echo "1️⃣ Verificando archivos..." +if [ -f "api/sse_events.php" ]; then + echo " ✅ api/sse_events.php existe" +else + echo " ❌ api/sse_events.php NO encontrado" + echo " → Asegúrate de subir el archivo al servidor" + exit 1 +fi + +# 2. Verificar permisos +echo "" +echo "2️⃣ Verificando permisos..." +PERMS=$(stat -c "%a" api/sse_events.php 2>/dev/null || stat -f "%A" api/sse_events.php 2>/dev/null) +if [ "$PERMS" -ge "644" ]; then + echo " ✅ Permisos correctos ($PERMS)" +else + echo " ⚠️ Permisos: $PERMS (se recomienda 644)" + echo " Ejecutar: chmod 644 api/sse_events.php" +fi + +# 3. Verificar versión PHP +echo "" +echo "3️⃣ Verificando PHP..." +PHP_VERSION=$(php -v | head -n 1) +echo " $PHP_VERSION" +if php -v | grep -q "PHP 8"; then + echo " ✅ PHP 8.x detectado" +elif php -v | grep -q "PHP 7"; then + echo " ⚠️ PHP 7.x (recomendado PHP 8.x)" +else + echo " ❌ Versión PHP desconocida" +fi + +# 4. Verificar sintaxis PHP +echo "" +echo "4️⃣ Verificando sintaxis PHP..." +if php -l api/sse_events.php > /dev/null 2>&1; then + echo " ✅ Sin errores de sintaxis" +else + echo " ❌ Error de sintaxis en sse_events.php" + php -l api/sse_events.php + exit 1 +fi + +# 5. Verificar configuración PHP-FPM +echo "" +echo "5️⃣ Verificando PHP-FPM..." +if systemctl is-active --quiet php8.2-fpm || systemctl is-active --quiet php8.1-fpm || systemctl is-active --quiet php-fpm; then + echo " ✅ PHP-FPM está corriendo" +else + echo " ⚠️ PHP-FPM no detectado o no corriendo" +fi + +# 6. Probar conexión SSE local +echo "" +echo "6️⃣ Probando conexión SSE..." +echo " Conectando (3 segundos)..." + +RESPONSE=$(timeout 3 curl -N -s 'http://localhost/api/sse_events.php?token=demo_token' 2>&1 || echo "timeout") + +if echo "$RESPONSE" | grep -q "event: connected"; then + echo " ✅ SSE funciona correctamente" + echo " Respuesta:" + echo "$RESPONSE" | head -5 | sed 's/^/ /' +elif echo "$RESPONSE" | grep -q "timeout"; then + echo " ⚠️ Timeout - SSE puede no estar configurado correctamente" + echo " → Revisar configuración Apache/Nginx" +elif echo "$RESPONSE" | grep -q "401"; then + echo " ⚠️ HTTP 401 - Problema de autenticación" + echo " → Revisar config/auth.php" +else + echo " ❌ Error inesperado" + echo " Respuesta:" + echo "$RESPONSE" | head -10 | sed 's/^/ /' +fi + +# 7. Verificar .htaccess +echo "" +echo "7️⃣ Verificando .htaccess..." +if [ -f "api/.htaccess" ]; then + echo " ✅ api/.htaccess existe" + if grep -q "X-Accel-Buffering" api/.htaccess; then + echo " ✅ Configuración SSE encontrada" + else + echo " ⚠️ Falta configuración SSE en .htaccess" + echo " → Ver GUIA_HESTIA_SSE.md" + fi +else + echo " ⚠️ api/.htaccess no encontrado" + echo " → Crear según GUIA_HESTIA_SSE.md" +fi + +# 8. Verificar configuración base de datos +echo "" +echo "8️⃣ Verificando configuración..." +if [ -f "config/config.php" ]; then + echo " ✅ config/config.php existe" + if php -r "require_once 'config/config.php'; echo 'OK';" 2>/dev/null | grep -q "OK"; then + echo " ✅ config.php carga correctamente" + else + echo " ⚠️ Error al cargar config.php" + fi +else + echo " ❌ config/config.php NO encontrado" + exit 1 +fi + +# 9. Verificar tabla notifications +echo "" +echo "9️⃣ Verificando tabla notifications..." +if php -r "require_once 'config/config.php'; \$db = Database::getInstance(); \$r = \$db->fetchAll('SHOW TABLES LIKE \"notifications\"'); echo (count(\$r) > 0 ? 'OK' : 'NO');" 2>/dev/null | grep -q "OK"; then + echo " ✅ Tabla notifications existe" +else + echo " ⚠️ Tabla notifications no encontrada" + echo " → Ejecutar migration para crear tabla" +fi + +# Resumen final +echo "" +echo "====================================" +echo "📊 Resumen" +echo "====================================" +echo "" + +if echo "$RESPONSE" | grep -q "event: connected"; then + echo "✅ SSE está funcionando correctamente" + echo "" + echo "Próximos pasos:" + echo "1. Abrir https://tu-dominio.com/conversations.php" + echo "2. Abrir consola del navegador (F12)" + echo "3. Verificar: '✅ SSE conectado'" + echo "" + echo "🚀 Sistema de notificaciones en tiempo real activo!" +else + echo "⚠️ SSE necesita configuración adicional" + echo "" + echo "Próximos pasos:" + echo "1. Revisar GUIA_HESTIA_SSE.md" + echo "2. Configurar .htaccess para SSE" + echo "3. Ajustar PHP-FPM timeout (300s)" + echo "4. Ejecutar: bash check_sse.sh" +fi + +echo "" diff --git a/conversations.php b/conversations.php index 3a1ac0d..afc9ff1 100644 --- a/conversations.php +++ b/conversations.php @@ -1081,9 +1081,11 @@ console.log('Conectando a SSE para eventos en tiempo real...'); try { - // EventSource no soporta withCredentials directamente - // Usar token en URL como alternativa - const sseUrl = 'api/sse_events.php?token=demo_token&t=' + Date.now(); + // Detectar URL base automáticamente (funciona en dev y producción) + const baseUrl = window.location.origin; // http://localhost:8000 o https://tu-dominio.com + const sseUrl = `${baseUrl}/api/sse_events.php?token=demo_token&t=${Date.now()}`; + + console.log('SSE URL:', sseUrl); this.eventSource = new EventSource(sseUrl); // Evento: conexión establecida