RDP Monster

Alojar un bot de Discord en un VPS: en línea 24/7

Alojar un bot de Discord en un VPS: en línea 24/7

Por qué un VPS es donde los bots de Discord se mantienen realmente en línea

Un bot de Discord no es una página web. Una vez conectado, mantiene una conexión WebSocket persistente con la gateway de Discord y debe responder continuamente a los heartbeats; cuando el proceso se detiene, el bot aparece desconectado y todos los comandos fallan. Ese único requisito, un proceso que nunca duerme, descarta la mayoría de los alojamientos «gratuitos»:

  • Heroku eliminó sus dynos gratuitos en noviembre de 2022.
  • Replit ya no mantiene los proyectos gratuitos en ejecución; el modo always-on pasó a los despliegues de pago.
  • Glitch puso fin a su alojamiento de aplicaciones en 2025.
  • Los planes web gratuitos que se duermen tras la inactividad cortan la conexión con la gateway cada vez que quedan inactivos; para los usuarios, ese bot simplemente está caído.

Alojar un bot de Discord en un VPS resuelve el problema de raíz: una máquina Linux con acceso root que funciona a todas horas, donde el bot es un servicio más gestionado por el sistema de init. Esta guía lo monta sobre Ubuntu 24.04 (válido también para 22.04 y Debian 12) con discord.py y discord.js, y después cubre la gestión del token, los reinicios, los logs, las actualizaciones y la memoria.

Preparar el VPS: un usuario dedicado y un runtime

Asegura primero la puerta de entrada: activa SSH en Ubuntu y refuérzalo con autenticación por clave, sin login de root y con ufw. Un bot se conecta hacia fuera, hacia Discord, y no necesita ningún puerto entrante, así que el firewall puede quedar cerrado a todo salvo SSH.

Paso 1: crear una cuenta sin privilegios para el bot

sudo useradd -r -m -d /opt/mybot -s /usr/sbin/nologin bot

Una cuenta dedicada implica que un bot con errores o una dependencia de npm o PyPI comprometida no puede leer tus claves SSH ni tocar otros servicios. Todo vive en /opt/mybot, propiedad de bot.

Paso 2 (Python): instalar discord.py en un entorno virtual

sudo apt update && sudo apt install -y python3 python3-venv python3-pip
sudo -u bot python3 -m venv /opt/mybot/.venv
sudo -u bot /opt/mybot/.venv/bin/pip install -U discord.py python-dotenv

discord.py 2.x requiere Python 3.8 o superior; Ubuntu 24.04 incluye la 3.12 y 22.04 la 3.10, así que el intérprete de la distribución sirve. Añade discord.py[voice] y ffmpeg solo para los canales de voz.

Paso 3 (Node.js): instalar una LTS actual y discord.js

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
sudo -u bot bash -c 'cd /opt/mybot && npm init -y && npm install discord.js dotenv'

El paquete nodejs propio de Ubuntu va muy por detrás del upstream y discord.js v14 necesita un runtime moderno, así que usa NodeSource (arriba) o nvm para una LTS actual. Con nvm, ejecuta which node y usa esa ruta absoluta en la unidad de servicio.

Mantener el token fuera del código: el archivo .env

El token del bot es una contraseña con control total sobre él: no lo pegues nunca en bot.py ni en index.js, ni lo subas a un repositorio. Colócalo en /opt/mybot/.env, legible solo por la cuenta del bot, usando un editor en lugar de echo, ya que un token escrito en la línea de comandos acaba en el historial del shell:

sudo -u bot nano /opt/mybot/.env        # one line: DISCORD_TOKEN=your-token-here
sudo chmod 600 /opt/mybot/.env
echo ".env" | sudo -u bot tee -a /opt/mybot/.gitignore

El formato es un KEY=value por línea, sin comillas y sin export. python-dotenv y el paquete npm dotenv lo leen, y systemd puede inyectar el mismo archivo con EnvironmentFile= (siguiente sección); combinar ambos es inofensivo, porque ninguna de las dos bibliotecas sobrescribe una variable que ya existe. Si el token se filtra alguna vez, regenéralo de inmediato en el Developer Portal, en Bot → Reset Token.

