RE:NODE

Host a Discord or Telegram bot on Renode

Run a Discord or Telegram bot on a RE:NODE Node.js or Python server: the start script or entry file, keeping the token out of git, surviving restarts, and why a bot needs no port.

All docs pages

A bot runs on a Node.js or Python server, and starts exactly the way those pages describe: a start script or entry file on Node.js, the entry file on the Startup tab on Python. What is different about a bot is what it does not need, and what it must not do.

What is different about a bot#

  • It needs no inbound port. A Discord bot and a Telegram bot using long polling both connect *out* to the provider. Nothing has to reach the server, so there is nothing to bind. (A Telegram bot using webhooks is a web app: it must listen on SERVER_PORT and needs an HTTPS address - see Custom domains.)
  • The token is a secret. Read it from the environment - a .env uploaded through the Files tab, or a Startup tab variable. Never commit it and never log it. A token pushed to a public repository is usually found and abused within minutes.
  • It will be restarted. A push with restart on push on restarts it; so does any other restart. Handle reconnects, and keep anything you need across restarts in files under /home/container or in a database, not in memory.

A Discord bot in Node.js#

package.json
{  "name": "my-bot",  "private": true,  "scripts": { "start": "node bot.js" },  "dependencies": {    "discord.js": "^14.16.0",    "dotenv": "^16.4.0"  }}
bot.js
require("dotenv").config();const { Client, Events, GatewayIntentBits } = require("discord.js");const token = process.env.DISCORD_TOKEN;if (!token) {  console.error("DISCORD_TOKEN is not set - upload .env through the Files tab");  process.exit(1);}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.content === "!ping") message.reply("pong");});client.login(token);
.env (uploaded through the Files tab, never committed)
DISCORD_TOKEN=your-token-here

A Discord bot in Python#

requirements.txt
discord.py==2.4.0python-dotenv==1.0.1
bot.py
import osimport discordfrom dotenv import load_dotenvload_dotenv()intents = discord.Intents.default()intents.message_content = Trueclient = discord.Client(intents=intents)@client.eventasync def on_ready():    print(f"Logged in as {client.user}", flush=True)@client.eventasync def on_message(message):    if message.content == "!ping":        await message.reply("pong")client.run(os.environ["DISCORD_TOKEN"])

Set the entry file on the Startup tab to bot.py if the panel did not pick it already.

A Telegram bot in Python#

Long polling needs no port and no domain:

requirements.txt
python-telegram-bot==21.6python-dotenv==1.0.1
main.py
import osfrom dotenv import load_dotenvfrom telegram import Updatefrom telegram.ext import Application, CommandHandler, ContextTypesload_dotenv()async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):    await update.message.reply_text("Hello from Renode")app = Application.builder().token(os.environ["TELEGRAM_TOKEN"]).build()app.add_handler(CommandHandler("start", start))app.run_polling()

Checklist#

  • The bot starts from a start script (Node.js) or the entry file on the Startup tab (Python).
  • The token is read from the environment, is not committed and is never printed.
  • .env is in .gitignore, and uploaded through the Files tab.
  • State that must survive a restart is in files under /home/container or in a database.
  • The bot reconnects on its own after a disconnect.

Common errors#

The console shows the bot logging in, then nothing happens. The process is alive. Check the provider's side before the code: on Discord, the privileged intents (Message Content, Server Members) must be switched on in the Developer Portal for the bot to receive those events.

`DISCORD_TOKEN is not set`, or an invalid token error. The .env was not uploaded, is not in /home/container, or has a stray space or quote around the value.

The bot replies twice. Two copies are running - for example the same token on your own computer and on the server. Stop one.

It forgets everything after a restart. State was kept in memory. Write it to a file or a database.

Questions this does not answer? Open a ticket from the panel, or start from the overview. These pages are also available as plain text for AI assistants at /llms.txt.