There are two ways a bot "doesn't work" on a server. The obvious one: it stops the second you close SSH. The sneaky one: it runs fine for two days, crashes at 4am on some unhandled error, and you find out hours later when someone asks why it's down. Both have the same fix, and it's not "remember to restart it" — it's handing the job to systemd, which keeps things up so you don't have to.
Why it dies when you log out
If you launched it with python bot.py in your SSH session, the process is a child of that session. Close the session, the process goes with it. nohup and & paper over this, but they give you no restart-on-crash and no start-on-boot — so you've solved the small problem and kept the big one.
The real fix: a systemd service
This is the whole thing. Create /etc/systemd/system/mybot.service:
[Unit]
Description=My bot
After=network-online.target
[Service]
WorkingDirectory=/home/youruser/mybot
ExecStart=/home/youruser/mybot/venv/bin/python bot.py
Restart=always
RestartSec=5
User=youruser
Environment=API_KEY=...
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now mybot
Two lines are doing the heavy lifting:
Restart=always— the bot crashes, systemd brings it back in 5 seconds. That 4am death becomes a 5-second blip nobody notices.enable— it starts again after a reboot, on its own. No "oh, the server restarted and I forgot to relaunch everything."
When it's still misbehaving — read the logs
A bot that keeps crash-looping isn't fixed by restarting harder; something is actually wrong. systemd captures stdout/stderr, so:
systemctl status mybot # up or down, last exit code
journalctl -u mybot -n 100 # recent logs + the error it died on
journalctl -u mybot -f # follow live
The cause is almost always right there: a missing environment variable, an unhandled exception, an API timeout, an OOM kill. Fix that — Restart=always is a safety net, not a cure for a real bug.
Tip: if the logs show the bot getting killed for memory, you've outgrown the box — check the sizing guide.
When tmux or pm2 make sense instead
systemd isn't the only answer, just the best default:
- tmux — perfect for a quick test or watching an interactive process. Run, detach, reattach later. But it won't restart on crash or survive a reboot, so it's not for production.
- pm2 — reasonable if you're already in the Node world and want its process dashboard. The catch: pm2 is itself a process you now have to keep alive (usually... via systemd). For one bot, that's a layer you don't need.
For a single always-on bot or agent, systemd is the simplest thing that actually works — it's already on the server, needs no extra tooling, and does restart, boot-start and logging out of the box.
The honest bottom line
Uptime isn't about a bigger server or more discipline — it's about not tying your process to your laptop. Wrap it in a systemd unit with Restart=always and enable, and check journalctl when something's off. Do that once and your bot stays up whether you're watching or asleep. (New box? Lock it down first — a 24/7 bot is also a 24/7 target.)