Blog
3 min read

How to Run a Python Script 24/7 (and Keep It Running)

Scrapers, bots, monitors and workers need to keep running after you close your laptop. The options — a server with systemd, tmux for quick jobs, Docker with a restart policy, cron for scheduled scripts — plus logging, restarting on crashes, and not losing data on restart.

You've written a Python script — a bot, a scraper, a price monitor, a queue worker — and it works when you run python script.py. Then you close your laptop, and it stops.

Running something 24/7 needs two things:

  1. A machine that's always on — not your laptop.
  2. Something that restarts the script when it crashes or the machine reboots.

First: does it need to run constantly?

If your script does a job every hour or once a day and then finishes, it doesn't need to run 24/7 — it needs to be scheduled. Use cron (or a systemd timer):

crontab -e
0 * * * * /srv/myscript/.venv/bin/python /srv/myscript/check_prices.py >> /var/log/prices.log 2>&1

That runs it at the start of every hour. (Cron expressions explained)

Run it continuously only if it must react instantly (a bot, a listener, a worker processing a queue).

Where to run it

  • A small VPS — cheap, always on, full control. (What is a VPS?)
  • A container platform that supports background workers. (Render vs Railway vs Fly.io)
  • A Raspberry Pi at home — fine for personal projects.

Free hosts that put apps to sleep when idle don't work for always-running scripts.

Set up the script on the server with a virtual environment:

cd /srv/myscript
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt

(Python virtual environments)

Create /etc/systemd/system/myscript.service:

[Unit]
Description=My Python script
After=network-online.target

[Service]
User=app
WorkingDirectory=/srv/myscript
EnvironmentFile=/srv/myscript/.env
ExecStart=/srv/myscript/.venv/bin/python -u main.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now myscript
journalctl -u myscript -f      # watch its output
  • Restart=always — restart after crashes.
  • enable — start on boot.
  • -u — unbuffered output, so print() shows up in the logs immediately.

(What is systemd?, systemd service file)

Option 2: tmux (quick and temporary)

For a one-off long job you'll watch yourself:

tmux new -s scraper
python main.py
# press Ctrl+B, then D, to detach

Log out — it keeps running. tmux attach -t scraper to come back. But tmux won't restart the script if it crashes or the server reboots. (tmux cheat sheet)

(nohup python main.py & is the older version of this idea, with the same limits.)

Option 3: Docker

docker run -d --name myscript --restart unless-stopped --env-file .env myscript:latest

--restart unless-stopped brings it back after crashes and reboots. Good if you already use Docker. (Dockerfile explained)

Make the script itself robust

A 24/7 script will meet network errors, API timeouts and rate limits. Prepare for them:

  • Catch errors inside the main loop and retry with a delay, rather than letting one failed request kill the process. (Exponential backoff)
  • Log, don't just print — with timestamps, so you can see what happened at 3 a.m. (Structured logging)
  • Save state to disk or a database, not variables in memory. On restart, pick up where it left off. (Is SQLite good enough?)
  • Handle shutdown signals so it finishes the current item before stopping.
  • Watch memory — a slow leak eventually gets the process killed.

Know when it stops

Pair it with a "heartbeat" check: the script pings a monitoring URL every few minutes, and you get an alert if the pings stop. (How to know when your app is down)


EasySpawn gives you an always-on server where scripts run as managed services — restarted on crashes and reboots, with logs a click away and Claude Code to help harden them. See how it works or join the waitlist.

Related: How to Host a Discord Bot 24/7 · What Is systemd? · Your App Needs Background Jobs · A tmux Cheat Sheet

Keep reading