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>
14 KiB
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
- Antes de empezar — datos que necesitás de Marcos
- Conectarse a la VPS
- Crear usuario dedicado
- Instalar dependencias del sistema
- Clonar el repositorio
- Instalar dependencias del proyecto
- Configurar el archivo .env
- Cifrar las credenciales del PJ
- Verificar que el bot arranca
- Crear el servicio systemd
- Configurar el firewall
- Verificación final
- Monitoreo y logs
- Cómo actualizar el bot
- 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
ssh root@<IP_DE_LA_VPS>
Si usás clave SSH (recomendado):
ssh -i ~/.ssh/id_rsa root@<IP_DE_LA_VPS>
Verificar que el sistema está actualizado:
apt update && apt upgrade -y
3. Crear usuario dedicado
El bot no debe correr como root. Creamos un usuario propio llamado pedrito.
# 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
# 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:
ssh pedrito@<IP_DE_LA_VPS>Si entra sin pedir contraseña, todo está bien.
4. Instalar dependencias del sistema
# Aún como root
apt install -y git curl
Verificar Python 3.12+:
python3 --version
Si la versión es menor a 3.12:
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:
# 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).
# 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
.envse crea directamente en la VPS. Nunca se copia desde tu máquina ni se sube al repositorio. Tiene permisos 600 (solo lo puede leerpedrito).
# 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):
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:
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
.envcomo valor deFERNET_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.
uv run python scripts/cifrar_credenciales.py
El script te va a pedir:
- Cédula de identidad — el usuario con el que Marcos entra a
apps.csj.gov.py - 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:
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:
uv run python main.py
Salida esperada (en formato JSON, primeras líneas):
{"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:
exit # salir del usuario pedrito, volver a root
Crear el archivo de servicio:
nano /etc/systemd/system/pedrito.service
Pegar exactamente este contenido:
[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:
# 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.
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.
# 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 enablepara no cortarlos:ufw allow 80/tcp # HTTP ufw allow 443/tcp # HTTPS
12. Verificación final
Revisar que todo quedó en orden:
# 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
journalctl -u pedrito -f
Detener con Ctrl+C.
Ver los últimos N registros
journalctl -u pedrito -n 50
Ver logs de la última hora
journalctl -u pedrito --since "1 hour ago"
Ver logs de un día específico
journalctl -u pedrito --since "2026-05-25 00:00:00" --until "2026-05-25 23:59:59"
Buscar errores
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):
# 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
.envy el directoriodata/no se tocan congit pull— están en.gitignore. Las credenciales y el historial de notificaciones persisten entre actualizaciones.
15. Troubleshooting
El servicio no arranca (failed)
# Ver el error específico
journalctl -u pedrito -n 50
systemctl status pedrito
ModuleNotFoundError: No module named 'X'
su - pedrito
cd hechakuaa_bot
uv sync
exit
systemctl restart pedrito
.venv/bin/python: No such file or directory
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:
su - pedrito
mkdir -p /home/pedrito/hechakuaa_bot/data
exit
systemctl restart pedrito
El bot arranca pero no responde en Telegram
- Verificar que
TELEGRAM_BOT_TOKENen.enves correcto - Verificar que
TELEGRAM_CHAT_IDes el chat_id correcto de Marcos - Revisar logs:
journalctl -u pedrito -n 30 - Desde otro cliente probar que el bot existe: buscar
@pedrito_hechakuaaboten Telegram
Error de credenciales del PJ (Credenciales incorrectas)
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ó
systemctl status pedrito
# Si dice "disabled":
systemctl enable pedrito
systemctl start pedrito
Ver si hay dos instancias corriendo (causa conflictos)
ps aux | grep "python main.py" | grep -v grep
Si hay más de una línea, matar todas y reiniciar el servicio:
pkill -f "python main.py"
systemctl start pedrito
Referencia rápida de comandos
# 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.