systemd: run your app as a service and schedule jobs with timers
systemd keeps your app running, restarts it on failure and schedules jobs. Learn a minimal service file, timers and the commands you will use daily.

systemd is the init system on most modern Linux distributions. It starts services at boot, restarts them when they crash, collects their logs and runs scheduled jobs. For a small server, it is the easiest way to run your own app reliably.
A minimal service
Create /etc/systemd/system/myapp.service:
[Unit]
Description=My web app
After=network-online.target
[Service]
User=deploy
WorkingDirectory=/srv/myapp
EnvironmentFile=/etc/myapp.env
ExecStart=/usr/bin/node /srv/myapp/server.js
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
What the lines do:
After=: start after the network is up.User=: run as a normal user, not root.EnvironmentFile=: load settings and secrets from a file (keep itchmod 600) instead of putting them in the unit.ExecStart=: the command to run, with the full path.Restart=on-failure: bring it back if it crashes.WantedBy=multi-user.target: start at normal boot when enabled.
The commands you will use
sudo systemctl daemon-reload # after editing a unit file
sudo systemctl enable --now myapp # start now and at every boot
sudo systemctl status myapp # state and the last log lines
sudo systemctl restart myapp
sudo systemctl stop myapp
sudo systemctl disable myapp
Logs with journalctl
systemd collects what your app prints.
journalctl -u myapp # all logs for the service
journalctl -u myapp -f # follow live
journalctl -u myapp --since "1 hour ago"
journalctl -u myapp -p err # errors only
Hardening options (optional but useful)
Inside [Service] you can restrict what the app can do, for example:
NoNewPrivileges=truePrivateTmp=trueProtectSystem=fullProtectHome=true
Add them one at a time and test, because a strict setting can stop a legitimate app from working.
Timers: a modern replacement for cron
A timer runs a service on a schedule. You need two files with the same name: a .service (what to run) and a .timer (when).
/etc/systemd/system/backup.service
[Unit]
Description=Daily backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
/etc/systemd/system/backup.timer
[Unit]
Description=Run the backup every day
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers
Handy options:
OnCalendar=: a calendar time (daily, weekly, or a specific time).OnUnitActiveSec=15min: repeat 15 minutes after the last run.Persistent=true: if the machine was off at the scheduled time, run it when it comes back.RandomizedDelaySec=: spread load.
Compared with cron, timers give you logs in the journal, dependency handling, and easy status checks.
Common mistakes
- Forgetting
daemon-reloadafter editing. - Relative paths in
ExecStart(use full paths). - A service that runs as root when it does not need to.
- Putting secrets directly in the unit file, which many users can read.
Takeaway: a short unit file gives you auto-start, auto-restart and clean logs. Use timers for scheduled jobs, run services as a normal user, and keep secrets in a locked-down environment file.
Linux & DevOps series, Part 1 (servers and containers): 2 of 5. Previous: Linux file permissions explained: chmod, chown and umask.


