From 6487a7857c3037f2706b1b30d454d53e79441965 Mon Sep 17 00:00:00 2001 From: markosbenitez Date: Mon, 25 May 2026 11:20:48 -0300 Subject: [PATCH] =?UTF-8?q?Add=20DEPLOY.md=20=E2=80=94=20gu=C3=ADa=20compl?= =?UTF-8?q?eta=20de=20despliegue=20en=20VPS=20Ubuntu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Paso a paso para delegar el deploy a equipo técnico: usuario dedicado, uv, .env seguro, cifrado de credenciales, systemd service, firewall UFW, monitoreo con journalctl, procedimiento de actualización y troubleshooting. Co-Authored-By: Claude Sonnet 4.6 --- DEPLOY.md | 593 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 593 insertions(+) create mode 100644 DEPLOY.md diff --git a/DEPLOY.md b/DEPLOY.md new file mode 100644 index 0000000..69cfaec --- /dev/null +++ b/DEPLOY.md @@ -0,0 +1,593 @@ +# Guía de despliegue — Pedrito Hechakuaa en VPS Ubuntu + +> **Destinatario:** equipo técnico de InQuality +> **Entorno objetivo:** VPS Ubuntu en Hostinger — pre-producción estable +> **Tiempo estimado:** 30–45 minutos +> **Acceso requerido:** SSH root a la VPS + datos de configuración provistos por Marcos + +--- + +## Índice + +1. [Antes de empezar — datos que necesitás de Marcos](#1-antes-de-empezar) +2. [Conectarse a la VPS](#2-conectarse-a-la-vps) +3. [Crear usuario dedicado](#3-crear-usuario-dedicado) +4. [Instalar dependencias del sistema](#4-instalar-dependencias-del-sistema) +5. [Clonar el repositorio](#5-clonar-el-repositorio) +6. [Instalar dependencias del proyecto](#6-instalar-dependencias-del-proyecto) +7. [Configurar el archivo .env](#7-configurar-el-archivo-env) +8. [Cifrar las credenciales del PJ](#8-cifrar-las-credenciales-del-pj) +9. [Verificar que el bot arranca](#9-verificar-que-el-bot-arranca) +10. [Crear el servicio systemd](#10-crear-el-servicio-systemd) +11. [Configurar el firewall](#11-configurar-el-firewall) +12. [Verificación final](#12-verificación-final) +13. [Monitoreo y logs](#13-monitoreo-y-logs) +14. [Cómo actualizar el bot](#14-cómo-actualizar-el-bot) +15. [Troubleshooting](#15-troubleshooting) + +--- + +## 1. Antes de empezar + +Antes de tocar la VPS, pedile a Marcos que te provea estos datos. Sin ellos no podés completar el deploy. + +| Dato | Dónde conseguirlo | Dónde va | +|------|------------------|----------| +| `FERNET_KEY` | Marcos la genera o te la pasa | `.env` | +| `TELEGRAM_BOT_TOKEN` | Token del bot de Telegram (de @BotFather) | `.env` | +| `TELEGRAM_CHAT_ID` | Chat ID de Telegram de Marcos (de @userinfobot) | `.env` | +| Cédula de identidad del PJ | Marcos | Script de cifrado (paso 8) | +| Contraseña del sistema del PJ | Marcos | Script de cifrado (paso 8) | +| IP de la VPS | Panel de Hostinger | SSH | + +> ⚠️ **Seguridad:** No guardes la contraseña del PJ en ningún archivo, chat ni nota. +> El script de cifrado (paso 8) la pide interactivamente y la descarta de memoria al terminar. +> Solo persiste cifrada en `.env`. + +--- + +## 2. Conectarse a la VPS + +```bash +ssh root@ +``` + +Si usás clave SSH (recomendado): +```bash +ssh -i ~/.ssh/id_rsa root@ +``` + +Verificar que el sistema está actualizado: +```bash +apt update && apt upgrade -y +``` + +--- + +## 3. Crear usuario dedicado + +El bot no debe correr como root. Creamos un usuario propio llamado `pedrito`. + +```bash +# Crear usuario sin contraseña de login (solo acceso SSH) +adduser pedrito --disabled-password --gecos "" + +# Verificar que se creó correctamente +id pedrito +# Salida esperada: uid=1001(pedrito) gid=1001(pedrito) groups=1001(pedrito) +``` + +### Configurar acceso SSH para el usuario pedrito + +```bash +# Crear directorio SSH para el usuario +mkdir -p /home/pedrito/.ssh + +# Copiar las claves autorizadas de root (si ya tenés acceso por clave SSH como root) +cp /root/.ssh/authorized_keys /home/pedrito/.ssh/ + +# Dar los permisos correctos (obligatorio para que SSH funcione) +chown -R pedrito:pedrito /home/pedrito/.ssh +chmod 700 /home/pedrito/.ssh +chmod 600 /home/pedrito/.ssh/authorized_keys +``` + +> Podés verificar el acceso abriendo una segunda terminal: +> ```bash +> ssh pedrito@ +> ``` +> Si entra sin pedir contraseña, todo está bien. + +--- + +## 4. Instalar dependencias del sistema + +```bash +# Aún como root +apt install -y git curl +``` + +Verificar Python 3.12+: +```bash +python3 --version +``` + +Si la versión es menor a 3.12: +```bash +apt install -y software-properties-common +add-apt-repository ppa:deadsnakes/ppa -y +apt update +apt install -y python3.12 python3.12-venv +``` + +--- + +## 5. Clonar el repositorio + +A partir de acá trabajamos como el usuario `pedrito`: + +```bash +# Cambiar al usuario pedrito +su - pedrito + +# Verificar que estamos en el home correcto +pwd +# /home/pedrito + +# Clonar el repo +git clone https://github.com/InqGit/hechakuaa_bot.git +cd hechakuaa_bot + +# Verificar que los archivos están +ls -la +# Deberías ver: main.py, config.py, telegram_bot.py, poller.py, etc. +``` + +--- + +## 6. Instalar dependencias del proyecto + +El proyecto usa `uv` como gestor de dependencias (más rápido que pip). + +```bash +# Instalar uv (como usuario pedrito) +curl -LsSf https://astral.sh/uv/install.sh | sh + +# Cargar uv en el shell actual (sin necesidad de cerrar sesión) +source $HOME/.local/bin/env + +# Verificar instalación +uv --version +# Salida esperada: uv 0.x.x + +# Instalar todas las dependencias del proyecto en un entorno virtual +uv sync + +# Verificar que el entorno virtual se creó +ls .venv/bin/python +# Salida esperada: .venv/bin/python +``` + +--- + +## 7. Configurar el archivo .env + +> ⚠️ **Importante:** El `.env` se crea directamente en la VPS. Nunca se copia desde tu +> máquina ni se sube al repositorio. Tiene permisos 600 (solo lo puede leer `pedrito`). + +```bash +# Estamos en /home/pedrito/hechakuaa_bot/ +# Copiar el template +cp .env.example .env + +# Editar el archivo +nano .env +``` + +Completar los siguientes campos (los demás se pueden dejar con sus valores por defecto): + +``` +FERNET_KEY= +TELEGRAM_BOT_TOKEN= +TELEGRAM_CHAT_ID= +``` + +Guardar y salir de nano: `Ctrl+O`, `Enter`, `Ctrl+X`. + +Restringir permisos (obligatorio): +```bash +chmod 600 .env + +# Verificar +ls -la .env +# Salida esperada: -rw------- 1 pedrito pedrito ... .env +``` + +> Si la FERNET_KEY todavía no existe, generala así y anotala en un gestor de contraseñas: +> ```bash +> uv run python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" +> ``` +> Copiá la salida (una cadena larga de letras y números) y pegala en `.env` como valor de `FERNET_KEY`. + +--- + +## 8. Cifrar las credenciales del PJ + +El bot nunca guarda la cédula ni la contraseña del PJ en texto plano. +Este script las cifra con la `FERNET_KEY` y guarda el resultado cifrado en `.env`. + +```bash +uv run python scripts/cifrar_credenciales.py +``` + +El script te va a pedir: +1. **Cédula de identidad** — el usuario con el que Marcos entra a `apps.csj.gov.py` +2. **Contraseña** — se escribe pero no se muestra en pantalla + +Salida esperada al terminar: +``` +✅ Credenciales cifradas y guardadas en .env + PJ_USUARIO_ENC y PJ_PASSWORD_ENC actualizadas. +``` + +Verificar que se guardaron en `.env`: +```bash +grep "PJ_USUARIO_ENC" .env +# Debe mostrar una línea con un valor cifrado largo (no la cédula en texto plano) +``` + +--- + +## 9. Verificar que el bot arranca + +Antes de configurar el servicio, probamos que todo funciona: + +```bash +uv run python main.py +``` + +Salida esperada (en formato JSON, primeras líneas): +```json +{"event": "pedrito_hechakuaa_iniciando", "level": "info", ...} +{"event": "database_iniciada", "level": "info", ...} +{"event": "bot_telegram_iniciado", "level": "info", ...} +{"event": "pedrito_hechakuaa_corriendo", "level": "info", ...} +{"event": "poller_iniciado", "level": "info", ...} +{"event": "login_exitoso", "level": "info", ...} +``` + +Si aparece `"login_exitoso"` el bot se conectó al PJ correctamente. + +**Detener el bot:** `Ctrl+C` + +### Errores comunes en este paso + +| Mensaje de error | Causa | Solución | +|-----------------|-------|----------| +| `FERNET_KEY inválida` | La clave en `.env` es incorrecta o tiene espacios | Verificar que no tiene espacios ni comillas en `.env` | +| `Credenciales incorrectas (401)` | Cédula o contraseña del PJ incorrecta | Repetir paso 8 con los datos correctos | +| `telegram.error.InvalidToken` | TELEGRAM_BOT_TOKEN mal copiado | Verificar el token en `.env` | +| `ModuleNotFoundError` | `uv sync` no se ejecutó o falló | Correr `uv sync` de nuevo | + +--- + +## 10. Crear el servicio systemd + +El servicio systemd mantiene el bot corriendo en background, lo reinicia si cae, y lo levanta automáticamente al reiniciar la VPS. + +Volver a root para crear el archivo de servicio: +```bash +exit # salir del usuario pedrito, volver a root +``` + +Crear el archivo de servicio: +```bash +nano /etc/systemd/system/pedrito.service +``` + +Pegar exactamente este contenido: + +```ini +[Unit] +Description=Pedrito Hechakuaa — Monitor judicial PY +After=network-online.target +Wants=network-online.target + +[Service] +Type=simple +User=pedrito +WorkingDirectory=/home/pedrito/hechakuaa_bot + +# Usar el Python del entorno virtual directamente (no depende del PATH) +ExecStart=/home/pedrito/hechakuaa_bot/.venv/bin/python main.py + +# Reiniciar automáticamente si el proceso cae +Restart=on-failure +RestartSec=15 + +# Seguridad: el proceso no puede escalar privilegios +NoNewPrivileges=true +PrivateTmp=true + +# Logs a journald +StandardOutput=journal +StandardError=journal +SyslogIdentifier=pedrito + +[Install] +WantedBy=multi-user.target +``` + +Guardar: `Ctrl+O`, `Enter`, `Ctrl+X`. + +Activar e iniciar el servicio: +```bash +# Recargar la configuración de systemd para que detecte el nuevo servicio +systemctl daemon-reload + +# Habilitar para que arranque en cada reboot +systemctl enable pedrito + +# Iniciar el servicio ahora +systemctl start pedrito + +# Verificar que está corriendo +systemctl status pedrito +``` + +Salida esperada de `systemctl status pedrito`: +``` +● pedrito.service - Pedrito Hechakuaa — Monitor judicial PY + Loaded: loaded (/etc/systemd/system/pedrito.service; enabled; ...) + Active: active (running) since ... +``` + +El campo clave es `Active: active (running)`. Si dice `failed` o `inactive`, ver la sección de [Troubleshooting](#15-troubleshooting). + +--- + +## 11. Configurar el firewall + +El bot de Telegram usa polling saliente — no necesita puertos abiertos para funcionar. +Solo habilitamos SSH para no quedarnos sin acceso. + +```bash +# Como root +ufw allow OpenSSH +ufw --force enable +ufw status +``` + +Salida esperada: +``` +Status: active + +To Action From +-- ------ ---- +OpenSSH ALLOW Anywhere +``` + +> Si en la VPS ya tenés otros servicios corriendo (nginx, etc.), agregá sus puertos +> antes de hacer `ufw enable` para no cortarlos: +> ```bash +> ufw allow 80/tcp # HTTP +> ufw allow 443/tcp # HTTPS +> ``` + +--- + +## 12. Verificación final + +Revisar que todo quedó en orden: + +```bash +# 1. El servicio está corriendo +systemctl status pedrito +# Esperado: active (running) + +# 2. El bot se loguea al PJ y al bot de Telegram +journalctl -u pedrito -n 30 +# Buscar: "login_exitoso" y "bot_telegram_iniciado" + +# 3. El proceso existe +ps aux | grep "python main.py" | grep -v grep +# Debe mostrar el proceso del usuario pedrito + +# 4. El .env tiene los permisos correctos +su - pedrito -c "ls -la /home/pedrito/hechakuaa_bot/.env" +# Debe mostrar: -rw------- 1 pedrito pedrito + +# 5. El servicio se recupera de reinicios +# Opcional: reiniciar la VPS y verificar que el bot vuelve solo +reboot +# Esperar 1-2 minutos, reconectarse y correr: +systemctl status pedrito +``` + +Si todos los puntos pasan, el deploy está completo. +Avisarle a Marcos para que pruebe mandándole `/start` al bot en Telegram. + +--- + +## 13. Monitoreo y logs + +### Ver logs en tiempo real +```bash +journalctl -u pedrito -f +``` +Detener con `Ctrl+C`. + +### Ver los últimos N registros +```bash +journalctl -u pedrito -n 50 +``` + +### Ver logs de la última hora +```bash +journalctl -u pedrito --since "1 hour ago" +``` + +### Ver logs de un día específico +```bash +journalctl -u pedrito --since "2026-05-25 00:00:00" --until "2026-05-25 23:59:59" +``` + +### Buscar errores +```bash +journalctl -u pedrito -p err +``` + +### Eventos útiles que buscar en los logs + +| Evento en el log | Qué significa | +|-----------------|---------------| +| `login_exitoso` | Se conectó al PJ correctamente | +| `polling_tenant_ok` | Revisión de notificaciones completada | +| `polling_tenant_error` | Error en la revisión (ver `tipo` en el detalle) | +| `pj_error_conexion` | El PJ no respondió (puede ser transitorio) | +| `bot_notificacion_enviada` | Se envió una notificación a Telegram | +| `onboarding_completado` | Un usuario completó el registro | + +--- + +## 14. Cómo actualizar el bot + +Cuando hay cambios en el código (nuevo commit en el repo): + +```bash +# Como pedrito (o desde root: su - pedrito) +cd /home/pedrito/hechakuaa_bot + +# Traer los cambios +git pull + +# Reinstalar dependencias si hubo cambios en pyproject.toml +uv sync + +# Reiniciar el servicio para aplicar los cambios +# (hacerlo como root o con sudo) +exit # si estabas como pedrito +systemctl restart pedrito + +# Verificar que levantó bien +systemctl status pedrito +journalctl -u pedrito -n 20 +``` + +> **Nota:** El archivo `.env` y el directorio `data/` **no se tocan con `git pull`** — +> están en `.gitignore`. Las credenciales y el historial de notificaciones persisten +> entre actualizaciones. + +--- + +## 15. Troubleshooting + +### El servicio no arranca (`failed`) + +```bash +# Ver el error específico +journalctl -u pedrito -n 50 +systemctl status pedrito +``` + +**`ModuleNotFoundError: No module named 'X'`** +```bash +su - pedrito +cd hechakuaa_bot +uv sync +exit +systemctl restart pedrito +``` + +**`.venv/bin/python: No such file or directory`** +```bash +su - pedrito +cd hechakuaa_bot +uv sync # esto crea el .venv +exit +systemctl restart pedrito +``` + +**`DB no inicializada`** +El `data/` no existe todavía. El bot lo crea solo al arrancar. Si persiste: +```bash +su - pedrito +mkdir -p /home/pedrito/hechakuaa_bot/data +exit +systemctl restart pedrito +``` + +--- + +### El bot arranca pero no responde en Telegram + +1. Verificar que `TELEGRAM_BOT_TOKEN` en `.env` es correcto +2. Verificar que `TELEGRAM_CHAT_ID` es el chat_id correcto de Marcos +3. Revisar logs: `journalctl -u pedrito -n 30` +4. Desde otro cliente probar que el bot existe: buscar `@pedrito_hechakuaabot` en Telegram + +--- + +### Error de credenciales del PJ (`Credenciales incorrectas`) + +```bash +su - pedrito +cd hechakuaa_bot + +# Repetir el cifrado de credenciales +uv run python scripts/cifrar_credenciales.py + +exit +systemctl restart pedrito +``` + +--- + +### La VPS se reinició y el bot no volvió + +```bash +systemctl status pedrito +# Si dice "disabled": +systemctl enable pedrito +systemctl start pedrito +``` + +--- + +### Ver si hay dos instancias corriendo (causa conflictos) + +```bash +ps aux | grep "python main.py" | grep -v grep +``` + +Si hay más de una línea, matar todas y reiniciar el servicio: +```bash +pkill -f "python main.py" +systemctl start pedrito +``` + +--- + +## Referencia rápida de comandos + +```bash +# Estado del servicio +systemctl status pedrito + +# Iniciar / detener / reiniciar +systemctl start pedrito +systemctl stop pedrito +systemctl restart pedrito + +# Logs en tiempo real +journalctl -u pedrito -f + +# Actualizar el bot +su - pedrito -c "cd hechakuaa_bot && git pull && uv sync" +systemctl restart pedrito +``` + +--- + +*Repositorio: https://github.com/InqGit/hechakuaa_bot* +*Ante dudas, contactar a Marcos Benítez.*