A Discord bot never waits for incoming connections. It opens a connection to Discord and keeps it alive. That means it doesn't need its own IPv4 address. A NAT VPS, which shares one IPv4 address between customers and gives each server a block of ports, runs a bot just as well as a full VPS for a fraction of the price. Free bot hosts tend to sleep or restart your bot; a small VPS keeps it running and gives you root.
In this guide I use natbox.io's Nano plan ($1/month: 512 MB RAM, 5 GB SSD, 10 ports). Disclosure: I run natbox. The manual steps work on any Debian or Ubuntu server.
1. Create the bot in Discord
- Open the Discord Developer Portal and create a new application.
- Under Bot, reset and copy the token. Treat it like a password.
- If your bot reads message text, turn on Message Content Intent.
- Under OAuth2 → URL Generator, tick
bot, choose permissions, and open the link to invite the bot to your server.
2. Get a server
Order a Nano plan with Debian or Ubuntu. It's ready in under a minute. New customers can use the free one-month trial instead (256 MB RAM, 3 GB SSD, 5 ports, no payment details needed), which is enough for a small bot.
3a. The quick way: one-click Discord bot
natbox has a one-click Discord bot app. It installs a ready Python bot; you paste your bot token in the client area and it stays online 24/7. Use it if you want a running bot in two minutes and plan to edit the code afterwards.
3b. The manual way: your own code
Connect over SSH. Your login and port are in the client area; SSH listens on the first port of your block:
ssh root@natbox.io -p <your-first-port> Install Python and create a project:
apt update && apt install -y python3 python3-venv mkdir -p /opt/bot && cd /opt/bot python3 -m venv venv ./venv/bin/pip install -U discord.py Create /opt/bot/bot.py:
import os, discord from discord.ext import commands intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix="!", intents=intents) @bot.command() async def ping(ctx): await ctx.send("pong") bot.run(os.environ["DISCORD_TOKEN"]) Store the token outside the code:
echo 'DISCORD_TOKEN=paste-your-token-here' > /opt/bot/.env chmod 600 /opt/bot/.env 4. Keep it running with systemd
Create /etc/systemd/system/discord-bot.service:
[Unit] Description=Discord bot After=network-online.target [Service] WorkingDirectory=/opt/bot EnvironmentFile=/opt/bot/.env ExecStart=/opt/bot/venv/bin/python bot.py Restart=always RestartSec=5 [Install] WantedBy=multi-user.target Then start it and enable it at boot:
systemctl daemon-reload systemctl enable --now discord-bot journalctl -u discord-bot -f Type !ping in your server. The bot should answer pong. If it crashes, systemd restarts it within five seconds.
5. Lock it down
Every natbox server gets its own routed /80 of IPv6, which is reachable on every port and isn't filtered. A bot needs no inbound ports, so allow SSH and nothing else:
apt install -y ufw ufw default deny incoming ufw allow <your-ssh-port>/tcp ufw enable Good to know
- Outbound mail on ports 25, 465 and 587 is blocked. If your bot sends email, use an email API over HTTPS.
- Docker isn't supported (servers are LXC containers), so run the bot directly as shown.
- When you outgrow Nano, upgrade in place from the client area. Your data, IPs and ports stay the same.