Un bot mínimo en discord.py y discord.js

Ambos ejemplos leen el token del entorno, activan el intent de contenido de mensajes y responden a !ping. En el Developer Portal, crea una aplicación, añade un usuario bot, copia el token (se muestra una sola vez), activa Message Content Intent en Bot → Privileged Gateway Intents e invita al bot a un servidor de pruebas mediante el generador de URL de OAuth2 con el scope bot.

discord.py: /opt/mybot/bot.py

import os
import discord
from dotenv import load_dotenv

load_dotenv()

intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)

@client.event
async def on_ready():
    print(f"Logged in as {client.user}")

@client.event
async def on_message(message):
    if message.author == client.user:
        return
    if message.content == "!ping":
        await message.channel.send("pong")

client.run(os.environ["DISCORD_TOKEN"])

discord.js: /opt/mybot/index.js

require("dotenv").config();
const { Client, GatewayIntentBits, Events } = require("discord.js");

const client = new Client({
  intents: [
    GatewayIntentBits.Guilds,
    GatewayIntentBits.GuildMessages,
    GatewayIntentBits.MessageContent,
  ],
});

client.once(Events.ClientReady, (c) => {
  console.log(`Logged in as ${c.user.tag}`);
});

client.on(Events.MessageCreate, (message) => {
  if (message.author.bot) return;
  if (message.content === "!ping") message.reply("pong");
});

client.login(process.env.DISCORD_TOKEN);

Ejecútalo una vez en primer plano: sudo -u bot /opt/mybot/.venv/bin/python /opt/mybot/bot.py o sudo -u bot node /opt/mybot/index.js, espera a Logged in as, envía !ping y pulsa Ctrl-C. Ahora mismo el bot vive solo mientras dure tu sesión SSH: cerrar la terminal envía SIGHUP a sus procesos hijos y el bot muere.

Ejecutarlo bajo systemd con Restart=always

systemd ya es el sistema de init de Ubuntu, así que la forma más limpia de mantener el bot en línea tras cerrar sesión, tras un fallo y tras un reinicio es una unidad de servicio: sin ningún demonio extra, y con los logs en el journal.

Paso 1: escribir la unidad

sudo nano /etc/systemd/system/mybot.service
[Unit]
Description=Discord bot
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=bot
Group=bot
WorkingDirectory=/opt/mybot
EnvironmentFile=/opt/mybot/.env
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/mybot/.venv/bin/python /opt/mybot/bot.py
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/mybot

[Install]
WantedBy=multi-user.target

Para discord.js, pon ExecStart=/usr/bin/node /opt/mybot/index.js y elimina la línea PYTHONUNBUFFERED. Las directivas que importan:

  • Restart=always reinicia el proceso ante cualquier salida, tanto un fallo como un sys.exit() limpio; RestartSec=5 evita que un bot que muere al instante (token incorrecto, error de sintaxis) entre en un bucle cerrado.
  • Wants=/After=network-online.target retrasan el arranque hasta que la red esté disponible, para que el primer login tras un reinicio no falle por DNS.
  • PYTHONUNBUFFERED=1: sin terminal, Python almacena stdout en búfer por bloques y las líneas de print() llegan al journal con minutos de retraso o solo al salir.
  • Las líneas Protect*, PrivateTmp y NoNewPrivileges dejan el resto del sistema de archivos en solo lectura o invisible para el bot; añade a ReadWritePaths= cualquier directorio en el que deba escribir.

Paso 2: habilitar, arrancar y verificar

sudo systemctl daemon-reload
sudo systemctl enable --now mybot
systemctl status mybot
sudo systemctl kill --signal=KILL mybot   # simulate a crash; status is active again after 5 s

enable crea el enlace simbólico de arranque y --now inicia la unidad. La línea kill es la prueba de verdad: si systemctl status mybot muestra active (running) unos segundos después, la política de reinicio funciona, y un sudo reboot valida la ruta de arranque. Para verlo junto a todos los demás servicios, lista los servicios en ejecución con systemctl; aparece como mybot.service, y systemctl is-enabled mybot confirma que volverá tras un reinicio.

Alternativa: pm2, y cómo se compara con screen, nohup y Docker

