DEV Community

Antonin Courtadon
Antonin Courtadon

Posted on Fully Autonomous

Host a discord.py or discord.js Bot on a Free Host, Step by Step

Disclosure: I'm Antonin Courtadon, founder of ACLClouds.

This guide takes a minimal bot from your computer to a hosted process. You will write a bot that answers !ping with "pong" (discord.py or discord.js), upload it, start it and check the logs. Once that works, you can replace the code with your own.

You need:

  • a Discord account and a server where you have administrator rights;
  • Python 3.10+ or Node.js 18+ on your computer for a quick local test;
  • a free bot slot on a hosting platform (we use ACLClouds in the examples, but the steps are similar elsewhere).

Step 1: Create the bot in the Discord Developer Portal

  1. Open the Discord Developer Portal and create a new application.
  2. Go to the Bot section and create the bot user.
  3. Click Reset Token and copy the token. Treat it like a password. Do not paste it into code, a repository, a screenshot or a chat.
  4. In the same section, enable Message Content Intent under Privileged Gateway Intents. Without it, your bot receives messages with an empty content field, which breaks prefix commands.
  5. Go to OAuth2 → URL Generator, select the bot scope and the permissions you need (at minimum Send Messages and Read Message History for this test). Open the generated URL and add the bot to your test server.

Step 2: Write the bot

discord.py (Python)

Create a folder with two files: bot.py and requirements.txt.

bot.py:

import os
import discord

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

client = discord.Client(intents=intents)


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


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


client.run(os.environ["DISCORD_TOKEN"])
Enter fullscreen mode Exit fullscreen mode

requirements.txt:

discord.py>=2.3,<3
Enter fullscreen mode Exit fullscreen mode

discord.js (Node.js)

Create a folder with index.js and package.json.

index.js:

const { Client, GatewayIntentBits } = require('discord.js');

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

client.once('ready', () => {
  console.log(`Connected as ${client.user.tag}`);
});

client.on('messageCreate', (message) => {
  if (message.author.bot) return;
  if (message.content.trim() === '!ping') {
    message.reply('pong');
  }
});

client.login(process.env.DISCORD_TOKEN);
Enter fullscreen mode Exit fullscreen mode

package.json:

{
  "name": "ping-bot",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "discord.js": "^14.16.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Two details matter in both versions. The token is read from an environment variable, never written in the file. And the message content intent is requested in the code and must also be enabled in the portal, or Discord refuses the connection with an error about privileged intents.

Step 3: Test on your computer

Before you upload anything, check that the bot connects. On Windows, Linux or macOS, the variable syntax differs slightly. On Linux or macOS:

export DISCORD_TOKEN="paste-your-token-here"
python bot.py        # discord.py
# or
npm install && npm start   # discord.js
Enter fullscreen mode Exit fullscreen mode

When you see Connected as ... in the terminal, type !ping in the test server. If the bot answers "pong", the code works. Stop it with Ctrl+C.

If the bot does not answer, check these in order:

  1. The bot is in the server and has Send Messages in that channel.
  2. Message Content Intent is enabled in the portal.
  3. The token is current. If you reset it, the old one stops working.

Step 4: Upload the bot to the free host

Every hosting panel has its own screens, but the logic is the same: create a bot, upload the files, set the token, choose the start file, start the bot.

On ACLClouds, the flow looks like this:

  1. Create a bot from the dashboard. The free plan gives you one bot slot.
  2. Upload your files. Use the panel upload, or connect with SFTP. Each bot has its own SFTP access on port 2222, with a username of bot- followed by 8 characters, shown on the bot page.
  3. Paste the Discord token into the Discord token card. The panel refuses a value that looks like a variable name, which catches a common mistake: pasting the text DISCORD_TOKEN where the token itself should go.
  4. Check the start file. The panel tries to detect bot.py or index.js automatically. If it finds the wrong file or none, set it yourself.
  5. Start the bot and open the logs tab.

Upload only your source and a dependency list. Do not upload node_modules, a virtual environment or your .env file. The free plan allows uploads up to 100 MB and 715 MB of storage, so smaller is safer.

Step 5: Read the logs

The first start is where most problems appear. What you should see:

  • Connected as YourBot#1234 (or the new username format) in the logs;
  • no repeated error lines;
  • the bot shows as online in your server.

Common errors and what they mean:

Log message Likely cause Fix
PrivilegedIntentsRequired / intents error Message Content Intent is off in the portal Enable it, then restart
Improper token has been passed / LoginFailure Token is wrong, reset, or has spaces Copy the token again into the token card
ModuleNotFoundError: No module named 'discord' Dependencies not installed Check requirements.txt is uploaded and installed by the start process
Cannot find module 'discord.js' node_modules missing Check package.json is uploaded and dependencies install
Bot restarts in a loop Exception at startup Read the first traceback line, not the last one

Step 6: Keep it running

Free slots expire. Note the date the bot was started and renew from the bot page within the window the platform allows (on ACLClouds, within 2 days before expiry, or once the bot is suspended). A bot that is not renewed stops, even if the code is correct.

Also keep your code outside the host. A Git repository, even private, lets you redeploy in a minute if something goes wrong.

Comparison: what to check on the host

What to check Why ACLClouds free bot plan
Token handling Pasting it in code leaks it Discord token card per bot
Log access You need the traceback Logs and console per bot
File access Quick fixes without redeploying SFTP on port 2222
Runtimes Your library and its tools must be present Node.js and Python images include ffmpeg, yt-dlp and deno
RAM Bots grow in memory over time 315 MB
Renewal Expiry stops the bot 4 days, renewable from the bot page

Limits of this setup

  • This is a minimal example. A real bot needs error handling, rate-limit awareness and a way to store data (a file or a database) that survives restarts.
  • The free plan's 315 MB RAM is enough for the code above and for a modest command set. It is not a reason to cache everything.
  • Do not run a bot on a host you do not trust with your token. If a host asks you to paste your token in a chat or an email, do not.

Frequently asked questions

Do I need to know Python or JavaScript to host a bot?
You need to be able to edit one file and read a traceback. The examples above are the whole program for a ping bot, so you can copy them and change the command.

Why does !ping not work when the bot is online?
Check Message Content Intent first. The bot can be online and still receive empty message text.

Should I use discord.py or discord.js?
Use the language you already know. Both are maintained and both work well on small hosts. Choose based on your team and the libraries you need, not on the hosting.

Where do I put the token?
In the token card on the bot page, not in your code. Your code reads it from the environment variable the platform provides, or from a local .env file that you never upload.

What if my bot needs ffmpeg or yt-dlp?
The ACLClouds Node.js and Python images include ffmpeg, yt-dlp and deno. Check the image you chose before you add a dependency that calls them.

Next steps

Once your ping bot answers, add one command at a time, and check RAM and logs after each change. The free bot plan page is at https://aclclouds.com/en/ and the French version at https://aclclouds.com/fr/.


Antonin Courtadon, founder of ACLClouds · https://aclclouds.com

Top comments (0)