~$ delxium

systemd · linux · devops

systemd: A Pocket Companion

Run your app as a real service — started on boot, restarted on crash, with logs you can actually read.

A process you start by hand dies when you log out. systemd is how Linux runs things properly: as services that start on boot, restart if they crash, and log to one place you can query. This guide turns a plain script into a managed service, then replaces a cron job with a timer — the ops layer beneath everything you deploy.

$ sudo systemctl status nginx     # is it running? when did it start? recent logs?

The model: units

systemd manages units — mostly .service units (long-running processes) and .timer units (scheduled triggers). You control them with systemctl and read their logs with journalctl.

$ systemctl status  <name>   # state + recent log lines
$ systemctl start   <name>   # start now
$ systemctl stop    <name>   # stop now
$ systemctl restart <name>   # stop + start
$ systemctl enable  <name>   # start automatically on boot
$ systemctl disable <name>   # don't start on boot
$ systemctl enable --now <name>   # enable *and* start in one go

enable ≠ start

start runs it right now; enable makes it run on every boot. They’re independent — you usually want both, which is what enable --now does.

Turning a script into a service

Say you have an app started by /opt/myapp/run.sh. Create /etc/systemd/system/myapp.service:

[Unit]
Description=My App
After=network.target

[Service]
ExecStart=/opt/myapp/run.sh
WorkingDirectory=/opt/myapp
User=appuser
Restart=on-failure
RestartSec=3
Environment=PORT=8000

[Install]
WantedBy=multi-user.target

Three sections: [Unit] is metadata and ordering (After= says start us once the network is up), [Service] is how to run it, and [Install] is when to enable it.

$ sudo systemctl daemon-reload        # tell systemd to re-read unit files
$ sudo systemctl enable --now myapp   # start it + run on boot
$ systemctl status myapp              # confirm it's active

Edit a unit? daemon-reload first

systemd caches unit files. After creating or editing one, run sudo systemctl daemon-reload before restart, or your changes won’t take effect.

Restart policy: surviving crashes

The line that earns systemd its keep:

Restart=on-failure   # restart only on non-zero exit / signal
RestartSec=3         # wait 3s between restarts

Restart=always restarts even on clean exits; on-failure restarts only on crashes — usually what you want for a web app. systemd also backs off if a service crash-loops, so a broken deploy doesn’t hammer the box.

Reading logs: journalctl

All service output goes to the journal — no more hunting through /var/log:

$ journalctl -u myapp            # all logs for this unit
$ journalctl -u myapp -f         # follow (tail -f)
$ journalctl -u myapp -n 100     # last 100 lines
$ journalctl -u myapp --since "10 min ago"
$ journalctl -u myapp -p err     # only errors and worse
$ journalctl -b                  # logs since the last boot

journalctl -u myapp -f is the one you’ll live in while debugging a deploy.

Timers: a better cron

systemd timers replace cron jobs — with logs, dependencies, and the ability to catch up on missed runs. Pair a .service (what to do) with a .timer (when):

/etc/systemd/system/backup.service:

[Service]
Type=oneshot
ExecStart=/opt/backup.sh

/etc/systemd/system/backup.timer:

[Timer]
OnCalendar=*-*-* 03:00:00   # every day at 3am
Persistent=true             # run on next boot if a scheduled run was missed

[Install]
WantedBy=timers.target
$ sudo systemctl enable --now backup.timer
$ systemctl list-timers          # what's scheduled, and when it next fires

Persistent=true is the win over cron: if the machine was off at 3am, the job runs once it’s back — cron would just skip it.

When it breaks

  • Service won’t start? systemctl status myapp shows the exit code; journalctl -u myapp -n 50 shows why.
  • Edited the unit, nothing changed? daemon-reload, then restart.
  • Crash-looping? Check the logs, then systemctl reset-failed myapp after you fix it.
  • Wrong working dir / user? Those are common silent failures — set WorkingDirectory and User explicitly.

Pocket cheat-sheet

Do Command
Status + recent logs systemctl status x
Start / stop / restart systemctl start\|stop\|restart x
Enable on boot (+ start) systemctl enable --now x
Re-read unit files systemctl daemon-reload
Follow logs journalctl -u x -f
Errors only / since boot journalctl -u x -p err / journalctl -b
List scheduled timers systemctl list-timers

Wrap any long-running process in a unit file and it becomes something you can trust: started on boot, restarted on failure, logged in one place. man systemd.service and man systemd.timer are the full reference.

← all field notes