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

  1. Open the Discord Developer Portal and create a new application.
  2. Under Bot, reset and copy the token. Treat it like a password.
  3. If your bot reads message text, turn on Message Content Intent.
  4. 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.