skip to content

Search

Syspirit
EN

Systemd

Manage Linux services with systemd: systemctl, journalctl, units and timers, including the differences between Debian, Ubuntu and RHEL!

Linux
Published on
Karl Certa

Systemd is the service manager and PID 1 of nearly every Linux distribution. It starts services, handles their dependencies, collects their logs in the journal and schedules tasks through its timers.

🐧 What changes between distributions

The systemctl commands are the same everywhere. What varies is the systemd version shipped, so the options available, and the choices each distribution makes. To check yours: systemctl --version.

📌 Distribution📦 Systemd version⚠️ Distribution specifics
🌀 Debian 12 bookworm252rsyslog is no longer installed by default, no /var/log/syslog
🌀 Debian 13 trixie257Default config moved under /usr/lib/systemd/
🟠 Ubuntu 22.04 LTS249SSH uses socket activation since 22.10
🟠 Ubuntu 24.04 LTS255ssh.socket listens instead of ssh.service
🟠 Ubuntu 26.04 LTS259Support for legacy cgroup v1 removed for good
🔴 RHEL / Rocky / Alma 9252SysV scripts are still supported
🔴 RHEL / Rocky / Alma 10257SysV scripts deprecated, convert them to units

Alpine and Devuan are the exception: they run OpenRC or sysvinit, so none of the commands here apply.

⚙️ Service management

📌 Action🧠 Command
▶️ Startsudo systemctl start <unit>
⏹️ Stopsudo systemctl stop <unit>
🔁 Restartsudo systemctl restart <unit>
🔄 Reload the configsudo systemctl reload <unit>
🚀 Enable at bootsudo systemctl enable <unit>
⚡ Enable and startsudo systemctl enable --now <unit>
🚫 Disable at bootsudo systemctl disable --now <unit>
🔒 Block any startsudo systemctl mask <unit>
🔓 Remove the blocksudo systemctl unmask <unit>
♻️ Pick up a modified unitsudo systemctl daemon-reload

🏷️ Service names per distribution

This is where commands copied between distributions break.

📌 Service🌀 Debian / Ubuntu🔴 RHEL / Rocky / Alma / Fedora🟢 openSUSE
🔐 SSHssh (+ ssh.socket on Ubuntu)sshdsshd
⏰ Croncroncrondcron
🌐 Apacheapache2httpdapache2
🛡️ Firewallufw or nftablesfirewalldfirewalld
🕐 Time syncsystemd-timesyncdchronydchronyd

🔍 Status and inventory

📌 Action🧠 Command
📊 Detailed statussystemctl status <unit>
✅ Is it running?systemctl is-active <unit>
🚀 Is it enabled at boot?systemctl is-enabled <unit>
📋 Loaded servicessystemctl list-units --type=service
🗂️ All installed servicessystemctl list-unit-files --type=service
❌ Failed servicessystemctl --failed
📄 Effective unit contentsystemctl cat <unit>

📜 Reading a service journal

journalctl is part of systemd. The systemd-journald daemon captures the output of every service and indexes it per unit, which is what makes the -u filter possible. It picks up where systemctl status stops, since that only shows the last ten lines.

📌 Action🧠 Command
📖 Logs of a servicejournalctl -u nginx
🔟 Last 50 linesjournalctl -u nginx -n 50 --no-pager
👀 Follow livejournalctl -u nginx -f
🔀 Follow several servicesjournalctl -f -u nginx -u php8.2-fpm
🕐 Since a point in timejournalctl -u nginx --since "2 hours ago"
🔴 Errors onlyjournalctl -u nginx -p err
🥾 Current / previous bootjournalctl -b / journalctl -b -1
🆘 Last errors with contextjournalctl -xe

For journal disk usage and trimming, see the Disk space cheatsheet.

📄 Anatomy of a unit

[Unit]
Description=Application backup
After=network-online.target       # Waits for the network to be truly reachable
Wants=network-online.target       # Soft dependency, not blocking
 
[Service]
Type=simple                       # simple: process stays in the foreground
                                  # oneshot: runs then exits
User=backup                       # Never leave root without a reason
ExecStart=/opt/scripts/backup.sh
Restart=on-failure                # no, on-failure, always
RestartSec=30                     # Delay before restarting
 
[Install]
WantedBy=multi-user.target        # Target that pulls the service in at boot
📌 Action🧠 Command
➕ Add an overridesudo systemctl edit <unit>
📝 Copy the whole unitsudo systemctl edit --full <unit>
🔙 Back to the originalsudo systemctl revert <unit>

📂 Locations and priority

📌 Path🧠 Purpose📊 Priority
/etc/systemd/system/Your units and overridesHighest
/usr/lib/systemd/system/Units shipped by packagesLowest
~/.config/systemd/user/User units (--user)Session

On Debian and Ubuntu, /lib/systemd/system/ is still visible: since the /usr merge it is only a symlink to /usr/lib/systemd/system/.

⏱️ Timers, the cron alternative

📌 Action🧠 Command
📋 List active timerssystemctl list-timers
▶️ Enable a timersudo systemctl enable --now backup.timer
🧪 Trigger it manuallysudo systemctl start backup.service
📅 Test an expressionsystemd-analyze calendar "Mon *-*-* 02:30:00"
# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup
 
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true      # Catches up a missed run if the machine was off
 
[Install]
WantedBy=timers.target
📌 CriterionCron⏱️ Systemd timer
🧠 SyntaxCompact, five fieldsVerbose, two files
📜 LogsMTA or a separate fileIn the journal, journalctl -u
🔁 Catch-upNo, unless anacronPersistent=true

🎯 Targets and boot

📌 Action🧠 Command
🎯 Default targetsystemctl get-default
🖥️ Boot to console modesudo systemctl set-default multi-user.target
🚑 Rescue modesudo systemctl rescue
⏱️ Boot durationsystemd-analyze
🐌 Slowest servicessystemd-analyze blame

🛠️ Common troubleshooting

🆘 Problem🧠 Solution
❌ Unit change has no effectRun systemctl daemon-reload before the restart
🔁 Service restarts in a loopCheck Restart= and read journalctl -u <unit> -b
🚫 Unit is maskedsystemctl unmask <unit>
📭 journalctl returns nothingVolatile journal, create /var/log/journal
🐢 Service starts too earlyUse After=network-online.target over network.target
📄 /var/log/syslog missingExpected since Debian 12, everything goes to journalctl
📄 /var/log/messages missingExpected on Debian and Ubuntu, that path is RHEL only

🧭 Old habits and their equivalents

📌 Old command🧠 Systemd equivalent
service nginx restartsystemctl restart nginx
chkconfig nginx onsystemctl enable nginx
chkconfig --listsystemctl list-unit-files
shutdown -r nowsystemctl reboot
tail -f /var/log/messagesjournalctl -f