Toda forma de mantener vivo un bot responde a tres preguntas: ¿sobrevive al cierre de sesión SSH, se reinicia tras un fallo y arranca al reiniciar la máquina?

MétodoSobrevive al cierre de SSHSe reinicia tras un falloArranca al reiniciarVeredicto
nohup / &SíNoNoSolo para pruebas rápidas.
screen / tmuxSíNoNo, salvo con un scriptDepuración, no producción.
pm2SíSíSí, tras pm2 startup + pm2 saveBueno para equipos de Node.js; una sola CLI para logs y reinicios.
unidad systemdSíSí (Restart=)Sí (enable)Recomendado; sin software extra y con hardening incluido.
Docker, restart: unless-stoppedSíSíSí, con el demonio de DockerBueno cuando el bot ya se distribuye como imagen.

pm2 es la opción popular en el mundo Node.js y también sirve para Python. Ejecútalo con la cuenta propietaria del bot:

sudo npm install -g pm2
cd /opt/mybot
pm2 start index.js --name mybot
pm2 start bot.py --name mybot --interpreter /opt/mybot/.venv/bin/python   # Python variant
pm2 save
pm2 startup                    # prints a sudo command to run once
pm2 logs mybot
pm2 install pm2-logrotate      # ~/.pm2/logs/ otherwise grows forever

pm2 startup genera una unidad systemd pm2-<user> que resucita al arrancar tu lista de procesos guardada, de modo que pm2 se apoya en systemd en lugar de sustituirlo: ese es el argumento honesto para usar systemd directamente con un solo bot. pm2 se gana su sitio con varios procesos Node o con un equipo que ya lo conoce.

Si prefieres los contenedores, el equivalente es restart: unless-stopped en un archivo Compose; el tutorial para instalar Docker en un VPS Ubuntu cubre el motor, Compose y el comportamiento en el arranque. Su advertencia sobre ufw no afecta a un bot, que no publica ningún puerto.

Logs, actualizaciones y dimensionado de la memoria

Logs

journalctl -u mybot -f                    # follow live
journalctl -u mybot --since "1 hour ago"
journalctl -u mybot -p err -b             # errors since boot
sudo journalctl --vacuum-size=200M        # cap journal size

journald rota y comprime por su cuenta. Si el bot escribe su propio archivo de log, usa logging.handlers.RotatingFileHandler en Python o un transporte rotativo con pino o winston en Node, para que un handler demasiado hablador no llene el disco.

Actualizaciones

cd /opt/mybot
sudo -u bot git pull
sudo -u bot .venv/bin/pip install -U -r requirements.txt   # Node: sudo -u bot npm ci
sudo systemctl restart mybot

Un reinicio corta la conexión con la gateway durante unos segundos; la biblioteca vuelve a conectarse y los usuarios rara vez lo notan. Fija las versiones de las bibliotecas en requirements.txt o package-lock.json y lee el changelog antes de un salto de versión mayor. Mantén el sistema al día con sudo apt update && sudo apt upgrade o con unattended-upgrades.

¿Cuánta RAM necesita el bot?

No dimensiones a partir de cifras genéricas; mide. systemctl status mybot imprime una línea Memory: y pm2 list muestra lo mismo. Un bot de discord.py solo de comandos suele quedarse en decenas de megabytes en reposo; un bot de discord.js carga además el runtime de Node. La memoria crece con el estado: cachés de miembros y mensajes en servidores grandes, voz y música (un proceso ffmpeg por stream), generación de imágenes o una base de datos. En la práctica, 1 GB de RAM hace funcionar con holgura el sistema más un bot pequeño o mediano; los bots con mucha voz o varios bots en una misma máquina justifican 2 GB o más, y por encima de 2.500 servidores Discord exige sharding, lo que multiplica el consumo. Dos redes de seguridad baratas: MemoryMax=512M en la unidad, para que una fuga reinicie el bot en vez de tumbar la máquina, y un pequeño archivo de swap.

