From 6aa8b8fa62821e990d3b80836fe600c36fe9ebaa Mon Sep 17 00:00:00 2001 From: markosbenitez Date: Mon, 25 May 2026 23:55:36 -0300 Subject: [PATCH] =?UTF-8?q?docs:=20gu=C3=ADa=20de=20deploy=20completa=20co?= =?UTF-8?q?n=20Docker,=20Nginx,=20SSL,=20DNS=20y=20webhook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Estructura en 4 partes: preparación, servidor, HTTPS/producción, operación - Sección DNS detallada para Bluehost cPanel + mensaje exacto en inglés para delegar a un asistente técnico - Configuración Nginx como reverse proxy con SSL terminado en el servidor - Certbot + Let's Encrypt con renovación automática - docker-compose en modo producción (bind 127.0.0.1:8080) - Activación del modo webhook paso a paso - Health check HTTP integrado en Nginx - Tabla de rutas absolutas de todos los archivos - Troubleshooting expandido para 8 escenarios de error Co-Authored-By: Claude Sonnet 4.6 --- DEPLOY.md | 1395 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 1028 insertions(+), 367 deletions(-) diff --git a/DEPLOY.md b/DEPLOY.md index 69cfaec..6b6e489 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -1,128 +1,333 @@ # 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 +> **Entorno objetivo:** VPS Ubuntu 22.04 en Hostinger — producción +> **Tiempo estimado:** 60–90 minutos (primera vez) +> **Acceso requerido:** SSH root al VPS + datos de configuración provistos por Marcos +> **Subdominio objetivo:** `pedrito.inqualityhq.com` --- ## Í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) +**PARTE A — Preparación (antes de tocar el servidor)** +1. [Datos que necesitás antes de empezar](#1-datos-que-necesitás-antes-de-empezar) +2. [Configurar DNS en Bluehost](#2-configurar-dns-en-bluehost) + +**PARTE B — Servidor: base** +3. [Conectarse al VPS](#3-conectarse-al-vps) +4. [Actualizar el sistema y crear usuario](#4-actualizar-el-sistema-y-crear-usuario) +5. [Instalar Docker](#5-instalar-docker) +6. [Instalar Nginx](#6-instalar-nginx) +7. [Clonar el repositorio](#7-clonar-el-repositorio) +8. [Configurar el archivo .env](#8-configurar-el-archivo-env) +9. [Cifrar las credenciales del PJ](#9-cifrar-las-credenciales-del-pj) + +**PARTE C — HTTPS y producción** +10. [Obtener certificado SSL con Certbot](#10-obtener-certificado-ssl-con-certbot) +11. [Configurar Nginx como reverse proxy](#11-configurar-nginx-como-reverse-proxy) +12. [Configurar el firewall](#12-configurar-el-firewall) +13. [Iniciar el bot con Docker](#13-iniciar-el-bot-con-docker) +14. [Activar el modo webhook](#14-activar-el-modo-webhook) + +**PARTE D — Operación** +15. [Verificación final](#15-verificación-final) +16. [Monitoreo y logs](#16-monitoreo-y-logs) +17. [Health check HTTP](#17-health-check-http) +18. [Cómo actualizar el bot](#18-cómo-actualizar-el-bot) +19. [Troubleshooting](#19-troubleshooting) +20. [Referencia rápida de comandos](#20-referencia-rápida-de-comandos) --- -## 1. Antes de empezar +## 1. Datos que necesitás antes de empezar -Antes de tocar la VPS, pedile a Marcos que te provea estos datos. Sin ellos no podés completar el deploy. +Antes de conectarte al VPS, juntá estos datos. Sin alguno de ellos el deploy no puede completarse. -| 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 | +| # | Dato | Quién lo tiene | Dónde va | +|---|------|---------------|----------| +| 1 | `FERNET_KEY` (clave de cifrado) | Marcos la genera | `.env` | +| 2 | `TELEGRAM_BOT_TOKEN` | Marcos (de @BotFather) | `.env` | +| 3 | `TELEGRAM_CHAT_ID` | Marcos (de @userinfobot) | `.env` | +| 4 | `TELEGRAM_EXTRA_IDS` | Marcos (chat IDs de otros abogados, separados por coma) | `.env` | +| 5 | `INVITE_CODE` | Marcos lo decide | `.env` | +| 6 | Cédula del PJ | Marcos | Script de cifrado | +| 7 | Contraseña del PJ | Marcos | Script de cifrado | +| 8 | IP pública del VPS | Panel de Hostinger | DNS + SSH | +| 9 | Credenciales SSH del VPS | Panel de Hostinger | Terminal | -> ⚠️ **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`. +> **Tip:** Pedile a Marcos que te envíe los datos 1-5 por un canal seguro (Signal, Bitwarden Send, etc.). +> Nunca por email ni WhatsApp. + +> ⚠️ **Seguridad crítica:** Nunca guardés la contraseña del PJ (dato 7) en ningún archivo, chat, +> nota, ni Post-it. El script del paso 9 la pide en pantalla, la descarta de memoria y guarda +> solo el resultado cifrado. Una vez que el script termina exitosamente, podés olvidarla. --- -## 2. Conectarse a la VPS +## 2. Configurar DNS en Bluehost + +El bot va a ser accesible en `pedrito.inqualityhq.com`. Para eso necesitamos apuntar ese +subdominio a la IP del VPS con un registro DNS tipo A. + +**Necesitás:** La IP pública del VPS (Panel de Hostinger → tu VPS → ver IP). + +--- + +### Opción A: Hacerlo vos mismo en Bluehost cPanel + +1. Entrá a [bluehost.com](https://www.bluehost.com) con las credenciales de InQuality +2. En el panel, buscá **"cPanel"** y hacé click +3. Dentro de cPanel, en la sección **"Domains"**, hacé click en **"Zone Editor"** + (también puede aparecer como **"DNS Zone Editor"** o **"Advanced DNS Editor"**) +4. Buscá `inqualityhq.com` en la lista y hacé click en **"Manage"** +5. Hacé click en **"Add Record"** +6. Completá el formulario así: + + | Campo | Valor | + |-------|-------| + | **Name** (o Host) | `pedrito` | + | **Type** | `A` | + | **TTL** | `300` (o el mínimo disponible) | + | **Value** (o Points To) | `` | + +7. Hacé click en **"Save"** o **"Add Record"** + +8. Para verificar que se propagó (puede tardar de 5 minutos a 2 horas): + ```bash + # Desde tu computadora local + nslookup pedrito.inqualityhq.com + # Debe mostrar la IP del VPS en la respuesta + + # O también: + dig pedrito.inqualityhq.com A +short + # Debe retornar solo la IP del VPS + ``` + +> **Tip:** Si `nslookup` aún no muestra la IP, esperá 10-15 minutos y volvé a intentar. +> La propagación en Bluehost suele ser rápida, pero a veces tarda más. + +--- + +### Opción B: Mensaje exacto para pedirle a un asistente de Bluehost (en inglés) + +Si necesitás que un asistente del equipo (que tenga acceso al cPanel de Bluehost) lo haga por vos, +podés enviarle exactamente este mensaje: + +--- + +> Hi, +> +> I need to add a DNS A record to the `inqualityhq.com` domain managed through Bluehost cPanel. +> Could you please add the following record? +> +> - **Domain:** inqualityhq.com +> - **Record type:** A +> - **Host/Name:** pedrito *(this will create pedrito.inqualityhq.com)* +> - **Value/Points to:** `` *(replace with the actual VPS IP)* +> - **TTL:** 300 seconds (minimum available) +> +> Once added, please confirm so I can verify propagation. +> If you need me to confirm with the account holder, let me know. +> +> Thank you! + +--- + +Reemplazá `` con la IP real del VPS antes de enviar el mensaje. + +--- + +## 3. Conectarse al VPS + +Desde tu computadora local, abrí una terminal: ```bash ssh root@ ``` -Si usás clave SSH (recomendado): +Si tenés clave SSH configurada en Hostinger (recomendado): ```bash ssh -i ~/.ssh/id_rsa root@ ``` -Verificar que el sistema está actualizado: +Si te pide contraseña, es la del panel de Hostinger. + +> **Tip para Windows:** Usá [Windows Terminal](https://apps.microsoft.com/detail/9n0dx20hk701) o +> [PuTTY](https://www.putty.org/). En Windows Terminal el comando SSH es el mismo. + +> **Tip:** Si es la primera conexión, va a preguntar: +> ``` +> Are you sure you want to continue connecting (yes/no/[fingerprint])? +> ``` +> Escribí `yes` y Enter. + +--- + +## 4. Actualizar el sistema y crear usuario + +Todos estos comandos se ejecutan como **root**. + +### 4.1 Actualizar paquetes + ```bash apt update && apt upgrade -y ``` ---- +Esto puede tardar 2-5 minutos. Esperá que termine. -## 3. Crear usuario dedicado - -El bot no debe correr como root. Creamos un usuario propio llamado `pedrito`. +### 4.2 Verificar la versión de Ubuntu ```bash -# Crear usuario sin contraseña de login (solo acceso SSH) +lsb_release -a +``` +Salida esperada: `Ubuntu 22.04.x LTS`. Si es otra versión, avisale a Marcos antes de continuar. + +### 4.3 Crear el usuario `pedrito` + +El bot no debe correr como root. Le creamos un usuario propio: + +```bash +# Crear el usuario (sin contraseña de login interactivo) adduser pedrito --disabled-password --gecos "" -# Verificar que se creó correctamente +# Verificar que se creó id pedrito -# Salida esperada: uid=1001(pedrito) gid=1001(pedrito) groups=1001(pedrito) ``` -### Configurar acceso SSH para el usuario pedrito +Salida esperada: +``` +uid=1001(pedrito) gid=1001(pedrito) groups=1001(pedrito) +``` + +> **¿Por qué UID 1001 y no 1000?** En Ubuntu el usuario 1000 suele ser el primer usuario +> creado durante la instalación. En un VPS de Hostinger puede o no existir. +> Lo importante es que `pedrito` tenga su propio UID. + +### 4.4 Permitir que `pedrito` use Docker (sin sudo) + +```bash +# Esto lo hacemos después de instalar Docker (paso 5), pero lo dejamos acá como referencia +# usermod -aG docker pedrito ← lo corremos en el paso 5.3 +``` + +### 4.5 Configurar acceso SSH para `pedrito` (opcional pero recomendado) ```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. +Para verificar: en una segunda terminal, intentá `ssh pedrito@`. Si entra sin contraseña, perfecto. --- -## 4. Instalar dependencias del sistema +## 5. Instalar Docker + +Docker es el motor de contenedores que va a correr el bot de forma aislada y reproducible. + +### 5.1 Instalar dependencias previas ```bash -# Aún como root -apt install -y git curl +apt install -y \ + ca-certificates \ + curl \ + gnupg \ + lsb-release ``` -Verificar Python 3.12+: -```bash -python3 --version -``` +### 5.2 Agregar el repositorio oficial de Docker -Si la versión es menor a 3.12: ```bash -apt install -y software-properties-common -add-apt-repository ppa:deadsnakes/ppa -y +# Crear directorio para las claves GPG +install -m 0755 -d /etc/apt/keyrings + +# Descargar e instalar la clave GPG de Docker +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ + gpg --dearmor -o /etc/apt/keyrings/docker.gpg + +chmod a+r /etc/apt/keyrings/docker.gpg + +# Agregar el repositorio +echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ + https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | \ + tee /etc/apt/sources.list.d/docker.list > /dev/null + +# Actualizar lista de paquetes apt update -apt install -y python3.12 python3.12-venv +``` + +### 5.3 Instalar Docker Engine y docker-compose + +```bash +apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + +# Verificar que Docker se instaló correctamente +docker --version +# Salida esperada: Docker version 24.x.x o mayor + +docker compose version +# Salida esperada: Docker Compose version v2.x.x +``` + +### 5.4 Agregar a `pedrito` al grupo docker + +```bash +# Esto permite que pedrito corra docker sin sudo +usermod -aG docker pedrito + +# Verificar +groups pedrito +# Debe incluir "docker" en la lista +``` + +### 5.5 Verificar que Docker funciona + +```bash +docker run --rm hello-world +``` + +Si imprime `Hello from Docker!`, Docker está funcionando. + +> **¿Qué es un contenedor?** Pensalo como una "caja" cerrada que incluye el código del bot +> y todas sus dependencias. Si algo falla dentro de la caja, no afecta al resto del servidor. +> `docker compose up` abre la caja, `docker compose down` la cierra. + +--- + +## 6. Instalar Nginx + +Nginx actúa como intermediario entre internet y el bot. Recibe las conexiones HTTPS (puerto 443) +y las reenvía internamente al bot (puerto 8080). Esto permite tener SSL sin que el bot lo maneje. + +```bash +# Instalar Nginx +apt install -y nginx + +# Verificar que arrancó +systemctl status nginx +``` + +Salida esperada: +``` +● nginx.service - A high performance web server and reverse proxy server + Active: active (running) since ... +``` + +Si dice `inactive`, arrancalo manualmente: +```bash +systemctl start nginx +systemctl enable nginx # para que arranque en cada reboot ``` --- -## 5. Clonar el repositorio +## 7. Clonar el repositorio A partir de acá trabajamos como el usuario `pedrito`: @@ -132,229 +337,355 @@ su - pedrito # Verificar que estamos en el home correcto pwd -# /home/pedrito +# Debe mostrar: /home/pedrito -# Clonar el repo +# Clonar el repositorio git clone https://github.com/InqGit/hechakuaa_bot.git + +# Entrar al directorio cd hechakuaa_bot -# Verificar que los archivos están +# Verificar que los archivos están presentes ls -la -# Deberías ver: main.py, config.py, telegram_bot.py, poller.py, etc. ``` +Deberías ver archivos como: `main.py`, `config.py`, `telegram_bot.py`, `Dockerfile`, +`docker-compose.yml`, `migrations/`, etc. + +### Crear el directorio de datos + +```bash +# Este directorio persiste entre reinicios del bot (DB, snapshots) +mkdir -p /home/pedrito/hechakuaa_bot/data +``` + +Salir de vuelta a root para el siguiente paso: +```bash +exit +# Ahora estás como root de nuevo +``` + +### Ajustar permisos del directorio data para Docker + +El contenedor Docker corre con usuario UID 1000. El directorio `data/` necesita +ser escribible por ese UID: + +```bash +chown -R 1000:1000 /home/pedrito/hechakuaa_bot/data + +# Verificar +ls -la /home/pedrito/hechakuaa_bot/data +# Debe mostrar: drwxr-xr-x 2 1000 1000 ... data +``` + +> **¿Por qué 1000 y no pedrito?** Dentro del contenedor Docker existe un usuario con UID 1000. +> El servidor no sabe que ese usuario se llama "pedrito" — solo entiende el número UID. +> En el sistema anfitrión, UID 1000 puede corresponder a un usuario diferente, pero Docker +> solo necesita que el directorio sea escribible por ese número. + --- -## 6. Instalar dependencias del proyecto +## 8. Configurar el archivo .env -El proyecto usa `uv` como gestor de dependencias (más rápido que pip). +El archivo `.env` contiene toda la configuración sensible del bot. Se crea directamente en el VPS +y **nunca** se sube al repositorio ni se copia entre máquinas. ```bash -# Instalar uv (como usuario pedrito) -curl -LsSf https://astral.sh/uv/install.sh | sh +# Como pedrito: +su - pedrito +cd /home/pedrito/hechakuaa_bot -# 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 +# Crear .env a partir del template cp .env.example .env -# Editar el archivo +# Editar (nano es el editor más simple) nano .env ``` -Completar los siguientes campos (los demás se pueden dejar con sus valores por defecto): +### Guía de campos del .env -``` -FERNET_KEY= -TELEGRAM_BOT_TOKEN= -TELEGRAM_CHAT_ID= -``` +Completá los campos marcados con `← COMPLETAR`. Los demás se pueden dejar con sus valores por defecto: -Guardar y salir de nano: `Ctrl+O`, `Enter`, `Ctrl+X`. - -Restringir permisos (obligatorio): ```bash -chmod 600 .env +# ── CIFRADO ────────────────────────────────────────────────────────────────── +FERNET_KEY= # ← COMPLETAR (Marcos te la da o la generás abajo) + +# ── CREDENCIALES PJ (se completan en el paso 9) ─────────────────────────────── +PJ_USUARIO_ENC= # ← se completa automáticamente con el script de cifrado +PJ_PASSWORD_ENC= # ← se completa automáticamente con el script de cifrado + +# ── TELEGRAM ───────────────────────────────────────────────────────────────── +TELEGRAM_BOT_TOKEN= # ← COMPLETAR (de @BotFather) +TELEGRAM_CHAT_ID= # ← COMPLETAR (chat ID de Marcos) +TELEGRAM_EXTRA_IDS= # ← COMPLETAR si hay más abogados (ej: 111222333,444555666) + +# ── INVITACIÓN ──────────────────────────────────────────────────────────────── +INVITE_CODE= # ← COMPLETAR (código maestro ilimitado) + +# ── WEBHOOK (completar después del paso 14) ─────────────────────────────────── +WEBHOOK_URL= # ← dejar vacío por ahora, completar en el paso 14 +WEBHOOK_SECRET= # ← dejar vacío por ahora, completar en el paso 14 + +# ── HEALTH CHECK ───────────────────────────────────────────────────────────── +HEALTH_PORT=8080 # dejar así +HEALTH_ALERT_HOURS=2 # alerta al admin si el poller no actualizó en 2 horas + +# ── POLLING ────────────────────────────────────────────────────────────────── +POLL_INTERVAL_MINUTES=60 # revisar el PJ cada 60 minutos +POLL_HORA_INICIO=7 # desde las 7am (hora Paraguay) +POLL_HORA_FIN=18 # hasta las 6pm (hora Paraguay) +``` + +Guardar y salir de nano: `Ctrl+O` → `Enter` → `Ctrl+X`. + +### Generar FERNET_KEY si Marcos no te la dio + +```bash +# Generar una clave nueva (solo si no tenés una preexistente) +uv run python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" +``` + +Salida esperada: una cadena de ~44 caracteres como `gAAAAABx3...`. Copiarla y pegarla en `.env`. + +> ⚠️ **Guardá la FERNET_KEY en un gestor de contraseñas (Bitwarden, 1Password, etc.).** +> Si se pierde, las credenciales cifradas de todos los abogados quedan irrecuperables. + +### Instalar uv (si no está disponible como pedrito) + +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +source $HOME/.local/bin/env +uv --version +``` + +### Restringir permisos del .env + +```bash +chmod 600 /home/pedrito/hechakuaa_bot/.env # Verificar -ls -la .env -# Salida esperada: -rw------- 1 pedrito pedrito ... .env +ls -la /home/pedrito/hechakuaa_bot/.env +# Debe mostrar: -rw------- 1 pedrito pedrito ``` -> 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 +## 9. 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`. +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 +# Como pedrito, dentro del directorio del proyecto: +cd /home/pedrito/hechakuaa_bot 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 +1. **Cédula de identidad** — el número con el que Marcos entra a `apps.csj.gov.py` +2. **Contraseña** — la contraseña de ese sistema (no se muestra mientras escribís) -Salida esperada al terminar: +Salida esperada: ``` ✅ Credenciales cifradas y guardadas en .env PJ_USUARIO_ENC y PJ_PASSWORD_ENC actualizadas. ``` -Verificar que se guardaron en `.env`: +Verificar que se guardaron: ```bash -grep "PJ_USUARIO_ENC" .env -# Debe mostrar una línea con un valor cifrado largo (no la cédula en texto plano) +grep "PJ_USUARIO_ENC" /home/pedrito/hechakuaa_bot/.env +# Debe mostrar un valor cifrado largo, NUNCA la cédula en texto plano ``` --- -## 9. Verificar que el bot arranca +## 10. Obtener certificado SSL con Certbot -Antes de configurar el servicio, probamos que todo funciona: +HTTPS es obligatorio para el modo webhook de Telegram y para cualquier servicio expuesto +en producción. Certbot obtiene el certificado gratis de Let's Encrypt. + +> **Prerequisito:** El DNS del paso 2 ya debe estar propagado. Verificalo: +> ```bash +> nslookup pedrito.inqualityhq.com +> # Debe retornar la IP de este VPS +> ``` +> Si no retorna la IP correcta, esperá y volvé después. + +### 10.1 Instalar Certbot ```bash -uv run python main.py +# Como root: +exit # si estabas como pedrito, volver a root + +apt install -y certbot python3-certbot-nginx ``` -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", ...} +### 10.2 Obtener el certificado + +```bash +certbot --nginx -d pedrito.inqualityhq.com ``` -Si aparece `"login_exitoso"` el bot se conectó al PJ correctamente. +Certbot te va a preguntar: +1. Tu dirección de email (para avisos de vencimiento) — ponés la de Marcos o la del equipo +2. Aceptar los términos de servicio → `Y` +3. Si querés compartir el email con EFF → `N` (opcional) -**Detener el bot:** `Ctrl+C` +Salida esperada al terminar: +``` +Successfully received certificate. +Certificate is saved at: /etc/letsencrypt/live/pedrito.inqualityhq.com/fullchain.pem +Key is saved at: /etc/letsencrypt/live/pedrito.inqualityhq.com/privkey.pem +... +``` -### Errores comunes en este paso +> **¿Por qué usamos --nginx?** Le decimos a Certbot que tenemos Nginx instalado y que puede +> configurar automáticamente el sitio para HTTPS. Pero vamos a sobreescribir esa configuración +> en el siguiente paso para personalizarla. -| 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.3 Verificar la renovación automática + +Los certificados de Let's Encrypt duran 90 días y se renuevan automáticamente: + +```bash +# Verificar que el timer de renovación automática existe +systemctl status certbot.timer +# Debe estar "active (waiting)" + +# Simular una renovación para verificar que funciona +certbot renew --dry-run +# Debe decir: "Simulating renewal of an existing certificate..." +``` --- -## 10. Crear el servicio systemd +## 11. Configurar Nginx como reverse proxy -El servicio systemd mantiene el bot corriendo en background, lo reinicia si cae, y lo levanta automáticamente al reiniciar la VPS. +Nginx recibe las requests de internet y las redirige al bot corriendo en el contenedor Docker +(puerto 8080). También maneja el SSL automáticamente. + +### 11.1 Crear el archivo de configuración -Volver a root para crear el archivo de servicio: ```bash -exit # salir del usuario pedrito, volver a root +# Como root: +nano /etc/nginx/sites-available/pedrito ``` -Crear el archivo de servicio: +Pegar **exactamente** este contenido (reemplazá el nombre de dominio si usás uno diferente): + +```nginx +# /etc/nginx/sites-available/pedrito +# Reverse proxy para Pedrito Hechakuaa + +server { + listen 80; + server_name pedrito.inqualityhq.com; + # Redirigir todo el tráfico HTTP a HTTPS + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl; + server_name pedrito.inqualityhq.com; + + # Certificados SSL de Let's Encrypt + ssl_certificate /etc/letsencrypt/live/pedrito.inqualityhq.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/pedrito.inqualityhq.com/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + # Seguridad: no exponer versión de Nginx + server_tokens off; + + # Tamaño máximo de payload (Telegram puede enviar archivos) + client_max_body_size 20M; + + # ── Health check (acceso público para monitoreo) ────────────────────────── + location /health { + proxy_pass http://127.0.0.1:8080/health; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 10s; + } + + location /health/history { + proxy_pass http://127.0.0.1:8080/health/history; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 10s; + } + + # ── Webhook de Telegram ─────────────────────────────────────────────────── + location /webhook { + proxy_pass http://127.0.0.1:8080/webhook; + 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; + # Pasar el header de autenticación del webhook de Telegram + proxy_set_header X-Telegram-Bot-Api-Secret-Token $http_x_telegram_bot_api_secret_token; + proxy_read_timeout 30s; + } + + # ── Denegar cualquier otra ruta ─────────────────────────────────────────── + location / { + return 404; + } +} +``` + +Guardar: `Ctrl+O` → `Enter` → `Ctrl+X`. + +### 11.2 Activar el sitio + ```bash -nano /etc/systemd/system/pedrito.service +# Crear el enlace simbólico que activa el sitio +ln -s /etc/nginx/sites-available/pedrito /etc/nginx/sites-enabled/pedrito + +# Verificar que no hay errores de sintaxis en la configuración +nginx -t ``` -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 +Salida esperada: +``` +nginx: the configuration file /etc/nginx/nginx.conf syntax is ok +nginx: configuration file /etc/nginx/nginx.conf test is successful ``` -Guardar: `Ctrl+O`, `Enter`, `Ctrl+X`. +Si hay errores, revisá que el archivo se pegó correctamente (especialmente las comillas y los `;`). + +### 11.3 Recargar Nginx -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 +systemctl reload nginx +systemctl status nginx +# Debe estar active (running) ``` -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 ... -``` +### 11.4 Verificar que Nginx responde -El campo clave es `Active: active (running)`. Si dice `failed` o `inactive`, ver la sección de [Troubleshooting](#15-troubleshooting). +```bash +# Desde el propio servidor: +curl -sk https://pedrito.inqualityhq.com/health +# Debe retornar un error de conexión rechazada (porque el bot no está corriendo aún) +# o un JSON si ya está corriendo + +# Verificar que HTTP redirige a HTTPS: +curl -I http://pedrito.inqualityhq.com/health +# Debe retornar: HTTP/1.1 301 Moved Permanently +``` --- -## 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. +## 12. Configurar el firewall ```bash # Como root ufw allow OpenSSH +ufw allow 'Nginx Full' # abre puertos 80 (HTTP) y 443 (HTTPS) ufw --force enable + +# Verificar estado ufw status ``` @@ -365,229 +696,559 @@ Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere +Nginx Full ALLOW Anywhere +OpenSSH (v6) ALLOW Anywhere (v6) +Nginx Full (v6) ALLOW Anywhere (v6) ``` -> Si en la VPS ya tenés otros servicios corriendo (nginx, etc.), agregá sus puertos -> antes de hacer `ufw enable` para no cortarlos: +> **Importante:** El puerto 8080 del bot **no** se abre al exterior. Solo Nginx (que corre en el +> mismo servidor) se comunica con el bot internamente. El bot no es accesible directamente desde +> internet, solo a través de Nginx. + +--- + +## 13. Iniciar el bot con Docker + +### 13.1 Actualizar docker-compose.yml para producción + +Por seguridad, el bot solo debe escuchar en localhost (no en todas las interfaces de red). +Modificá el puerto en docker-compose.yml: + +```bash +# Como pedrito: +su - pedrito +cd /home/pedrito/hechakuaa_bot + +# Editar docker-compose.yml +nano docker-compose.yml +``` + +Buscá la línea: +```yaml + - "8080:8080" +``` + +Cambiala por: +```yaml + - "127.0.0.1:8080:8080" +``` + +Guardar y salir. Esto hace que el bot solo sea accesible desde el mismo servidor (por Nginx), +no desde internet. + +### 13.2 Construir la imagen Docker + +```bash +# Construir la imagen (tarda 1-3 minutos la primera vez) +docker compose build + +# Salida esperada al final: +# => exporting to image +# => => naming to docker.io/library/hechakuaa_bot-pedrito +``` + +### 13.3 Primera prueba: correr en primer plano + +Antes de dejarlo en background, verificamos que arranca bien: + +```bash +docker compose up +``` + +Deberías ver logs como: +``` +pedrito-1 | {"event": "migration_aplicada", "version": "001_initial_schema", ...} +pedrito-1 | {"event": "database_iniciada", ...} +pedrito-1 | {"event": "health_server_iniciado", "port": 8080, ...} +pedrito-1 | {"event": "bot_telegram_iniciado", ...} +pedrito-1 | {"event": "pedrito_hechakuaa_corriendo", ...} +pedrito-1 | {"event": "poller_iniciado", ...} +pedrito-1 | {"event": "login_exitoso", ...} +``` + +Si aparece `login_exitoso`, el bot se conectó al PJ. Detenerlo con `Ctrl+C`. + +> **Si no aparece `login_exitoso`:** ver la sección [Troubleshooting](#19-troubleshooting). + +### 13.4 Correr en background (modo producción) + +```bash +# Arrancar en modo detached (background) +docker compose up -d + +# Verificar que el contenedor está corriendo +docker compose ps +``` + +Salida esperada: +``` +NAME IMAGE COMMAND SERVICE STATUS PORTS +hechakuaa_bot-... hechakuaa_bot-pedrito "uv run python main.…" pedrito running 127.0.0.1:8080->8080/tcp +``` + +El `STATUS` debe decir `running`. + +### 13.5 Configurar Docker para que arranque en cada reboot + +```bash +# Como root: +exit # salir de pedrito + +# El servicio de Docker ya inicia automáticamente +# Solo verificar que el contenedor tiene restart policy correcta +systemctl enable docker +``` + +El `docker-compose.yml` ya tiene `restart: unless-stopped`, lo que hace que el contenedor +se reinicie automáticamente si el VPS se reinicia. + +--- + +## 14. Activar el modo webhook + +En modo webhook, Telegram envía los mensajes al bot directamente (HTTPS push), en lugar de +que el bot los pida constantemente (polling). Es más eficiente y tiene menor latencia. + +### 14.1 Generar el WEBHOOK_SECRET + +Este token es como una contraseña que Telegram incluye en cada request para probar que es legítimo: + +```bash +# Generar un token aleatorio seguro: +python3 -c "import secrets; print(secrets.token_hex(32))" +# Salida: una cadena de 64 caracteres hexadecimales +``` + +Copiar la salida. La vamos a usar en el siguiente paso. + +### 14.2 Actualizar .env con los datos del webhook + +```bash +su - pedrito +nano /home/pedrito/hechakuaa_bot/.env +``` + +Completar estas dos líneas: +```bash +WEBHOOK_URL=https://pedrito.inqualityhq.com +WEBHOOK_SECRET= +``` + +Guardar y salir. + +### 14.3 Reiniciar el bot para aplicar el cambio + +```bash +cd /home/pedrito/hechakuaa_bot +docker compose restart + +# Ver los logs para confirmar que el webhook se registró: +docker compose logs --tail=20 +``` + +Buscar en los logs: +``` +{"event": "webhook_registrado", "url": "https://pedrito.inqualityhq.com/webhook", ...} +``` + +### 14.4 Verificar que el webhook quedó registrado en Telegram + +```bash +# Reemplazá TU_BOT_TOKEN con el valor real del .env +curl -s "https://api.telegram.org/bot/getWebhookInfo" | python3 -m json.tool +``` + +Salida esperada: +```json +{ + "ok": true, + "result": { + "url": "https://pedrito.inqualityhq.com/webhook", + "has_custom_certificate": false, + "pending_update_count": 0, + ... + } +} +``` + +El campo `url` debe mostrar la URL correcta. Si está vacío o muestra otra URL, revisá los logs del bot. + +--- + +## 15. Verificación final + +Correr esta lista de verificaciones antes de dar el deploy por terminado: + +```bash +# 1. El contenedor Docker está corriendo +docker compose ps +# STATUS debe ser "running" + +# 2. Los logs no tienen errores +docker compose logs --tail=30 +# Buscar "login_exitoso" y "pedrito_hechakuaa_corriendo" +# NO debe aparecer: ERROR, exception, Traceback + +# 3. El health check responde +curl -s https://pedrito.inqualityhq.com/health | python3 -m json.tool +# Debe retornar JSON con "status": "ok" + +# 4. El webhook está registrado (si activaste el modo webhook) +curl -s "https://api.telegram.org/bot/getWebhookInfo" | python3 -m json.tool +# url debe ser: https://pedrito.inqualityhq.com/webhook + +# 5. El .env tiene los permisos correctos +ls -la /home/pedrito/hechakuaa_bot/.env +# Debe mostrar: -rw------- 1 pedrito pedrito + +# 6. El directorio data existe y tiene contenido +ls -la /home/pedrito/hechakuaa_bot/data/ +# Debe aparecer pasante.db y snapshot_*.json + +# 7. Nginx redirige HTTP a HTTPS +curl -I http://pedrito.inqualityhq.com/health +# Debe retornar: HTTP/1.1 301 Moved Permanently +``` + +Si todos los checks pasan, avisarle a Marcos para que pruebe mandándole `/start` al bot en Telegram. + +--- + +## 16. Monitoreo y logs + +### Logs del bot en tiempo real + +```bash +# Como pedrito: +su - pedrito +cd /home/pedrito/hechakuaa_bot + +# Ver logs en tiempo real (Ctrl+C para salir) +docker compose logs -f + +# Ver solo los últimos 50 registros +docker compose logs --tail=50 + +# Ver logs con timestamps más legibles +docker compose logs --tail=50 --timestamps +``` + +### Logs de Nginx + +```bash +# Accesos (como root): +tail -f /var/log/nginx/access.log + +# Errores: +tail -f /var/log/nginx/error.log + +# Solo errores del bot (filtra por el path): +grep "/webhook\|/health" /var/log/nginx/access.log | tail -20 +``` + +### Eventos útiles que buscar en los logs del bot + +| Evento | Qué significa | +|--------|---------------| +| `login_exitoso` | Se conectó al PJ correctamente | +| `migration_aplicada` | Se aplicó una migración de DB (solo al arrancar) | +| `health_server_iniciado` | El server HTTP de health está escuchando | +| `webhook_registrado` | El webhook se registró con Telegram correctamente | +| `polling_tenant_ok` | Revisión de notificaciones completada sin errores | +| `polling_tenant_error` | Error al revisar notificaciones de un abogado | +| `pj_error_conexion` | El PJ no respondió (puede ser transitorio) | +| `bot_notificacion_enviada` | Se envió una notificación a Telegram | +| `onboarding_completado` | Un abogado completó el registro | +| `health_alerta_enviada` | El bot detectó que el poller está detenido y avisó al admin | + +### Ver historial de eventos vía HTTP + +```bash +# Últimos 50 eventos del audit log: +curl -s https://pedrito.inqualityhq.com/health/history | python3 -m json.tool + +# Últimos 100 eventos: +curl -s "https://pedrito.inqualityhq.com/health/history?limit=100" | python3 -m json.tool +``` + +--- + +## 17. Health check HTTP + +El bot expone un endpoint HTTP en `https://pedrito.inqualityhq.com/health` que retorna el estado actual. + +### Ejemplo de respuesta normal (status 200) + +```json +{ + "status": "ok", + "timestamp": "2026-05-25T10:00:00+00:00", + "tenants_activos": 3, + "last_poll": "2026-05-25T09:58:42+00:00", + "last_poll_tenants": 3, + "seconds_since_last_poll": 78, + "poll_interval_minutes": 60, + "webhook_mode": true +} +``` + +### Ejemplo de respuesta degradada (status 503) + +Si el poller no actualizó en más de `HEALTH_ALERT_HOURS` horas, retorna: +```json +{ + "status": "degraded", + ... +} +``` + +En ese caso, el bot también manda un mensaje de alerta automáticamente al Telegram de Marcos. + +### Integrar con un monitor externo (opcional) + +Si tienen un servicio de uptime monitoring (UptimeRobot, BetterUptime, etc.): +- URL a monitorear: `https://pedrito.inqualityhq.com/health` +- Método: `GET` +- Código esperado: `200` +- Intervalo: `5 minutos` + +--- + +## 18. Cómo actualizar el bot + +Cuando hay cambios en el código (nuevo commit en el repositorio): + +```bash +# Como pedrito: +su - pedrito +cd /home/pedrito/hechakuaa_bot + +# 1. Traer los cambios del repositorio +git pull + +# 2. Reconstruir la imagen con el nuevo código +docker compose build + +# 3. Reiniciar el contenedor con la nueva imagen +docker compose up -d + +# 4. Verificar que levantó bien +docker compose ps +docker compose logs --tail=20 +``` + +> **Importante:** 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. + +> **Si hubo cambios en `.env.example`:** revisar manualmente si hay nuevos campos que agregar al `.env` existente. > ```bash -> ufw allow 80/tcp # HTTP -> ufw allow 443/tcp # HTTPS +> # Ver diferencias entre el template nuevo y el .env actual: +> diff .env.example .env > ``` --- -## 12. Verificación final +## 19. Troubleshooting -Revisar que todo quedó en orden: +### El contenedor no arranca ```bash -# 1. El servicio está corriendo -systemctl status pedrito -# Esperado: active (running) +# Ver el error específico: +docker compose logs --tail=50 -# 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 +# O ver el estado del contenedor: +docker compose ps ``` -Si todos los puntos pasan, el deploy está completo. -Avisarle a Marcos para que pruebe mandándole `/start` al bot en Telegram. +**`FERNET_KEY inválida`** +La clave en `.env` es incorrecta o tiene espacios/comillas. Verificar que el valor +en `.env` no tiene comillas ni espacios al inicio/final. ---- - -## 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 -``` +**`telegram.error.InvalidToken`** +El `TELEGRAM_BOT_TOKEN` en `.env` tiene un error. Verificar copiando el token +directamente desde la conversación con @BotFather en Telegram. **`ModuleNotFoundError: No module named 'X'`** +La imagen necesita ser reconstruida: ```bash -su - pedrito -cd hechakuaa_bot -uv sync -exit -systemctl restart pedrito +docker compose build --no-cache +docker compose up -d ``` -**`.venv/bin/python: No such file or directory`** +**`Error response from daemon: Cannot connect to the Docker daemon`** +Docker no está corriendo: ```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 +systemctl start docker +docker compose up -d ``` --- ### 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 +1. Verificar que el contenedor está corriendo: `docker compose ps` +2. Verificar que el webhook está registrado: `curl -s "https://api.telegram.org/bot/getWebhookInfo"` +3. Verificar que Nginx está ok: `systemctl status nginx` +4. Verificar que el health check responde: `curl -s https://pedrito.inqualityhq.com/health` +5. Revisar logs de Nginx: `tail -20 /var/log/nginx/error.log` --- -### Error de credenciales del PJ (`Credenciales incorrectas`) +### Error de credenciales del PJ ```bash su - pedrito -cd hechakuaa_bot +cd /home/pedrito/hechakuaa_bot # Repetir el cifrado de credenciales uv run python scripts/cifrar_credenciales.py -exit -systemctl restart pedrito +# Reiniciar el bot +docker compose restart +docker compose logs --tail=10 ``` --- -### La VPS se reinició y el bot no volvió +### El certificado SSL venció o hay error de SSL ```bash -systemctl status pedrito -# Si dice "disabled": -systemctl enable pedrito -systemctl start pedrito +# Renovar manualmente (normalmente es automático): +certbot renew + +# Recargar Nginx para que use el nuevo certificado: +systemctl reload nginx ``` --- -### Ver si hay dos instancias corriendo (causa conflictos) +### El webhook no recibe mensajes (pero el bot arranca) ```bash -ps aux | grep "python main.py" | grep -v grep -``` +# 1. Verificar que Nginx está reenviando correctamente: +tail -20 /var/log/nginx/access.log +# Debe aparecer peticiones POST a /webhook cuando alguien manda un mensaje -Si hay más de una línea, matar todas y reiniciar el servicio: -```bash -pkill -f "python main.py" -systemctl start pedrito +# 2. Verificar el health check del bot directamente (sin pasar por Nginx): +# Desde el propio servidor: +curl -s http://127.0.0.1:8080/health + +# 3. Volver a registrar el webhook manualmente: +curl "https://api.telegram.org/bot/setWebhook?url=https://pedrito.inqualityhq.com/webhook&secret_token=" ``` --- -## Referencia rápida de comandos +### El VPS se reinició y el bot no volvió + +El contenedor tiene `restart: unless-stopped`, así que debería volver solo. Si no: +```bash +su - pedrito +cd /home/pedrito/hechakuaa_bot +docker compose up -d +``` + +Si Docker en sí no arrancó: +```bash +systemctl start docker +su - pedrito +cd /home/pedrito/hechakuaa_bot +docker compose up -d +``` + +--- + +### Ver dos instancias corriendo (causa conflictos de Telegram) ```bash -# Estado del servicio -systemctl status pedrito +docker compose ps +# Si hay más de un contenedor corriendo: +docker compose down +docker compose up -d +``` + +--- + +### Error de permisos en el directorio data/ + +```bash +# Como root: +chown -R 1000:1000 /home/pedrito/hechakuaa_bot/data +# Reiniciar: +su - pedrito +cd /home/pedrito/hechakuaa_bot +docker compose restart +``` + +--- + +## 20. Referencia rápida de comandos + +### Gestión del bot (como usuario `pedrito`) + +```bash +cd /home/pedrito/hechakuaa_bot + +# Estado +docker compose ps # Iniciar / detener / reiniciar -systemctl start pedrito -systemctl stop pedrito -systemctl restart pedrito +docker compose up -d +docker compose down +docker compose restart # Logs en tiempo real -journalctl -u pedrito -f +docker compose logs -f -# Actualizar el bot -su - pedrito -c "cd hechakuaa_bot && git pull && uv sync" -systemctl restart pedrito +# Logs últimos 50 registros +docker compose logs --tail=50 + +# Actualizar (git pull + rebuild + restart) +git pull && docker compose build && docker compose up -d ``` +### Nginx (como `root`) + +```bash +# Verificar configuración +nginx -t + +# Recargar sin cortar conexiones +systemctl reload nginx + +# Reiniciar completamente +systemctl restart nginx + +# Ver logs de error +tail -f /var/log/nginx/error.log +``` + +### SSL + +```bash +# Renovar certificado manualmente +certbot renew + +# Ver fecha de vencimiento del certificado actual +certbot certificates +``` + +### Rutas de archivos importantes + +| Archivo | Ruta absoluta | +|---------|---------------| +| Código del bot | `/home/pedrito/hechakuaa_bot/` | +| Configuración | `/home/pedrito/hechakuaa_bot/.env` | +| Base de datos SQLite | `/home/pedrito/hechakuaa_bot/data/pasante.db` | +| Snapshots de notificaciones | `/home/pedrito/hechakuaa_bot/data/snapshot_*.json` | +| Docker Compose | `/home/pedrito/hechakuaa_bot/docker-compose.yml` | +| Config Nginx del bot | `/etc/nginx/sites-available/pedrito` | +| Logs de Nginx | `/var/log/nginx/` | +| Certificado SSL (cert) | `/etc/letsencrypt/live/pedrito.inqualityhq.com/fullchain.pem` | +| Certificado SSL (clave) | `/etc/letsencrypt/live/pedrito.inqualityhq.com/privkey.pem` | + --- *Repositorio: https://github.com/InqGit/hechakuaa_bot* -*Ante dudas, contactar a Marcos Benítez.* +*Ante dudas técnicas no cubiertas acá, contactar a Marcos Benítez.*