Host a Discord bot on a Linux VPS by deploying a working application, installing its supported runtime and running it under an unprivileged service account. Use a process supervisor so it survives your SSH logout and restarts after failure. Keep its token separate from source code and verify real bot functionality rather than relying only on a running process.
Prerequisites and application model
This guide deploys an existing Node.js bot with a tested entry point and lockfile on a systemd-based VPS. It does not invent a bot token or configure your Discord application for you. Follow the application’s SDK/runtime requirements and Discord’s official setup for installation scopes, permissions and required intents.
A Gateway bot normally establishes outbound connections to Discord. An application receiving HTTP interactions needs a reachable HTTPS endpoint and request-signature verification instead. Determine which design your code uses before opening ports; a bot process does not automatically need a public inbound listener.
1. Prepare a repeatable application release
- Create a dedicated unprivileged service account, such as discordbot, using the distribution’s account tools.
- Install the application’s supported Node runtime and verify its absolute executable path. An interactive shell version manager may not exist in the service environment.
- Place a reviewed release under /opt/discord-bot/current, owned so the service can read code but cannot modify unrelated files.
- Install the locked dependencies as an unprivileged deployment user. Run any build step with its required dependencies before producing the production release.
- Keep persistent state in a separate writable location and document its backup method.
2. Supply the token without committing it
Prefer the application’s supported secret mechanism. For software that reads a token file, systemd credentials can supply one without putting it in the unit’s command line. The example below assumes your application reads DISCORD_TOKEN_FILE; adapt the code deliberately if it expects a different interface. Keep the source secret file root-owned and accessible only to the service manager.
# /etc/systemd/system/discord-bot.service
[Unit]
Description=Community Discord bot
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
User=discordbot
Group=discordbot
WorkingDirectory=/opt/discord-bot/current
ExecStart=/usr/bin/node /opt/discord-bot/current/index.js
LoadCredential=bot-token:/etc/discord-bot/token
Environment=DISCORD_TOKEN_FILE=%d/bot-token
Restart=on-failure
RestartSec=10
NoNewPrivileges=true
PrivateTmp=true
UMask=0077
[Install]
WantedBy=multi-user.targetCreate the named account, group, application files and protected token file before activation. Substitute the real Node path and entry point. On a systemd release without the required credential support, use that release’s documented secret-delivery mechanism rather than silently dropping the protection. Never print the token to logs.
3. Validate and start the service
sudo systemd-analyze verify /etc/systemd/system/discord-bot.service
sudo systemctl daemon-reload
sudo systemctl enable --now discord-bot
sudo systemctl status discord-bot
sudo journalctl -u discord-bot -n 50 --no-pagerContinue only after validation succeeds. Check the application’s ready/connection event, then exercise a harmless authorized action in a test server. Test a normal user’s permissions as well as an administrator’s. A process can remain active while its token, intents, registration or external connection is wrong.
4. Keep updates and failures controlled
| Symptom | Check |
|---|---|
| Executable not found | Absolute runtime path and service environment |
| Token rejected | Correct application token, file access and whether it was rotated |
| Connected but missing events | Requested and enabled intents, installation and permissions |
| Duplicate replies or actions | An old process or second deployment running concurrently |
| Restart loop | First application error; rate limits and dependency/runtime mismatch |
Use one supervisor, retain the previous release and back up persistent data before schema changes. Monitor failures and restart loops without sending secrets in alerts. If a token leaks, rotate it in the official portal and update the protected source; deleting it from the repository’s latest revision is not sufficient.
Use VPS security and monitoring for the host. Compare VPS plans using the bot’s actual workload, including databases and any media processing rather than assuming all bots have the same requirements.
Sources and references
Hosting documentation. Publication and update dates reflect this edition.
Related articles
- First Steps on an Ubuntu or Debian VPSVerify identity and recovery access, prepare a named administrator, update deliberately and establish monitoring before deploying applications.3 min read
- How to Secure a Linux VPS Without Locking Yourself OutEstablish console recovery and a verified SSH key login before tightening authentication and firewall rules on Ubuntu or Debian.5 min read
- VPS Monitoring: CPU, Memory, Disk and Useful AlertsConnect operating-system metrics to application symptoms and test the alert path before relying on it during an outage.3 min read
