A Discord bot on your laptop dies the moment you close the lid. Fine for testing — useless for a bot your server actually depends on. Move it to a VPS and it stays online: it survives your wifi dropping, doesn't stop when you sleep, and reconnects to Discord on its own.
Here's the whole thing — a minimal bot, a service that keeps it alive, and how to pay without handing over an ID.
Why a VPS, not your laptop
A Discord bot needs a stable, always-on connection to Discord's gateway. A laptop sleeps, reboots for updates, and changes networks — every time, the bot drops offline and members notice. A VPS holds one steady connection around the clock. That's the entire reason people move bots off personal machines.
What size — and how you pay
A Discord bot is light. It holds a websocket and reacts to events, so the box mostly waits:
- 1 GB RAM, 1–2 cores covers most bots — even fairly busy ones.
- Scale up only if the bot does the heavy lifting itself: image generation, a local model, audio for many servers, a big database.
Two practical calls:
- NAT is enough. The bot only makes outbound connections to Discord, so a NAT plan with port-forwarded SSH works — no dedicated IP, no open inbound ports. Add a public IP only if you also run a web dashboard or receive webhooks.
- No-KYC, paid in crypto. Sign up with an email and pay in USDC or USDT on Base or Ethereum — no card, no documents. A card works too, but the on-ramp has a ~$27 minimum, so topping up a small balance once is smoother for a cheap plan.
It's CPU-only and runs from a single datacenter in Germany — perfectly fine for a bot, worth knowing if you need a GPU or a specific region.
A minimal bot
SSH in, install Python, and drop in a small discord.py bot:
sudo apt update && sudo apt install -y python3-venv
mkdir ~/bot && cd ~/bot
python3 -m venv venv && source venv/bin/activate
pip install -U discord.py
# bot.py
import os, discord
intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)
@client.event
async def on_ready():
print(f"online as {client.user}")
@client.event
async def on_message(m):
if m.author == client.user:
return
if m.content == "!ping":
await m.channel.send("pong")
client.run(os.environ["DISCORD_TOKEN"])
Get the token from the Discord Developer Portal (your application → Bot → Reset Token), and enable the Message Content intent there if your bot reads messages.
Keep it alive with systemd
Running python bot.py in your SSH session means the bot dies when you disconnect. A systemd service fixes that — it restarts on crashes and survives reboots:
# /etc/systemd/system/discordbot.service
[Unit]
Description=Discord bot
After=network-online.target
[Service]
User=botuser
WorkingDirectory=/home/botuser/bot
Environment=DISCORD_TOKEN=your-token-here
ExecStart=/home/botuser/bot/venv/bin/python bot.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now discordbot
sudo journalctl -u discordbot -f # watch the logs
That's the difference between "a script I run" and "a bot that runs itself."
Honest caveats
- Guard the token. Keep it in the service file (root-only) or an env var, run as a non-root
botuser, never commit it. If it leaks, reset it in the Developer Portal immediately. - Voice is heavier. A music/voice bot streaming to many servers needs more CPU and bandwidth than a text bot — size up and test before you scale.
- Watch what the bot does, not just hosts. The hosting is cheap; if your bot calls paid APIs in a loop, that's where cost shows up.
Within that, a Discord bot on its own server just stays up — which is the whole point. Pick a plan, pay in crypto, and have it online in minutes. If you also run other bots, the same systemd pattern keeps any process alive.