Tu bot necesita estar online 24/7. Tu ordenador personal no puede hacer eso. Un VPS es la solución perfecta: siempre encendido, IP fija, recursos dedicados.
Bots de Discord, Telegram, scrapers, tareas programadas… todo funcionando mientras duermes. Esta guía te enseña a montarlo correctamente.
Por qué un VPS para bots
Tu PC vs VPS
| Aspecto | Tu ordenador | VPS |
|---|---|---|
| Disponibilidad | Cuando está encendido | 24/7/365 |
| IP | Dinámica | Fija |
| Recursos | Compartidos | Dedicados |
| Electricidad | Pagas tú | Incluida |
| Reinicio | Manual | Automático |
| Escalabilidad | Limitada | Flexible |
Casos de uso comunes
- Bots de Discord: Moderación, música, juegos
- Bots de Telegram: Notificaciones, comandos, grupos
- Web scraping: Extraer datos periódicamente
- Cron jobs: Backups, reportes, sincronización
- Trading bots: Crypto, forex (con precaución)
- Monitorización: Alertas, uptime checks
Requisitos del VPS
Por tipo de bot
| Tipo de bot | RAM | CPU | Notas |
|---|---|---|---|
| Bot Discord simple | 512 MB | 1 core | Comandos básicos |
| Bot Discord con música | 1-2 GB | 1-2 cores | Audio consume más |
| Bot Telegram | 512 MB | 1 core | Muy ligero |
| Web scraper | 1-2 GB | 1-2 cores | Depende de frecuencia |
| Trading bot | 1-2 GB | 2 cores | Necesita baja latencia |
| Múltiples bots | 2-4 GB | 2 cores | Escala según cantidad |
VPS recomendado para empezar
- RAM: 2 GB (suficiente para varios bots)
- CPU: 1-2 cores
- Almacenamiento: 20 GB SSD
- Coste: ~€5-10/mes
Arquitectura típica
┌─────────────────────────────────────────┐
│ Tu VPS │
│ │
│ ┌──────────┐ ┌──────────┐ ┌────────┐ │
│ │ Bot │ │ Bot │ │ Cron │ │
│ │ Discord │ │ Telegram │ │ Jobs │ │
│ └────┬─────┘ └────┬─────┘ └───┬────┘ │
│ │ │ │ │
│ ┌────┴─────────────┴────────────┴────┐ │
│ │ PM2 / Systemd │ │
│ │ (gestiona procesos 24/7) │ │
│ └────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ Base de datos (opcional) │ │
│ │ SQLite / Redis │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────┘
Configuración inicial del VPS
Preparar el sistema
# Actualizar
sudo apt update && sudo apt upgrade -y
# Instalar utilidades
sudo apt install -y git curl wget htop
# Crear usuario para bots (no usar root)
sudo useradd -m -s /bin/bash botuser
sudo passwd botuser
Instalar Node.js (para bots JS/TS)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Verificar
node --version
npm --version
Instalar Python (para bots Python)
sudo apt install -y python3 python3-pip python3-venv
# Verificar
python3 --version
pip3 --version
Instalar PM2 (gestor de procesos)
sudo npm install -g pm2
Bot de Discord
Crear el bot en Discord Developer Portal
- Ve a discord.com/developers/applications
- New Application → Nombre
- Bot → Add Bot
- Copia el TOKEN (guárdalo seguro)
- OAuth2 → URL Generator → bot + permissions
- Invita el bot a tu servidor
Bot básico (Node.js + discord.js)
# Como botuser
su - botuser
mkdir discord-bot && cd discord-bot
npm init -y
npm install discord.js dotenv
// index.js
require('dotenv').config();
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
]
});
client.once('ready', () => {
console.log(`Bot online: ${client.user.tag}`);
});
client.on('messageCreate', message => {
if (message.content === '!ping') {
message.reply('Pong! 🏓');
}
});
client.login(process.env.DISCORD_TOKEN);
# .env
DISCORD_TOKEN=tu_token_aqui
Ejecutar con PM2
pm2 start index.js --name "discord-bot"
pm2 save
pm2 startup
Bot de Telegram
Crear el bot con BotFather
- Habla con @BotFather en Telegram
/newbot→ Nombre → Username- Copia el TOKEN
Bot básico (Python + python-telegram-bot)
su - botuser
mkdir telegram-bot && cd telegram-bot
python3 -m venv venv
source venv/bin/activate
pip install python-telegram-bot python-dotenv
# bot.py
import os
from dotenv import load_dotenv
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
load_dotenv()
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text('¡Hola! Soy tu bot.')
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE):
await update.message.reply_text(update.message.text)
def main():
app = Application.builder().token(os.getenv('TELEGRAM_TOKEN')).build()
app.add_handler(CommandHandler('start', start))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
print('Bot iniciado...')
app.run_polling()
if __name__ == '__main__':
main()
# .env
TELEGRAM_TOKEN=tu_token_aqui
Ejecutar con PM2
pm2 start bot.py --name "telegram-bot" --interpreter python3
pm2 save
Web Scraping automatizado
Scraper básico (Python + BeautifulSoup)
mkdir scraper && cd scraper
python3 -m venv venv
source venv/bin/activate
pip install requests beautifulsoup4 schedule
# scraper.py
import requests
from bs4 import BeautifulSoup
import schedule
import time
from datetime import datetime
def scrape_prices():
url = 'https://ejemplo.com/productos'
try:
response = requests.get(url, timeout=10)
soup = BeautifulSoup(response.text, 'html.parser')
# Ejemplo: extraer precios
prices = soup.select('.price')
for price in prices:
print(f"{datetime.now()}: {price.text}")
# Guardar en archivo o base de datos
with open('prices.log', 'a') as f:
f.write(f"{datetime.now()}: {len(prices)} precios\n")
except Exception as e:
print(f"Error: {e}")
# Ejecutar cada hora
schedule.every(1).hours.do(scrape_prices)
# Primera ejecución
scrape_prices()
print("Scraper iniciado...")
while True:
schedule.run_pending()
time.sleep(60)
Ejecutar con PM2
pm2 start scraper.py --name "price-scraper" --interpreter python3
Cron Jobs (tareas programadas)
Usando crontab
crontab -e
# Formato: minuto hora día mes día_semana comando
# Backup diario a las 3 AM
0 3 * * * /home/botuser/scripts/backup.sh
# Scraper cada 6 horas
0 */6 * * * /home/botuser/scraper/venv/bin/python /home/botuser/scraper/run.py
# Reporte semanal los lunes a las 9 AM
0 9 * * 1 /home/botuser/scripts/weekly-report.sh
# Limpiar logs cada domingo
0 0 * * 0 find /home/botuser/logs -mtime +30 -delete
Script de backup ejemplo
#!/bin/bash
# /home/botuser/scripts/backup.sh
DATE=$(date +%Y%m%d)
BACKUP_DIR="/home/botuser/backups"
# Backup de datos de bots
tar -czf $BACKUP_DIR/bots-$DATE.tar.gz /home/botuser/discord-bot/data /home/botuser/telegram-bot/data
# Eliminar backups antiguos
find $BACKUP_DIR -mtime +7 -delete
echo "Backup completado: $DATE"
chmod +x /home/botuser/scripts/backup.sh
Gestión con PM2
Comandos esenciales
# Ver todos los procesos
pm2 list
# Ver logs en tiempo real
pm2 logs
# Logs de un proceso específico
pm2 logs discord-bot
# Reiniciar proceso
pm2 restart discord-bot
# Detener proceso
pm2 stop discord-bot
# Eliminar proceso
pm2 delete discord-bot
# Monitorización
pm2 monit
Archivo de configuración ecosystem
// ecosystem.config.js
module.exports = {
apps: [
{
name: 'discord-bot',
script: './discord-bot/index.js',
watch: false,
max_memory_restart: '200M',
env: {
NODE_ENV: 'production'
}
},
{
name: 'telegram-bot',
script: './telegram-bot/bot.py',
interpreter: 'python3',
watch: false,
max_memory_restart: '150M'
},
{
name: 'scraper',
script: './scraper/scraper.py',
interpreter: './scraper/venv/bin/python',
cron_restart: '0 */6 * * *' // Reiniciar cada 6 horas
}
]
};
pm2 start ecosystem.config.js
pm2 save
Auto-arranque al reiniciar
pm2 startup
# Ejecuta el comando que te muestra
pm2 save
Variables de entorno seguras
Archivo .env
# /home/botuser/discord-bot/.env
DISCORD_TOKEN=xxx
DATABASE_URL=sqlite:///data/bot.db
LOG_LEVEL=info
Permisos seguros
chmod 600 .env
Nunca commitear .env
# .gitignore
.env
*.log
node_modules/
__pycache__/
venv/
Base de datos para bots
SQLite (simple, sin servidor)
// Node.js con better-sqlite3
const Database = require('better-sqlite3');
const db = new Database('bot.db');
db.exec(`
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
username TEXT,
points INTEGER DEFAULT 0
)
`);
# Python con sqlite3
import sqlite3
conn = sqlite3.connect('bot.db')
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
username TEXT,
points INTEGER DEFAULT 0
)
''')
conn.commit()
Redis (caché rápido)
sudo apt install redis-server -y
// Node.js
const Redis = require('ioredis');
const redis = new Redis();
await redis.set('user:123:points', 100);
const points = await redis.get('user:123:points');
Monitorización y alertas
Logs estructurados
// Node.js con winston
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
logger.info('Bot iniciado');
logger.error('Error en comando', { command: 'ping', error: err.message });
Alertas por Telegram
# alert.py - Envía alertas a tu Telegram
import requests
def send_alert(message):
token = 'TU_BOT_TOKEN'
chat_id = 'TU_CHAT_ID'
url = f'https://api.telegram.org/bot{token}/sendMessage'
requests.post(url, data={'chat_id': chat_id, 'text': message})
# Usar en tu bot
try:
# código que puede fallar
except Exception as e:
send_alert(f'❌ Error en bot: {e}')
Healthcheck simple
#!/bin/bash
# /home/botuser/scripts/healthcheck.sh
# Verificar que PM2 está corriendo
if ! pm2 list | grep -q "online"; then
echo "PM2 no tiene procesos online" | mail -s "Alert: Bots down" [email protected]
fi
# Verificar memoria
MEM_USED=$(free | grep Mem | awk '{print int($3/$2 * 100)}')
if [ $MEM_USED -gt 90 ]; then
echo "Memoria al ${MEM_USED}%" | mail -s "Alert: High memory" [email protected]
fi
# Cron cada 5 minutos
*/5 * * * * /home/botuser/scripts/healthcheck.sh
Seguridad
Firewall básico
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw enable
Los bots no necesitan puertos abiertos (hacen conexiones salientes).
No usar root
Siempre ejecuta bots como usuario sin privilegios.
Tokens seguros
- Nunca commitear tokens a Git
- Usar variables de entorno
- Rotar tokens si se exponen
Preguntas frecuentes
¿Puedo ejecutar varios bots en un VPS pequeño?
Sí, un VPS de 2GB puede ejecutar 5-10 bots simples sin problemas. PM2 gestiona los recursos eficientemente.
¿Qué pasa si mi bot se cae?
PM2 lo reinicia automáticamente. Configura alertas para enterarte cuando ocurra y revisar logs.
¿Necesito IP dedicada para bots?
No es obligatorio, pero algunos servicios pueden limitar IPs compartidas. La mayoría de VPS incluyen IP dedicada.
¿Puedo hacer scraping de cualquier web?
Técnicamente sí, pero respeta robots.txt, términos de servicio y no sobrecargues servidores ajenos. El scraping agresivo puede bloquear tu IP.
¿Cómo actualizo mi bot sin downtime?
Con PM2: git pull, npm install (si hay cambios), pm2 restart bot-name. El reinicio es casi instantáneo.
Nuestra recomendación
Para empezar (1-3 bots):
- VPS 2GB RAM
- PM2 para gestión
- SQLite para datos
Para múltiples bots o scrapers:
- VPS 4GB RAM
- Redis para caché
- Monitorización con alertas
¿Necesitas ayuda configurando tus bots? La administración gestionada de Avantys puede configurar y mantener tu infraestructura de automatización.
Conclusión
Un VPS para bots es una inversión pequeña que te libera de tener el ordenador encendido 24/7. Con PM2 y buenas prácticas, tus bots funcionarán de forma fiable durante meses sin intervención.
Empieza con un bot, aprende el flujo, y escala desde ahí.
¿Listo para tus bots 24/7? Explora los VPS de Avantys con recursos dedicados para automatización.
¿Quieres que lo hagamos por ti?
En Avantys gestionamos tu web, hosting y crecimiento digital de punta a punta. Tú a lo importante.