Files
hechakuaa_bot/DEPLOY.md
markosbenitez 6487a7857c Add DEPLOY.md — guía completa de despliegue en VPS Ubuntu
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 <noreply@anthropic.com>
2026-05-25 11:20:48 -03:00

594 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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:** 3045 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@<IP_DE_LA_VPS>
```
Si usás clave SSH (recomendado):
```bash
ssh -i ~/.ssh/id_rsa root@<IP_DE_LA_VPS>
```
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@<IP_DE_LA_VPS>
> ```
> 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=<clave que te pasó Marcos>
TELEGRAM_BOT_TOKEN=<token del bot de @BotFather>
TELEGRAM_CHAT_ID=<chat_id de Marcos>
```
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.*