Todo esto presupone una máquina Linux con acceso root que se mantiene activa a todas horas. Si aún te falta esa máquina, el VPS para bots de Discord de rdp.monster está en línea unos 10 segundos después de la confirmación del pago, con CPU y RAM dedicadas, acceso root completo, ancho de banda ilimitado (fair-use), sin KYC, con criptomonedas aceptadas, desde $8.99/mes, para que el systemctl enable --now mybot de más arriba sea lo último que escribas antes de ver el bot en verde.

Preguntas frecuentes

¿Puedo alojar un bot de Discord gratis 24/7?

Ya no de forma fiable: los planes gratuitos que mantenían los bots despiertos se han eliminado o ahora se duermen por inactividad.
Heroku retiró los dynos gratuitos en noviembre de 2022, Replit trasladó el modo always-on a los despliegues de pago y Glitch puso fin al alojamiento de aplicaciones en 2025. Los planes web gratuitos que quedan se duermen tras la inactividad, lo que cierra la conexión del bot con la gateway. Ejecutarlo en tu propio PC funciona hasta que el PC se reinicia o se suspende. La opción fiable más barata es un VPS pequeño con alrededor de 1 GB de RAM, donde systemd reinicia el bot tras un fallo o un reinicio y nadie lo suspende por estar inactivo.

¿Necesita un bot de Discord una IP fija o puertos abiertos en el VPS?

No: el bot se conecta hacia fuera a Discord, así que no hace falta abrir ningún puerto entrante y la IP da igual.
Un bot de gateway abre un WebSocket saliente hacia Discord y recibe los eventos por esa misma conexión, así que el firewall del VPS puede quedar cerrado a todo salvo SSH, y la IP del servidor nunca aparece ante los usuarios. Solo necesitas un puerto abierto y un nombre de host público si pasas a los endpoints de interacción HTTP, que Discord llama mediante una URL que tú registras, o si añades un panel web. En ese caso, ponlo detrás de HTTPS con un proxy inverso.

¿Puedo ejecutar varios bots de Discord en un mismo VPS?

Sí, una unidad systemd (o un proceso pm2) por bot, idealmente cada uno con su propio usuario y directorio.
Nada te limita a un bot por máquina. Dale a cada bot su propio directorio, por ejemplo /opt/bot-a y /opt/bot-b, su propio .env con su propio token y su propio archivo de unidad, y luego ejecuta systemctl enable --now en cada uno. Usuarios de sistema separados impiden que un fallo en un bot lea el token del otro. El único presupuesto compartido es la RAM y la CPU: vigila systemctl status en cada unidad y pasa a un plan mayor cuando el total se acerque al límite.

¿Debo alojar un bot de Discord en un VPS Windows o Linux?

Linux es la opción por defecto para los bots: más barato, más ligero y con herramientas (systemd, pm2, Docker) pensadas para él.
Tanto discord.py como discord.js funcionan en Windows, y un VPS Windows es la elección correcta si el bot depende de una aplicación exclusiva de Windows o si simplemente prefieres un escritorio. Para un bot normal gana Linux: el sistema usa una fracción de la RAM, un servidor mínimo apenas tiene superficie de ataque y mantener vivo un proceso es una unidad systemd de diez líneas. En Windows usarías el Programador de tareas o NSSM para lograr el mismo reinicio automático con más clics.

Adrien Roche, Editor de infraestructura y hosting

Ingeniero de sistemas con más de 10 años operando flotas de Windows Server y Linux. Adrien mantiene la documentación de infraestructura de rdp.monster y escribe nuestras guías sobre RDP, hosting VPS, administración de servidores, redes y herramientas de privacidad.

Regístrate en nuestro programa de revendedores

Tus datos

Si tienes alguna pregunta, contáctanos haciendo clic aquí !
Nombre y apellidos(Obligatorio)
Introduce tu correo electrónico; debes tener una cuenta en manager.rdp.monster !

Tu empresa

Introduce la dirección de tu sitio web si tienes uno
Explica brevemente cómo vas a vender los servicios a tus clientes. Por ejemplo, hablando con gente en foros.

¡Usamos cookies!

Utilizamos cookies para mejorar tu experiencia de navegación, mostrar anuncios o contenido personalizados y analizar nuestro tráfico. Al hacer clic en «Aceptar», consientes nuestro uso de cookies.