Running an app with & or nohup is fine until the server reboots, the process crashes, or you want to find its logs — then it falls apart. systemd is the standard answer: it starts your app on boot, restarts it if it dies, and captures its logs. Turning a script or binary into a managed service is one small file.
1. Write a unit file
Create /etc/systemd/system/myapp.service:
[Unit]
Description=My application
After=network.target
[Service]
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/run.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Adjust ExecStart, WorkingDirectory and User to your app. Restart=always is what keeps it alive.
2. Create a dedicated user (recommended)
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp
sudo chown -R myapp:myapp /opt/myapp
Running as a non-root user limits the damage if the app is ever compromised.
3. Enable and start it
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
enable makes it start on boot; --now starts it immediately.
4. Check status and logs
sudo systemctl status myapp
journalctl -u myapp -f # follow live logs
Everyday commands
sudo systemctl restart myapp # restart after a change
sudo systemctl stop myapp # stop it
sudo systemctl disable myapp # stop starting on boot
Honest cautions
- Run
daemon-reloadafter editing a unit file, or systemd uses the old version. - Watch for crash loops. If the app fails instantly,
Restart=alwaysretries forever —RestartSec=5spaces attempts out; fix the root error via the logs. - Prefer a non-root
User=so a compromised app doesn't own the whole server.
Next steps
A systemd service is how you keep anything running 24/7 — for example an AI agent that runs around the clock or the relay behind a self-hosted RustDesk server. If your app is containerised instead, Docker's --restart unless-stopped plays the same role — see how to install Docker.
Comments
No comments yet. Be the first.