EQVPS

Keep a bot running 24/7 on a VPS (so it never silently dies)

Jun 15, 2026 · 3 min read · EQVPS Team

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:

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 thatRestart=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:

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.)

FAQ

Why does my bot stop when I close SSH?

Because you started it inside your SSH session, so it's tied to that session and dies when you disconnect. The fix is to run it as a background service that's independent of your login — systemd is the clean way, tmux is the quick way.

How do I auto-restart a bot when it crashes?

Run it as a systemd service with Restart=always and a small RestartSec delay. systemd then relaunches the process within seconds of any crash, indefinitely, with no babysitting. That single line is the difference between 'it died at 4am' and 'it blipped and recovered.'

How do I make a bot start automatically after a reboot?

systemctl enable your service. 'enable' wires it to start at boot, 'start' runs it now — do both (systemctl enable --now). After any reboot, the bot comes back on its own without you logging in.

systemd or pm2 or tmux — which should I use?

systemd for anything real and long-lived: it handles restart, boot-start and logging natively, no extra tooling. tmux is great for a quick test or watching an interactive run. pm2 is reasonable if you live in Node and want its dashboard, but it's another thing to keep running. For a single always-on bot, systemd wins on simplicity.

How do I see why my bot keeps crashing?

journalctl -u yourbot -n 100 shows the recent logs and the error it died on; add -f to follow live. This is usually where the real cause hides — a missing env var, an unhandled exception, an API timeout. Fix that, don't just restart blindly.

← Back to blogSee plans & pricing →