Cap 8: Despliegue

Por: Artiko
desplieguengrokrailwayvpswebhookproduccion

Modos de operación

flowchart TD
    subgraph DEV[Desarrollo local]
        POL[Polling\nbun bot.py] -->|funciona sin URL| TG1[Telegram]
        NGR[Webhook + ngrok\nURL temporal] --> TG1
    end

    subgraph PROD[Producción]
        VPS[VPS / Railway\nWebhook HTTPS] --> TG2[Telegram]
    end

Para el tutorial de Claude Code local (cap. 5), el bot siempre corre en local en modo polling — el Claude Code necesita acceso al filesystem de tu máquina.

Desarrollo local con polling

La forma más simple. No necesitas ngrok ni URL pública:

# Activar entorno virtual
source .venv/bin/activate

# Iniciar bot
python bot.py

Para recargar automáticamente en cambios:

pip install watchfiles
watchfiles "python bot.py" .

Desarrollo con webhook — ngrok

Si necesitas probar webhooks localmente:

# Instalar ngrok
# linux: snap install ngrok / brew install ngrok

ngrok http 8080
# → https://abc123.ngrok-free.app

Actualiza bot.py para webhook:

import os
from telegram.ext import Application

WEBHOOK_URL = os.getenv("WEBHOOK_URL")  # tu URL de ngrok o producción
PORT = int(os.getenv("PORT", "8080"))

def main():
    init_db()
    app = Application.builder().token(TELEGRAM_TOKEN).build()
    # ... handlers

    if WEBHOOK_URL:
        # Modo webhook
        app.run_webhook(
            listen="0.0.0.0",
            port=PORT,
            webhook_url=f"{WEBHOOK_URL}/webhook",
            url_path="/webhook",
        )
    else:
        # Modo polling (desarrollo simple)
        app.run_polling(allowed_updates=["message", "callback_query"])

if __name__ == "__main__":
    main()
# Con webhook local
WEBHOOK_URL=https://abc123.ngrok-free.app python bot.py

Despliegue en Railway

Railway es ideal para el bot con Claude API (sin Claude Code local):

1. Preparar Procfile

# Procfile
web: python bot.py

2. Subir a GitHub

git init
git add .
git commit -m "feat: bot telegram con claude"
git remote add origin https://github.com/usuario/mi-bot.git
git push -u origin main

3. Crear proyecto en Railway

# Instalar Railway CLI
npm install -g @railway/cli

railway login
railway init
railway up

4. Configurar variables de entorno en Railway

En el dashboard de Railway → Variables:

TELEGRAM_BOT_TOKEN = 7123...
ANTHROPIC_API_KEY = sk-ant-...
ALLOWED_USER_ID = 123456789
CLAUDE_MODEL = claude-opus-4-5-20251001
WEBHOOK_URL = https://mi-bot.up.railway.app
PORT = 8080

5. Despliegue automático

Railway re-deploya en cada push a main. El bot estará disponible 24/7.

Despliegue en VPS (Ubuntu)

Para el caso de Claude Code local — necesitas una máquina con tu repositorio:

Instalar dependencias

# En el VPS
sudo apt update && sudo apt install -y python3.11 python3.11-venv git nodejs npm

# Claude Code
npm install -g @anthropic-ai/claude-code
claude  # hacer login

# Clonar tu repositorio del proyecto
git clone https://github.com/usuario/mi-proyecto.git ~/mi-proyecto

# Clonar el bot
git clone https://github.com/usuario/mi-bot.git ~/mi-bot
cd ~/mi-bot
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Configurar como servicio systemd

# /etc/systemd/system/telegram-bot.service
sudo nano /etc/systemd/system/telegram-bot.service
[Unit]
Description=Telegram Claude Bot
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/mi-bot
EnvironmentFile=/home/ubuntu/mi-bot/.env
ExecStart=/home/ubuntu/mi-bot/.venv/bin/python bot.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl enable telegram-bot
sudo systemctl start telegram-bot
sudo systemctl status telegram-bot

# Ver logs
sudo journalctl -u telegram-bot -f

Actualizar el bot

cd ~/mi-bot
git pull
sudo systemctl restart telegram-bot

Dockerfile para contenedor

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "bot.py"]
docker build -t telegram-bot .
docker run -d \
  --env-file .env \
  --name telegram-bot \
  --restart unless-stopped \
  telegram-bot

Keep-alive y health check

Para evitar que el servicio muera silenciosamente, agrega un endpoint de health y un ping periódico:

# En bot.py, antes de run_polling/run_webhook

from aiohttp import web

async def health_check(request):
    return web.Response(text="ok")

async def start_health_server():
    app_web = web.Application()
    app_web.router.add_get("/health", health_check)
    runner = web.AppRunner(app_web)
    await runner.setup()
    site = web.TCPSite(runner, "0.0.0.0", 9090)
    await site.start()

Agrega aiohttp a requirements.txt.

Checklist de producción

Monitoreo básico

Agrega un comando /ping para verificar que el bot responde:

async def cmd_ping(update: Update, context: ContextTypes.DEFAULT_TYPE):
    import time
    t = time.time()
    msg = await update.message.reply_text("Pong!")
    latencia = int((time.time() - t) * 1000)
    await msg.edit_text(f"Pong! Latencia: {latencia}ms")

app.add_handler(CommandHandler("ping", cmd_ping))

Arquitectura final del sistema

flowchart TD
    subgraph LOCAL[Máquina local o VPS]
        BOT[Bot Python\npython bot.py] --> DB[(SQLite\nbot_history.db)]
        BOT --> CC[Claude Code CLI\nclaude --print]
        CC --> REPO[Repositorio\nde código]
    end

    subgraph CLOUD[Cloud]
        TG[Telegram Servers]
        ANT[Anthropic API]
    end

    PHONE([Teléfono]) <--> TG
    TG <-->|polling| BOT
    BOT <-->|HTTP| ANT