Startseite » Blog » Discord-Bot auf einem VPS hosten: 24/7 online bleiben
Discord-Bot auf einem VPS hosten: 24/7 online bleiben
- 18. Oktober 2026
- 09:00
- Von Adrien Roche
- Tutorials

Warum Discord-Bots ausgerechnet auf einem VPS online bleiben
Ein Discord-Bot ist keine Webseite. Nach dem Login hält er eine dauerhafte WebSocket-Verbindung zum Gateway von Discord und muss fortlaufend Heartbeats beantworten; sobald der Prozess stoppt, erscheint der Bot offline und jeder Befehl schlägt fehl. Diese eine Anforderung – ein Prozess, der nie schläft – schließt die meisten „kostenlosen“ Hostings aus:
- Heroku hat seine kostenlosen Dynos im November 2022 abgeschafft.
- Replit hält kostenlose Projekte nicht mehr am Laufen; Always-on gibt es nur noch in kostenpflichtigen Deployments.
- Glitch hat sein App-Hosting 2025 eingestellt.
- Kostenlose Web-Tarife, die bei Inaktivität einschlafen, trennen jedes Mal die Gateway-Verbindung; für die Nutzer ist der Bot damit schlicht offline.
Discord-Bot-Hosting auf einem VPS behebt das an der Wurzel: eine Linux-Maschine mit Root-Zugriff, die rund um die Uhr läuft und auf der der Bot einfach ein weiterer vom Init-System verwalteter Dienst ist. Diese Anleitung baut das auf Ubuntu 24.04 auf (gilt auch für 22.04 und Debian 12), mit discord.py und discord.js, und behandelt danach Token-Handhabung, Neustarts, Logs, Updates und Speicher.
Den VPS vorbereiten: ein eigener Benutzer und eine Laufzeitumgebung
Zuerst die Haustür sichern: SSH unter Ubuntu aktivieren und härten – mit Schlüsselauthentifizierung, ohne Root-Login und mit ufw. Ein Bot baut die Verbindung zu Discord selbst auf und braucht keine eingehenden Ports, die Firewall kann also außer SSH alles blockieren.
Schritt 1: ein unprivilegiertes Konto für den Bot anlegen
sudo useradd -r -m -d /opt/mybot -s /usr/sbin/nologin bot
Ein eigenes Konto sorgt dafür, dass ein fehlerhafter Bot oder eine kompromittierte npm- oder PyPI-Abhängigkeit weder Ihre SSH-Schlüssel lesen noch andere Dienste anfassen kann. Alles liegt in /opt/mybot und gehört dem Benutzer bot.
Schritt 2 (Python): discord.py in einer virtuellen Umgebung installieren
sudo apt update && sudo apt install -y python3 python3-venv python3-pip
sudo -u bot python3 -m venv /opt/mybot/.venv
sudo -u bot /opt/mybot/.venv/bin/pip install -U discord.py python-dotenv
discord.py 2.x setzt Python 3.8 oder neuer voraus; Ubuntu 24.04 liefert 3.12 und 22.04 liefert 3.10, der Interpreter der Distribution genügt also. discord.py[voice] und ffmpeg nur für Sprachkanäle ergänzen.
Schritt 3 (Node.js): aktuelles LTS und discord.js installieren
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
sudo -u bot bash -c 'cd /opt/mybot && npm init -y && npm install discord.js dotenv'
Ubuntus eigenes nodejs-Paket hinkt dem Upstream deutlich hinterher und discord.js v14 braucht eine moderne Laufzeitumgebung – nehmen Sie daher NodeSource (siehe oben) oder nvm für ein aktuelles LTS. Bei nvm which node ausführen und diesen absoluten Pfad in der Service-Unit eintragen.
Den Token aus dem Code heraushalten: die .env-Datei
Der Bot-Token ist ein Passwort mit voller Kontrolle über den Bot: niemals in bot.py oder index.js einfügen, niemals committen. Legen Sie ihn in /opt/mybot/.env ab, nur für das Bot-Konto lesbar, und benutzen Sie einen Editor statt echo, denn ein auf der Kommandozeile getippter Token landet in der Shell-History:
sudo -u bot nano /opt/mybot/.env # one line: DISCORD_TOKEN=your-token-here
sudo chmod 600 /opt/mybot/.env
echo ".env" | sudo -u bot tee -a /opt/mybot/.gitignore
Das Format ist ein KEY=value pro Zeile, ohne Anführungszeichen, ohne export. python-dotenv und das npm-Paket dotenv lesen sie, und systemd kann dieselbe Datei mit EnvironmentFile= einspeisen (nächster Abschnitt); beides zu kombinieren ist unschädlich, da keine der Bibliotheken eine bereits vorhandene Variable überschreibt. Sollte der Token je durchsickern, setzen Sie ihn sofort im Developer Portal unter Bot → Reset Token zurück.
Ein minimaler Bot in discord.py und discord.js
Beide Beispiele lesen den Token aus der Umgebung, aktivieren den Message-Content-Intent und antworten auf !ping. Legen Sie im Developer Portal eine Anwendung an, fügen Sie einen Bot-Benutzer hinzu, kopieren Sie den Token (er wird nur einmal angezeigt), aktivieren Sie Message Content Intent unter Bot → Privileged Gateway Intents und laden Sie den Bot über den OAuth2-URL-Generator mit dem Scope bot auf einen Testserver ein.
discord.py: /opt/mybot/bot.py
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.event
async def on_message(message):
if message.author == client.user:
return
if message.content == "!ping":
await message.channel.send("pong")
client.run(os.environ["DISCORD_TOKEN"])
discord.js: /opt/mybot/index.js
require("dotenv").config();
const { Client, GatewayIntentBits, Events } = require("discord.js");
const client = new Client({
intents: [
GatewayIntentBits.Guilds,
GatewayIntentBits.GuildMessages,
GatewayIntentBits.MessageContent,
],
});
client.once(Events.ClientReady, (c) => {
console.log(`Logged in as ${c.user.tag}`);
});
client.on(Events.MessageCreate, (message) => {
if (message.author.bot) return;
if (message.content === "!ping") message.reply("pong");
});
client.login(process.env.DISCORD_TOKEN);
Führen Sie ihn einmal im Vordergrund aus: sudo -u bot /opt/mybot/.venv/bin/python /opt/mybot/bot.py oder sudo -u bot node /opt/mybot/index.js, warten Sie auf Logged in as, senden Sie !ping und drücken Sie dann Strg-C. Derzeit lebt der Bot nur so lange wie Ihre SSH-Sitzung: Beim Schließen des Terminals geht ein SIGHUP an die Kindprozesse und der Bot stirbt.
Mit systemd und Restart=always betreiben
systemd ist ohnehin das Init-System von Ubuntu, deshalb ist eine Service-Unit der sauberste Weg, den Bot nach Abmeldung, Absturz und Neustart online zu halten: kein zusätzlicher Daemon, und die Logs landen im Journal.
Schritt 1: die Unit schreiben
sudo nano /etc/systemd/system/mybot.service
[Unit]
Description=Discord bot
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=bot
Group=bot
WorkingDirectory=/opt/mybot
EnvironmentFile=/opt/mybot/.env
Environment=PYTHONUNBUFFERED=1
ExecStart=/opt/mybot/.venv/bin/python /opt/mybot/bot.py
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/mybot
[Install]
WantedBy=multi-user.target
Für discord.js setzen Sie ExecStart=/usr/bin/node /opt/mybot/index.js und lassen die Zeile PYTHONUNBUFFERED weg. Die entscheidenden Direktiven:
Restart=alwaysstartet den Prozess bei jedem Beenden neu, egal ob Absturz oder sauberessys.exit();RestartSec=5verhindert, dass ein sofort sterbender Bot (falscher Token, Syntaxfehler) in einer engen Schleife kreist.Wants=/After=network-online.targetverzögern den Start, bis das Netzwerk steht, damit der erste Login nach einem Neustart nicht am DNS scheitert.PYTHONUNBUFFERED=1: Ohne Terminal puffert Pythonstdoutblockweise, undprint()-Zeilen erreichen das Journal erst Minuten später oder erst beim Beenden.- Die Zeilen
Protect*,PrivateTmpundNoNewPrivilegesmachen den Rest des Dateisystems für den Bot schreibgeschützt oder unsichtbar; jedes Verzeichnis, in das er schreiben muss, gehört inReadWritePaths=.
Schritt 2: aktivieren, starten und prüfen
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
systemctl status mybot
sudo systemctl kill --signal=KILL mybot # simulate a crash; status is active again after 5 s
enable legt den Boot-Symlink an und --now startet die Unit. Die kill-Zeile ist der eigentliche Test: Zeigt systemctl status mybot wenige Sekunden später active (running), funktioniert die Restart-Policy, und ein sudo reboot belegt den Boot-Pfad. Um ihn neben allen anderen Diensten zu sehen, können Sie die laufenden Dienste mit systemctl auflisten; er erscheint als mybot.service, und systemctl is-enabled mybot bestätigt, dass er nach einem Neustart wiederkommt.
Alternative: pm2 – und der Vergleich mit screen, nohup und Docker
Jede Methode, einen Bot am Leben zu halten, beantwortet drei Fragen: Übersteht sie die SSH-Abmeldung, startet sie nach einem Absturz neu und startet sie beim Neustart mit?
| Methode | Übersteht SSH-Abmeldung | Neustart nach Absturz | Start beim Booten | Fazit |
|---|---|---|---|---|
nohup / & | Ja | Nein | Nein | Nur für schnelle Tests. |
screen / tmux | Ja | Nein | Nein, außer per Skript | Zum Debuggen, nicht für den Produktivbetrieb. |
| pm2 | Ja | Ja | Ja, nach pm2 startup + pm2 save | Gut für Node.js-Teams; ein CLI für Logs und Neustarts. |
| systemd-Unit | Ja | Ja (Restart=) | Ja (enable) | Empfohlen; keine Zusatzsoftware, Härtung inklusive. |
Docker, restart: unless-stopped | Ja | Ja | Ja, mit dem Docker-Daemon | Gut, wenn der Bot ohnehin als Image ausgeliefert wird. |
pm2 ist die beliebte Wahl in der Node.js-Welt und kommt auch mit Python zurecht. Führen Sie es unter dem Konto aus, dem der Bot gehört:
sudo npm install -g pm2
cd /opt/mybot
pm2 start index.js --name mybot
pm2 start bot.py --name mybot --interpreter /opt/mybot/.venv/bin/python # Python variant
pm2 save
pm2 startup # prints a sudo command to run once
pm2 logs mybot
pm2 install pm2-logrotate # ~/.pm2/logs/ otherwise grows forever
pm2 startup erzeugt eine systemd-Unit pm2-<user>, die Ihre gespeicherte Prozessliste beim Booten wiederherstellt; pm2 setzt also auf systemd auf, statt es zu ersetzen – das ehrliche Argument dafür, für einen einzelnen Bot direkt systemd zu nehmen. pm2 lohnt sich bei mehreren Node-Prozessen oder in einem Team, das es ohnehin kennt.
Wenn Sie Container bevorzugen, ist restart: unless-stopped in einer Compose-Datei das Äquivalent; die Anleitung zum Installieren von Docker auf einem Ubuntu-VPS behandelt Engine, Compose und das Boot-Verhalten. Der dortige ufw-Vorbehalt betrifft einen Bot nicht, da er keine Ports veröffentlicht.
Logs, Updates und Speicherdimensionierung
Logs
journalctl -u mybot -f # follow live
journalctl -u mybot --since "1 hour ago"
journalctl -u mybot -p err -b # errors since boot
sudo journalctl --vacuum-size=200M # cap journal size
journald rotiert und komprimiert von selbst. Schreibt der Bot eine eigene Logdatei, verwenden Sie logging.handlers.RotatingFileHandler in Python oder einen rotierenden Transport mit pino oder winston in Node, damit ein geschwätziger Handler die Platte nicht vollschreibt.
Updates
cd /opt/mybot
sudo -u bot git pull
sudo -u bot .venv/bin/pip install -U -r requirements.txt # Node: sudo -u bot npm ci
sudo systemctl restart mybot
Ein Neustart trennt die Gateway-Verbindung für wenige Sekunden; die Bibliothek verbindet sich neu und den Nutzern fällt es selten auf. Pinnen Sie Bibliotheksversionen in requirements.txt oder package-lock.json und lesen Sie das Changelog vor einem Major-Sprung. Halten Sie das Betriebssystem mit sudo apt update && sudo apt upgrade oder unattended-upgrades aktuell.
Wie viel RAM braucht der Bot?
Dimensionieren Sie nicht nach Pauschalwerten, sondern messen Sie. systemctl status mybot gibt eine Zeile Memory: aus, und pm2 list zeigt dasselbe. Ein reiner Command-Bot mit discord.py liegt im Leerlauf typischerweise bei einigen zehn Megabyte; ein discord.js-Bot bringt zusätzlich die Node-Laufzeit mit. Der Speicherbedarf wächst mit dem Zustand: Member- und Message-Caches auf großen Servern, Voice und Musik (ein ffmpeg-Prozess pro Stream), Bildgenerierung oder eine Datenbank. In der Praxis betreibt 1 GB RAM bequem das Betriebssystem plus einen kleinen bis mittleren Bot; Voice-lastige Bots oder mehrere Bots auf einer Maschine rechtfertigen 2 GB oder mehr, und ab 2.500 Servern verlangt Discord Sharding, was den Bedarf vervielfacht. Zwei günstige Sicherheitsnetze: MemoryMax=512M in der Unit, damit ein Leck den Bot neu startet statt die Maschine lahmzulegen, und eine kleine Swap-Datei.
All das setzt eine Linux-Maschine mit Root-Zugriff voraus, die rund um die Uhr läuft. Falls Ihnen diese Maschine noch fehlt: der Discord-Bot-VPS von rdp.monster ist rund 10 Sekunden nach Zahlungsbestätigung online, mit dedizierter CPU und dediziertem RAM, vollem Root-Zugriff, unbegrenzter Bandbreite (Fair Use), ohne KYC, mit Krypto-Zahlung, ab $8.99/Monat – damit kann das obige systemctl enable --now mybot das Letzte sein, was Sie tippen, bevor der Bot grün leuchtet.
Häufig gestellte Fragen
Kann ich einen Discord-Bot kostenlos rund um die Uhr hosten?
systemd den Bot nach Absturz und Neustart wieder hochfährt und niemand ihn wegen Leerlauf aussetzt.Braucht ein Discord-Bot eine feste IP oder offene Ports auf dem VPS?
Kann ich mehrere Discord-Bots auf einem VPS betreiben?
/opt/bot-a und /opt/bot-b, eine eigene .env mit eigenem Token und eine eigene Unit-Datei, und führen Sie dann für jeden systemctl enable --now aus. Getrennte Systembenutzer verhindern, dass ein Fehler in einem Bot den Token des anderen lesen kann. Das einzige gemeinsame Budget sind RAM und CPU: Beobachten Sie systemctl status je Unit und wechseln Sie auf einen größeren Tarif, wenn die Summe an die Grenze stößt.Windows- oder Linux-VPS für einen Discord-Bot?
systemd-Unit. Unter Windows würden Sie dasselbe Neustartverhalten über den Aufgabenplaner oder NSSM erreichen – mit mehr Klicks.Adrien Roche, Redakteur für Infrastruktur & Hosting
Systemingenieur mit über 10 Jahren Erfahrung im Betrieb von Windows-Server- und Linux-Flotten. Adrien pflegt die Infrastruktur-Dokumentation von rdp.monster und schreibt unsere Guides zu RDP, VPS-Hosting, Serveradministration, Netzwerken und Privacy-Tools.




