diff --git a/DEPLOY_DEBIAN.md b/DEPLOY_DEBIAN.md new file mode 100644 index 0000000..54a8784 --- /dev/null +++ b/DEPLOY_DEBIAN.md @@ -0,0 +1,283 @@ +# COCONEWS · Despliegue en Debian (sin Docker) + +Guía completa para instalar y operar COCONEWS en un servidor Debian 12 (Bookworm) o Ubuntu 22.04+, sin Docker ni contenedores. + +--- + +## Requisitos de hardware + +| Modo | CPU | RAM | Disco | +|------|-----|-----|-------| +| **Mínimo (solo CPU)** | 4 cores | 8 GB | 40 GB | +| **Recomendado** | 8 cores | 16 GB | 80 GB | +| **Con GPU** | 8 cores + NVIDIA | 16 GB | 80 GB | + +> Los modelos de IA (NLLB-200 + MiniLM + spaCy) ocupan ~5 GB en disco una vez descargados. + +--- + +## Servicios que se instalan en el servidor + +| Servicio | Tecnología | Gestionado por | +|----------|-----------|----------------| +| Base de datos | PostgreSQL 16 | apt + systemd | +| Caché | Redis 7 | apt + systemd | +| Búsqueda vectorial | Qdrant (binario) | systemd | +| API REST | Go (backend) | systemd | +| Ingestor RSS | Go | systemd | +| Scraper / Discovery / Wiki / Topics / Related / Qdrant-worker | Go | systemd | +| Traducción (NLLB-200) | Python + CTranslate2 | systemd | +| Embeddings | Python + Sentence-Transformers | systemd | +| NER | Python + spaCy | systemd | +| Clustering / Categorización | Python | systemd | +| Frontend | React (estático compilado) | nginx | +| Proxy / Web | nginx | apt + systemd | + +--- + +## Instalación paso a paso + +### 1. Clonar el repositorio + +```bash +git clone https://gitea.laenre.net/pietre/rss2.git /opt/src/rss2 +cd /opt/src/rss2 +git checkout coconews +``` + +### 2. Configurar variables de entorno + +```bash +cp deploy/debian/env.example /opt/rss2/.env +nano /opt/rss2/.env +``` + +Valores que **debes cambiar obligatoriamente**: + +```env +POSTGRES_PASSWORD=contraseña_segura_postgres +DB_PASS=contraseña_segura_postgres +REDIS_PASSWORD=contraseña_segura_redis +SECRET_KEY=cadena_aleatoria_minimo_32_caracteres +``` + +Genera claves seguras con: +```bash +openssl rand -hex 32 +``` + +### 3. Descargar y convertir el modelo de traducción (NLLB-200) + +Este paso se hace **una sola vez** y puede tardar 10-30 minutos dependiendo de la conexión. + +```bash +# Instalar dependencias Python primero +python3 -m venv /opt/rss2/venv +/opt/rss2/venv/bin/pip install ctranslate2 transformers sentencepiece + +# Convertir modelo NLLB-200 a formato CTranslate2 +/opt/rss2/venv/bin/ct2-opus-mt-converter \ + --model facebook/nllb-200-distilled-600M \ + --output_dir /opt/rss2/models/nllb-ct2 \ + --quantization int8 + +# Alternativa si el comando anterior falla: +/opt/rss2/venv/bin/python -c " +import ctranslate2 +ctranslate2.converters.OpusMTConverter( + 'facebook/nllb-200-distilled-600M' +).convert('/opt/rss2/models/nllb-ct2', quantization='int8') +" +``` + +### 4. Ejecutar el instalador + +```bash +sudo bash /opt/src/rss2/deploy/debian/install.sh +``` + +El script hace automáticamente: +- Instala PostgreSQL, Redis, nginx, Go, Node.js via apt +- Descarga el binario de Qdrant +- Crea el usuario `rss2` del sistema +- Crea la base de datos y ejecuta las migraciones +- Compila los 8 binarios Go +- Compila el frontend React +- Instala y habilita los 16 servicios systemd + +--- + +## Verificar que funciona + +```bash +# Estado de todos los servicios +systemctl status rss2-backend rss2-ingestor rss2-translator rss2-embeddings + +# Ver logs en tiempo real +journalctl -u rss2-backend -f +journalctl -u rss2-translator -f + +# Comprobar que el API responde +curl http://localhost:8080/api/stats + +# Acceder al frontend +# http://IP_DEL_SERVIDOR:8001 +``` + +--- + +## Gestión de servicios + +### Iniciar / parar / reiniciar + +```bash +# Un servicio concreto +systemctl start rss2-backend +systemctl stop rss2-translator +systemctl restart rss2-embeddings + +# Todos los workers de una vez +systemctl restart rss2-backend rss2-ingestor rss2-scraper rss2-discovery \ + rss2-wiki rss2-topics rss2-related rss2-qdrant-worker \ + rss2-langdetect rss2-translation-scheduler rss2-translator \ + rss2-embeddings rss2-ner rss2-cluster rss2-categorizer +``` + +### Ver logs + +```bash +journalctl -u rss2-backend -f # API Go +journalctl -u rss2-translator -f # Traductor +journalctl -u rss2-embeddings -f # Embeddings +journalctl -u rss2-ner -f # NER entidades +journalctl -u rss2-ingestor -f # Ingestor RSS +``` + +--- + +## Actualizar el código + +Cuando hay nuevos cambios en el repositorio: + +```bash +cd /opt/src/rss2 +git pull +sudo bash deploy/debian/build.sh +``` + +El script `build.sh` recompila los binarios Go, el frontend y sincroniza los workers Python, y reinicia los servicios automáticamente. + +--- + +## Estructura de directorios en el servidor + +``` +/opt/rss2/ +├── .env # Variables de entorno (permisos 600) +├── bin/ # Binarios Go compilados +│ ├── server # API REST +│ ├── ingestor # Ingestor RSS +│ ├── scraper +│ ├── discovery +│ ├── wiki_worker +│ ├── topics +│ ├── related +│ └── qdrant_worker +├── src/ +│ └── workers/ # Workers Python +├── venv/ # Virtualenv Python (ML) +├── models/ +│ └── nllb-ct2/ # Modelo traduccion CTranslate2 +├── hf_cache/ # Cache HuggingFace (embeddings, NER) +├── frontend/ +│ └── dist/ # Frontend React compilado (servido por nginx) +├── data/ +│ ├── wiki_images/ # Imagenes Wikipedia descargadas +│ └── qdrant_storage/ # Datos vectoriales Qdrant +└── qdrant/ + └── qdrant # Binario Qdrant +``` + +--- + +## Requisitos de red / firewall + +Solo exponer al exterior el puerto **8001** (nginx). El resto deben ser internos: + +```bash +# Con ufw: +ufw allow 8001/tcp # COCONEWS web +ufw deny 5432/tcp # PostgreSQL - solo localhost +ufw deny 6379/tcp # Redis - solo localhost +ufw deny 6333/tcp # Qdrant - solo localhost +ufw deny 8080/tcp # API Go - solo localhost (nginx hace proxy) +ufw enable +``` + +--- + +## Backup de datos + +```bash +# PostgreSQL +sudo -u postgres pg_dump rss > /opt/rss2/backups/rss_$(date +%Y%m%d).sql + +# Datos Qdrant +systemctl stop rss2-qdrant +tar -czf /opt/rss2/backups/qdrant_$(date +%Y%m%d).tar.gz /opt/rss2/data/qdrant_storage +systemctl start rss2-qdrant + +# Imagenes Wikipedia (opcional, se pueden re-descargar) +tar -czf /opt/rss2/backups/wiki_images_$(date +%Y%m%d).tar.gz /opt/rss2/data/wiki_images +``` + +--- + +## Solución de problemas frecuentes + +### El traductor no arranca + +```bash +journalctl -u rss2-translator -n 50 +# Si dice "model not found": el modelo NLLB-200 no está convertido +# Ejecutar el paso 3 de la instalación +``` + +### PostgreSQL rechaza la conexión + +```bash +# Verificar que el .env tiene DB_HOST=127.0.0.1 (no "db") +grep DB_HOST /opt/rss2/.env + +# Verificar que el usuario existe +sudo -u postgres psql -c "\du" +``` + +### nginx devuelve 502 Bad Gateway + +```bash +# El backend Go no está corriendo +systemctl status rss2-backend +journalctl -u rss2-backend -n 30 +``` + +### Memoria insuficiente para los modelos Python + +Con 8 GB RAM el translator + embeddings + NER pueden coincidir. Si el servidor tiene poca RAM, deshabilitar el translator-gpu y bajar el batch: + +```bash +# En /opt/rss2/.env +TRANSLATOR_BATCH=8 +EMB_BATCH=32 +NER_BATCH=16 +systemctl restart rss2-translator rss2-embeddings rss2-ner +``` + +--- + +## Primer inicio de sesión + +1. Abrir `http://IP:8001` en el navegador +2. Al no haber usuarios, el sistema te redirige al registro +3. El primer usuario registrado se convierte en **administrador** +4. Ir a Configuración → Feeds → Importar el `feeds.csv` del repositorio para empezar con fuentes precargadas