How to Deploy a Discord Bot on a Cloud Server
Discord bots are everywhere on the platform: they assign roles to newcomers, ban spammers, play music in voice channels, and answer questions using AI. Writing a bot is only half the job. The other half is getting it to run continuously — not just while your laptop is open.
The most common approach is to move the bot to a VPS. The server runs 24/7, is independent of your home internet connection, doesn't reboot unexpectedly, and never goes to sleep. This article covers the entire process: from choosing a server to setting up automatic restarts on failure. Examples are provided for both Python and Node.js, step by step, with real commands.
Why Your Home Computer Isn't Suitable for Production
When you're writing a bot for the first time, running it directly on your machine is the fastest way to test that everything works. But for a bot serving a real Discord server, this is a poor long-term solution.
Home environments are unpredictable: your ISP can drop the connection for hours, the computer goes to sleep, Windows installs updates and reboots. Home IP addresses are usually dynamic — they change, and if the bot relies on whitelists or webhook notifications, that creates additional headaches. On top of that, the bot constantly consumes resources on your machine.
A VPS solves all of these problems at once. Fixed IP address, guaranteed uptime, and an isolated environment where the bot runs on its own — completely independent of your schedule.
The Basics: VPS, SSH, and Process Manager
What Is a VPS
A VPS (Virtual Private Server) is a virtual machine running on a physical server in a data center. You get dedicated resources: CPU, RAM, and disk space. You manage it via SSH — a secure remote command-line connection. For Linux servers, it's the primary tool for all operations.
What Is SSH
SSH (Secure Shell) is a protocol for connecting to a server remotely. Through it, you type commands as if you were sitting right at that machine, even though it may be physically located in a data center in another city. On macOS and Linux, SSH is built in; on Windows it's available in PowerShell and through the PuTTY application.
Why You Need a Process Manager
If you simply run the bot from a terminal prompt, it will stop as soon as you close the SSH session. A process manager — systemd, PM2, or supervisor — launches the bot as a background service, restarts it on failure, and brings it back up automatically after a server reboot.
Minimum Server Requirements
A Discord bot without voice features consumes very few resources. A typical Python bot with a few dozen commands uses around 50–150 MB of RAM. A voice bot or one running local ML models is a different story.
| Bot Type | RAM | CPU | Disk |
|---|---|---|---|
| Text commands, moderation | 512 MB | 1 core | 10 GB |
| API integrations, database | 1 GB | 1–2 cores | 20 GB |
| Music bot (voice channels) | 2 GB | 2 cores | 20 GB |
| Bot with a local ML model | 4+ GB | 2–4 cores | 40+ GB |
For most projects, a starter plan with 1 GB of RAM is enough. On a Serverspace VPS, that configuration is sufficient to run several small bots simultaneously. Resources can be scaled through the control panel at any time without reinstalling the operating system.
Step 1. First Connection and System Setup
After creating a VPS, you receive an IP address and a root password (or an SSH key, if you chose that option). Connect to the server:
ssh root@your_ip_address
The first thing to do is update the packages. This matters: a freshly installed system often ships with outdated software containing known vulnerabilities.
apt update && apt upgrade -y
Running everything as root permanently is poor practice. It's better to create a dedicated user for the bot with limited privileges:
adduser botuser
usermod -aG sudo botuser
su - botuser
From this point on, all operations run under the botuser account, with sudo used only for administrative tasks. This reduces risk: even if a vulnerability exists in the bot, an attacker won't have root-level access to the entire system.
Step 2. Installing the Runtime
Python
On Ubuntu 22.04, Python 3 comes pre-installed. Check the version and install pip along with the virtual environment module:
python3 --version
sudo apt install python3-pip python3-venv -y
Node.js
For Node.js, it's recommended to install the latest LTS version using the official NodeSource script — the version in Ubuntu's default repositories is usually outdated:
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node --version && npm --version
Step 3. Uploading Your Bot's Code to the Server
The most convenient method is Git. If the project is hosted on GitHub or GitLab, install git and clone the repository:
sudo apt install git -y
git clone https://github.com/your_username/your_bot.git
cd your_bot
If you don't have a repository and need to copy files from your local machine, use scp — it works over the same SSH connection:
scp -r /local/path/to/bot botuser@your_ip:/home/botuser/bot
After transferring, verify that everything is in place: the main file (main.py or index.js), the dependency file (requirements.txt or package.json), and any folders containing commands and config files.
Step 4. Setting Up Environment Variables
Your Discord bot token is sensitive data. Hard-coding it directly in the source is a mistake: the moment the code is pushed to GitHub, the token is exposed to everyone. The correct approach is to store the token and other secrets in a .env file.
Create the file in the bot's directory:
nano .env
Example contents:
DISCORD_TOKEN=your_token_here
PREFIX=!
DATABASE_URL=sqlite:///bot.db
Add .env to your .gitignore — this file must never end up in the repository. To load environment variables in a Python bot, use the python-dotenv library:
from dotenv import load_dotenv
import os
load_dotenv()
TOKEN = os.getenv("DISCORD_TOKEN")
For Node.js, use the dotenv package — it connects with a single line at the top of the main file: require('dotenv').config().
Step 5. Installing Dependencies
Python — Virtual Environment
A virtual environment isolates the project's packages from the system-level Python installation. This is important if the server hosts several bots or Python applications with different library version requirements.
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
Once activated, (venv) appears at the beginning of the terminal prompt — all subsequent pip commands operate inside the isolated environment.
Node.js
npm install
Step 6. Test Run
Before configuring autostart, make sure the bot launches without errors:
# Python (inside the activated venv)
python3 main.py
# Node.js
node index.js
If a connection message from Discord appears in the console, everything is working. Quickly test a couple of commands in chat. If something goes wrong, errors will be visible right in the terminal. To stop the process: Ctrl + C.
Worth noting: while the bot is running directly from the terminal, it will stop when the SSH session is closed. Persistent operation requires the next step.
Step 7. Autostart with systemd
systemd is the standard service manager in Ubuntu and most other Linux distributions. It starts processes at system boot, restarts them on failure, and keeps a log. For a Discord bot on a VPS, this is the optimal approach.
Create a unit file for the service:
sudo nano /etc/systemd/system/discord-bot.service
Contents for a Python bot:
[Unit]
Description=Discord Bot
After=network.target
[Service]
Type=simple
User=botuser
WorkingDirectory=/home/botuser/bot
ExecStart=/home/botuser/bot/venv/bin/python main.py
Restart=on-failure
RestartSec=5
EnvironmentFile=/home/botuser/bot/.env
[Install]
WantedBy=multi-user.target
For Node.js, the ExecStart line looks different:
ExecStart=/usr/bin/node /home/botuser/bot/index.js
A few notes on the config. After=network.target means the bot will only start after the network is initialized — critical for connecting to Discord. Restart=on-failure restarts the process on a crash, but not on a clean shutdown. EnvironmentFile loads variables from the .env file.
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable discord-bot
sudo systemctl start discord-bot
Check the status:
sudo systemctl status discord-bot
The line Active: active (running) confirms the service is running. The bot will now start automatically after any server reboot and recover on failure.
Alternative: PM2 for Node.js
PM2 is a popular process manager in the Node.js ecosystem. It's slightly easier to set up initially, offers convenient terminal-based monitoring, and manages multiple applications as a single workspace.
npm install -g pm2
pm2 start index.js --name "discord-bot"
pm2 startup
pm2 save
The pm2 startup command generates a command to create a systemd entry, which you'll need to run. pm2 save saves the current process list — exactly what PM2 will restore after a reboot.
To view live logs:
pm2 logs discord-bot
For Python bots, native systemd is more practical. If your entire stack is Node.js, PM2 gives you more monitoring tools in one place.
Viewing Logs and Diagnosing Issues
When the bot runs as a systemd service, logs are read through journalctl:
sudo journalctl -u discord-bot -f
The -f flag enables live streaming mode. To view the last 100 lines without a live feed:
sudo journalctl -u discord-bot -n 100
If the bot has its own file-based logging configured, look for a log file in the working directory. For Python bots this is often bot.log or a logs/ folder.
Updating the Bot
When you need to deploy a new version of the code, the process is straightforward. If you use Git:
cd /home/botuser/bot
git pull origin main
source venv/bin/activate # Python only
pip install -r requirements.txt # if dependencies changed
sudo systemctl restart discord-bot
A restart takes a few seconds. For most bots this is perfectly fine — users barely notice the brief reconnect. If you want to minimize downtime, implement graceful shutdown in the bot itself: finish any in-progress tasks before exiting.
Server and Bot Security
Deploying a bot and leaving the server in its default configuration creates unnecessary exposure. A few measures worth taking right after the initial deployment.
Disable password login for root and set up SSH keys. Automated scanners start brute-forcing passwords within minutes of a new IP appearing online. An SSH key is more secure than any password.
Set up UFW — Ubuntu's built-in firewall:
sudo ufw allow OpenSSH
sudo ufw enable
sudo ufw status
By default, UFW blocks all incoming connections except those explicitly allowed. If the bot needs a web server for webhook requests, add the required port separately.
Store the bot token only in the .env file. If the token ever ends up in a public repository, reset it immediately in the Discord Developer Portal. Regeneration takes a second; the consequences of a leaked token can be significant — anyone who has it gains full control over the bot.
On the Discord side: don't give the bot administrator permissions on a server unless the functionality genuinely requires it. Minimal permissions mean minimal damage if something goes wrong.
Practical Use Cases
Let's look at what tasks a Discord bot running on a permanently available server can actually handle.
Moderating a large community. The bot automatically assigns roles on join, filters banned words, issues warnings, and maintains a violation log. All of this requires uninterrupted operation — any downtime means an unmonitored window of activity in the channel.
Automated notifications. The bot monitors an RSS feed, checks GitHub Actions statuses, or tracks new releases on PyPI — then posts announcements to the appropriate channel. This kind of logic relies on a task scheduler (APScheduler for Python or node-cron for Node.js) and simply won't work reliably on a machine that gets turned off periodically.
Game features with a database. The bot stores scores, reputation, and character inventories. SQLite works well for smaller servers; PostgreSQL handles heavier loads. The database lives on the same VPS alongside the bot, which simplifies backups and migrations.
Voice bot. Plays music in voice channels. This requires ffmpeg and yt-dlp installed on the server, a stable connection, and a reasonably powerful CPU. A plan with 2 GB of RAM is recommended — encoding an audio stream in real time takes resources.
AI integrations. The bot answers questions via the OpenAI API, generates images, or summarizes text. When using an external API, a base VPS configuration is sufficient. If a model runs locally, you'll need a server with several gigabytes of RAM and a capable CPU.
Common Mistakes and How to Avoid Them
| Problem | Cause | Solution |
|---|---|---|
| Bot stops when SSH session closes | Process is tied to the terminal session | Configure a systemd service or use PM2 |
| Token exposed in repository | Hardcoded in the source or missing .gitignore | Reset the token in Developer Portal; move it to .env |
| ModuleNotFoundError when the service starts | ExecStart points to system Python instead of venv | Use the full path to venv/bin/python in the unit file |
| Bot can't read environment variables | EnvironmentFile not specified in [Service] section | Add EnvironmentFile=/path/.env to the service file |
| Slash commands don't update after deploy | Discord caches global commands for up to 1 hour | Use guild_id during development — updates are instant |
| Memory grows and bot crashes every few days | Memory leak or unbounded cache in code | Set Restart=always in systemd and review caching logic |
Conclusion
Deploying a Discord bot to a cloud server takes a few hours on the first run and just a few minutes for every update after that. The key steps are: create a user on the VPS, install the runtime, upload the code, move secrets to a .env file, and configure a systemd service with autostart.
Once that's done, the bot runs independently of your personal machine, restarts automatically on failure, and stays available to users around the clock. A minimal configuration is enough to get started — a VPS from Serverspace can be scaled up as load grows, directly from the control panel.
Frequently Asked Questions
Yes. Each bot runs as a separate systemd service with its own unit file and .env. Resources are shared across all processes, so when running several bots, choose a plan with enough RAM to spare.
No. The bot connects to Discord's servers via an outbound WebSocket connection — a static IP isn't needed for that. You'll only need one if you're exposing a web interface or accepting incoming webhook requests.
Check the logs: sudo journalctl -u discord-bot -n 50. There will be a detailed traceback. Common causes include: an invalid token, a missing dependency, insufficient permissions on the database file, or a syntax error introduced during a recent update.
Ubuntu 22.04 LTS is the most common choice: large community, up-to-date packages, and support through 2027. Debian and Rocky Linux are solid alternatives — the difference for bot deployment purposes is minimal.
That's exactly what a VPS is for. The server operates independently of your device — 24 hours a day, 7 days a week. There's no need to keep your own computer on to keep the bot alive.