TutorialsAugust 4, 20264 min read

How to Host a Python Discord Bot on a Linux VPS

Deploy a discord.py bot on a Linux VPS the right way: virtualenv, dependencies, a .env token, and a systemd service that restarts on crash and boot.

NBy Nxeon

A Python (discord.py) bot deserves a clean, reliable home. This guide deploys one on a Linux VPS with a virtual environment, a safely-stored token, and a systemd service so it restarts on crash and starts on boot. For the big-picture overview across languages, see how to host a Discord bot on a VPS 24/7.

Step 1: Prepare the server

Connect over SSH, create a non-root user, and update:

sudo adduser bot
su - bot
sudo apt update && sudo apt upgrade -y
sudo apt install -y python3 python3-venv python3-pip git

Harden the box first with securing your first Linux VPS: 10 steps.

Step 2: Get your code and create a virtualenv

A virtual environment isolates your bot's dependencies from the system Python:

git clone https://github.com/yourname/your-bot.git
cd your-bot
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt   # or: pip install discord.py python-dotenv
The Nxeon game-server control panel — live console, player slots, and TPS
The Nxeon game-server control panel — live console, player slots, and TPS

Step 3: Store the token in .env

Keep secrets out of your code. Create a .env file and read it with python-dotenv:

echo "DISCORD_TOKEN=your-bot-token-here" > .env
chmod 600 .env

A minimal bot.py that reads it:

import os
import discord
from dotenv import load_dotenv

load_dotenv()

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

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

client.run(os.environ["DISCORD_TOKEN"])

Test it once by hand: python bot.py. Confirm it comes online in your server, then stop it with Ctrl+C.

Step 4: Create a systemd service

systemd is the cleanest way to run a Python bot 24/7. Create /etc/systemd/system/discordbot.service:

[Unit]
Description=Python Discord Bot
After=network.target

[Service]
Type=simple
User=bot
WorkingDirectory=/home/bot/your-bot
ExecStart=/home/bot/your-bot/venv/bin/python /home/bot/your-bot/bot.py
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

Note ExecStart uses the virtualenv's Python directly — no need to "activate" it. Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable --now discordbot
sudo systemctl status discordbot

Step 5: Logs and updates

View logs with journalctl:

sudo journalctl -u discordbot -f

Deploy a code change:

cd ~/your-bot
git pull
source venv/bin/activate
pip install -r requirements.txt
sudo systemctl restart discordbot

systemd vs PM2 for Python

systemd needs no extra tooling and integrates with journald logging, which makes it a natural fit for Python bots. If you prefer PM2's dashboard and log tailing, you can run pm2 start bot.py --interpreter venv/bin/python instead — see how to keep a Discord bot online with PM2. Prefer containers? See how to deploy a Discord bot with Docker.

Pinning dependencies and Python versions

Pin your dependencies so a deploy can't pull in a breaking library update. Freeze them once locally and commit the file:

pip freeze > requirements.txt

On the server, always install from it inside the virtualenv. If your bot needs a newer Python than the distro ships, install one with deadsnakes or pyenv, create the venv from it, and point systemd's ExecStart at that venv's python.

Slash commands with discord.py

Modern discord.py supports application (slash) commands via app_commands. Sync them once after changes:

@client.event
async def on_ready():
    await tree.sync()
    print("Commands synced")

Global sync can take up to an hour to appear; guild-scoped sync is instant for testing.

Troubleshooting

  • Bot logs in but ignores commands: enable the intents you need (Message Content for prefix commands) in code and the Developer Portal.
  • "ModuleNotFoundError" under systemd: ExecStart isn't pointing at the virtualenv's Python — use the full venv/bin/python path.
  • Bot dies on deploy: a library upgraded; reinstall from your pinned requirements.txt and restart.

FAQ

Why use a virtualenv?

It isolates your bot's packages from the system Python, so upgrades or other apps can't break your dependencies. Point systemd's ExecStart at venv/bin/python.

How do I keep the bot running after logout?

Run it as a systemd service (or under PM2). Both detach it from your SSH session and restart it on crash and on boot.

Where are my bot's logs?

With systemd, use journalctl -u discordbot -f. Add print() or Python logging calls and they'll appear there.

My bot needs message content — why does it get empty messages?

Enable the Message Content intent in the Discord Developer Portal and in code (intents.message_content = True), or the bot receives empty message bodies.

Give your Python bot a permanent home on Discord bot hosting from Nxeon — NVMe VPS, full root access, and Python pre-installed on our Linux images.

#discord bot#python#discord.py#systemd#vps#seobatch

Deploy your first server in under a minute

Creating an account is free and takes no card details. You pay when you deploy — choose a billing term and pay from your wallet or by card at checkout.