Systemd Basics
Introduction to systemd service management
0. Specs
0.1. The What
systemd is a suite of basic building blocks for a Linux system. It provides a system and service manager that runs as PID 1 and starts the rest of the system (from systemd.io).
systemd is a software suite that provides an array of system components for Linux operating systems (from Wikipedia).
systemd is an init system for Linux that replaces SysV init. Many distributions use it as their init system, including Debian, Ubuntu, and RHEL. However, several distributions do not use systemd, such as Slackware, Devuan, Alpine, and Gentoo.
A strong alternative to systemd is OpenRC.
0.2. Definitions
D-Bus (Desktop Bus): A message-oriented middleware mechanism that allows communication between multiple processes running concurrently on the same machine (from Wikipedia).
cgroups (Control Groups): A kernel feature that allows setting resource utilization limits for processes, such as CPU shares, memory usage, and block I/O per process. Originally developed by Google.
0.3. Environment
This tutorial is prepared using Debian 12/13 and Ubuntu 24.04/26.04 editions. I believe it will be valid with any distro with systemd.
0.4. Sources
- wiki.debian.org
- www.digitalocean.com
- www.digitalocean.com
- www.digitalocean.com
- www.redhat.com
- wikipedia.org
- wikipedia.org
- access.redhat.com
- www.howtogeek.com
- systemd.io
- The Debian Administrator’s Handbook by Raphaël Hertzog and Roland Mas
- Linux Service Management Made Easy with systemd by Donald A. Tevault
1. systemd Units
Units are the resources that systemd knows how to manage and to operate.
1.1. Unit Locations
Unit files are located in the following directories (listed in increasing order of precedence):
/lib/systemd/system//run/systemd/system//etc/systemd/system/
1.2. Unit Types:
.service: Contains information for managing a service or application, including starting, stopping, automatic startup, and dependencies..socket: Describes a socket for systemd's socket-based activation. Must have an associated.servicefile..device: Describes a device that requires systemd management. Not all devices have a.devicefile..mount: Describes mountpoints that need to be managed by systemd..automount: Configures a mountpoint to be automatically mounted. Must have a corresponding.mountunit..swap: Describes swap space on the system..target: Used to synchronize with other units (similar to runlevels in SysV init)..path: Defines a path for path-based activation. A matching unit is started based on the path's existence or state..timer: Defines a timer managed by systemd. A matching unit is started when the timer elapses..snapshot: Created with thesystemctl snapshotcommand. Saves the current system state but does not persist across reboots..slice: Associated with cgroups (Linux Control Group nodes), allowing resource restrictions to be applied..scope: Created automatically by systemd from information received via its bus interfaces. Manages sets of system processes created externally.
1.3. Example Unit Files
Contents of /lib/systemd/system/apache2.service:
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=https://httpd.apache.org/docs/2.4/
[Service]
Type=forking
Environment=APACHE_STARTED_BY_SYSTEMD=true
ExecStart=/usr/sbin/apachectl start
ExecStop=/usr/sbin/apachectl graceful-stop
ExecReload=/usr/sbin/apachectl graceful
KillMode=mixed
PrivateTmp=true
Restart=on-abort
OOMPolicy=continue
[Install]
WantedBy=multi-user.target
Contents of /lib/systemd/system/ssh.service:
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target nss-user-lookup.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
Alias=sshd.service
Contents of /lib/systemd/system/ssh.socket:
[Unit]
Description=OpenBSD Secure Shell server socket
Before=sockets.target
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Socket]
ListenStream=22
Accept=no
[Install]
WantedBy=sockets.target
Contents of /etc/systemd/system/snap-firefox-2356.mount:
[Unit]
Description=Mount unit for firefox, revision 2356
After=snapd.mounts-pre.target
Before=snapd.mounts.target
Before=local-fs.target
[Mount]
What=/var/lib/snapd/snaps/firefox_2356.snap
Where=/snap/firefox/2356
Type=squashfs
Options=nodev,ro,x-gdu.hide,x-gvfs-hide
LazyUnmount=yes
[Install]
WantedBy=snapd.mounts.target
WantedBy=multi-user.target
1.4. Unit File Structure
Unit files consist of sections. The [Unit] and [Install] sections can exist in all unit types. Additional sections exist for specific unit types: [Socket], [Mount], [Automount], [Swap], [Path], [Timer], and [Slice].
Sections contain directives, which can be general or specific to certain unit types.
For a complete list of directives, see:
https://www.freedesktop.org/software/systemd/man/systemd.directives.html
1.4.1. [Unit] Section Directives (Applies to all unit types)
Description: A brief description of the unit.Documentation: Location of documentation.Requires: Units this unit depends on. All must be activated for this unit to activate.Wants: Similar toRequiresbut less strict. Systemd attempts to activate listed units before this unit.BindsTo: Similar toRequires; also stops this unit when the listed unit stops.Before: This unit must start before listed units (does not imply dependency).After: Listed units must start before this unit (does not imply dependency).Conflicts: This unit cannot run simultaneously with listed units. Starting this unit stops others.Condition: Unit starts only if conditions are met; otherwise, it is skipped.Assert: Similar toCondition, but unmet conditions cause a failure.ConditionPathExists: Unit starts if the specified path exists. Prefix with!to negate.
1.4.2. [Install] Section Directives (Applies to all unit types)
WantedBy: Similar to theWantsdirective; commonly used with targets.RequiredBy: Similar toWantedBybut stricter; failure occurs if dependency is unmet.Alias: Allows the unit to have an alias name (e.g.,sshforsshd).Also: Additional units to install/uninstall alongside this unit.DefaultInstance: Used only with template units; specifies the default instance name.
1.4.3. [Service] Section Directives (Applies to service units)
Type: Defines the service type:simple: Systemd assumes the service starts immediately.exec: Similar tosimple, but systemd waits for the binary to execute.forking: The service forks a child process and exits.oneshot: The service runs briefly and exits.dbus: The service acquires a name on the D-Bus.notify: The service notifies systemd when startup is complete.idle: The service runs only after all other jobs are dispatched.
RemainAfterExit: Commonly used withoneshot; indicates the service remains active after the process exits.PIDFile: Forforkingtype; specifies the file containing the child process PID.BusName: Fordbustype; the D-Bus name to acquire.NotifyAccess: Controls which service status messages are notified (main,exec, ornone).Environment: Environment variables to set.EnvironmentFile: File containing environment variables. Prefix with-to ignore if the file is missing.KillMode: How to stop the service:process(kill main process only),mixed(kill main and child processes),none(only runExecStop).ExecStart: Command to start the service. Prefix with-to ignore failures.ExecStartPre: Commands to run before the main process.ExecStartPost: Commands to run after the main process starts.ExecReload: Command to reload the service.ExecStop: Command to stop the service.ExecStopPost: Commands to run after stopping the service.RestartSec: Time to wait before restarting.Restart: Conditions for automatic restart (always,on-success,on-failure,on-abnormal,on-abort,on-watchdog).RestartPreventExitStatus: Prevents restart if the specified exit code is received.RuntimeDirectory: Directory under/runfor the service.RuntimeDirectoryMode: Permissions for the runtime directory (default:0755).TimeoutSec: Time to wait before marking start/stop as failed (or killing).TimeoutStartSec: Time to wait before marking start as failed.TimeoutStopSec: Time to wait before marking stop as failed.
1.4.4. [Socket] Section Directives (Applies to socket units)
ListenStream: Address to listen on for a TCP stream.ListenDatagram: Address to listen on for a UDP datagram.ListenSequentialPacket: Address to listen on for a Unix socket stream.ListenFIFO: Filesystem FIFO to listen on.Accept: Ifyes, a service instance is spawned for each connection; ifno, all sockets are passed to the service unit.SocketUser: Unix username for the socket (default:root).SocketGroup: Unix group name for the socket (default:root).SocketMode: Filesystem permissions for the socket (default:0666).Service: Name of the connected service (if different from the socket name).
1.4.5. [Mount] Section Directives (Applies to mount units)
What: Path to mount.Where: Mountpoint path.Type: Filesystem type.Options: Comma-separated mount options.SloppyOptions: Boolean; iftrue, unrecognized mount options are ignored.DirectoryMode: Permissions for parent directories of the mountpoint.TimeoutSec: Time to wait before marking the operation as failed.
1.4.6. [Automount] Section Directives (Applies to automount units)
Where: Mountpoint path.DirectoryMode: Permissions for parent directories.
1.4.7. [Swap] Section Directives (Applies to swap units)
What: Path to the swap file or device.Priority: Swap priority (integer).Options: Comma-separated options for/etc/fstab.TimeoutSec: Time to wait before marking the operation as failed.
1.4.8. [Path] Section Directives (Applies to path units)
PathExists: Activates the associated unit if the path exists.PathExistsGlob: Similar toPathExistsbut supports glob patterns.PathChanged: Activates the unit when the file at the path is saved and closed.PathModified: Similar toPathChangedbut also triggers on file modifications.DirectoryNotEmpty: Activates the unit if the specified directory is not empty.Unit: Name of the connected unit (if different from the path name).MakeDirectory: Iftrue, creates directories before watching.DirectoryMode: Permissions for created directories (default:0755).
1.4.9. [Timer] Section Directives (Applies to timer units)
OnActiveSec: Activates the associated unit after this duration from timer activation.OnBootSec: Activates the unit after this duration from boot.OnStartupSec: Activates the unit after this duration from systemd startup.OnUnitActiveSec: Activates the unit after this duration from the last activation.OnUnitInactiveSec: Activates the unit after this duration from the last inactivation.OnCalendar: Absolute time to activate the unit.AccuracySec: Timer accuracy level.Unit: Name of the associated unit (if different from the timer name).Persistent: Iftrue, stores the last trigger time on disk; triggers immediately if missed while inactive.
2. Targets
2.1. Definition and List
Targets are similar to SysV init runlevels. Their purpose is to group other systemd units through chains of dependencies.
A fresh Debian 13 server installation includes the following targets:
systemctl list-unit-files --type=target
UNIT FILE STATE PRESET
basic.target static -
blockdev@.target static -
bluetooth.target static -
boot-complete.target static -
ctrl-alt-del.target alias -
default.target alias -
emergency.target static -
exit.target disabled disabled
factory-reset.target static -
final.target static -
first-boot-complete.target static -
getty-pre.target static -
getty.target static -
graphical.target static -
halt.target disabled disabled
hibernate.target static -
hybrid-sleep.target static -
initrd-fs.target static -
initrd-root-device.target static -
initrd-root-fs.target static -
initrd-switch-root.target static -
initrd-usr-fs.target static -
initrd.target static -
kexec.target disabled disabled
local-fs-pre.target static -
local-fs.target static -
multi-user.target static -
network-online.target static -
network-pre.target static -
network.target static -
nss-lookup.target static -
nss-user-lookup.target static -
paths.target static -
poweroff.target disabled disabled
printer.target static -
reboot.target disabled enabled
remote-fs-pre.target static -
remote-fs.target enabled enabled
rescue-ssh.target static -
rescue.target static -
rpcbind.target static -
runlevel0.target alias -
runlevel1.target alias -
runlevel2.target alias -
runlevel3.target alias -
runlevel4.target alias -
runlevel5.target alias -
runlevel6.target alias -
shutdown.target static -
sigpwr.target static -
sleep.target static -
slices.target static -
smartcard.target static -
sockets.target static -
soft-reboot.target static -
sound.target static -
ssh-access.target static -
storage-target-mode.target static -
suspend-then-hibernate.target static -
suspend.target static -
swap.target static -
sysinit.target static -
system-update-pre.target static -
system-update.target static -
time-set.target static -
time-sync.target static -
timers.target static -
tpm2.target static -
sigpwr.target static -
sleep.target static -
slices.target static -
smartcard.target static -
sockets.target static -
soft-reboot.target static -
sound.target static -
ssh-access.target static -
storage-target-mode.target static -
suspend-then-hibernate.target static -
suspend.target static -
swap.target static -
sysinit.target static -
system-update-pre.target static -
system-update.target static -
time-set.target static -
time-sync.target static -
timers.target static -
tpm2.target static -
umount.target static -
usb-gadget.target static -
Target configuration files are located in /lib/systemd/system/.
2.2. Example Target Files
network.target:
[Unit]
Description=Network
Documentation=man:systemd.special(7)
Documentation=https://systemd.io/NETWORK_ONLINE
After=network-pre.target
RefuseManualStart=yes
multi-user.target:
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
graphical.target:
[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes
3. Unit Management: systemctl Command
Start a service:
sudo systemctl start apache2.service
Stop a service:
sudo systemctl stop apache2.service
Reload a service (reloads configuration without restarting):
sudo systemctl reload apache2.service
Restart a service:
sudo systemctl restart apache2.service
Reload if possible, otherwise restart:
sudo systemctl reload-or-restart apache2.service
Enable a service (starts automatically at boot):
sudo systemctl enable apache2.service
Disable a service (does not start at boot):
sudo systemctl disable apache2.service
Show status of a service:
sudo systemctl status apache2.service
Check if a service is active:
systemctl is-active apache2.service
Check if a service is enabled:
systemctl is-enabled apache2.service
Check if a service has failed:
systemctl is-failed apache2.service
Mask a service (prevents it from being started, even manually):
sudo systemctl mask apache2.service
Unmask a service:
sudo systemctl unmask apache2.service
List all active units:
sudo systemctl list-units
List all units (including loaded and attempted):
sudo systemctl list-units --all
List all installed unit files:
sudo systemctl list-unit-files
List services only:
systemctl list-units --type=service
View the contents of a unit file:
systemctl cat apache2.service
View dependencies of a unit:
systemctl list-dependencies apache2.service
View dependencies recursively:
systemctl list-dependencies apache2.service --all
View low-level details of a unit:
systemctl show apache2.service
Create an override or modify settings (creates/edit a drop-in file):
sudo systemctl edit apache2.service
Edit the entire unit file:
sudo systemctl edit --full apache2.service
Reload systemd (after modifying unit files):
sudo systemctl daemon-reload
Show the default target (equivalent to runlevel):
systemctl get-default
Set the default target:
sudo systemctl set-default graphical.target
sudo systemctl set-default multi-user.target
List available targets:
systemctl list-unit-files --type=target
List units associated with a target:
systemctl list-dependencies multi-user.target
Power off and reboot the system:
sudo systemctl poweroff
sudo systemctl reboot
Boot into rescue mode:
sudo systemctl rescue
Halt the system (does not power off the machine):
sudo systemctl halt
Control systemd on a remote system:
systemctl --host user_name@host_name command
4. Log Management: journalctl Command
View all log entries:
journalctl
View all log entries for the current boot:
journalctl -b
View only kernel entries:
journalctl -k
View only kernel entries for the current boot:
journalctl -k -b
View log entries for a specific unit (e.g., Apache):
journalctl -u apache2.service
View unit logs for the current boot:
journalctl -b -u apache2.service
View logs from the previous boot:
journalctl -b -1
View the list of the boots:
journalctl --list-boots
View logs within a time interval:
journalctl --since "2023-01-10 17:15:00"
journalctl --since "2023-01-10" --until "2023-01-11 03:00"
journalctl --since yesterday
journalctl --since 09:00 --until "1 hour ago"
journalctl -u apache2.service --since today
View log entries for a specific executable:
journalctl /usr/bin/bash
Output logs in JSON format:
journalctl -b -u apache2 -o json
journalctl -b -u apache2 -o json-pretty
Show the most recent 10 entries:
journalctl -n
Show the most recent 20 entries:
journalctl -n 20
Follow logs in real-time (similar to tail -f; press Ctrl+C to exit):
journalctl -f
Show disk usage of journal logs:
journalctl --disk-usage
Delete old logs to reduce size to a specified limit:
sudo journalctl --vacuum-size=1G
Delete logs older than a specified time:
sudo journalctl --vacuum-time=1years
5. Other systemd Components
systemd includes several additional components. Some notable ones are:
-
systemd-boot: A UEFI boot manager with basic configuration support. Integrates with
systemctland includes thebootctlcommand. -
systemd-cat: Adds records to the systemd journal via a pipeline.
echo "Test" | systemd-cat -p info -
systemd-localed: Manages system locale settings. Controlled via the
localectlcommand. -
systemd-logind: Manages user logins, tracks users and sessions, and handles device access for users.
-
systemd-machined: Detects and monitors virtual machines and containers. Includes the
machinectlcommand. -
systemd-mount: Manages
.mountand.automountunits. -
systemd-networkd: Handles network configuration. Configuration files are located in (in order of precedence):
/lib/systemd/network/run/systemd/network/etc/systemd/network
-
systemd-nspawn: Runs commands or operating systems in lightweight namespace containers, similar to
chrootin many respects. -
systemd-resolved: Provides network name resolution. Includes the
resolvectlcommand. -
systemd-sysusers: Creates system users and groups.
-
systemd-timesyncd: Synchronizes system time over the network with NTP servers. Includes the
timedatectlcommand. -
systemd-tmpfiles: Manages volatile and temporary files and directories (creates, deletes, cleans up).
-
systemd-udevd: Manages physical devices.
6. Creating a Custom Service
We will create a simple custom service that pings an IP address every 10 minutes. It logs an informational message if the ping succeeds, and an error message if it fails.
The service consists of a shell script placed in /usr/local/bin, a systemd unit file, and will be enabled, started, and tested.
6.1. Create the Shell Script
Create a script named ipcheck.sh:
nano ipcheck.sh
Add the following content:
#!/bin/bash
echo "ipcheck.service: Start. $(date)" | systemd-cat -p info
while true ; do
ping -q -w 1 192.168.1.1 > /dev/null
if [ $? = 0 ] ; then
echo "ipcheck.service: Ping to IP is OK. $(date)" | systemd-cat -p info
else
echo "ipcheck.service: Error cannot ping IP. $(date)" | systemd-cat -p err
fi
sleep 600
done
6.2. Copy the Script to /usr/local/bin
Make the script executable and copy it:
chmod +x ipcheck.sh
sudo cp ipcheck.sh /usr/local/bin
6.3. Create the Unit File
Use systemctl edit to create the service unit:
sudo systemctl edit --force --full ipcheck.service
This command opens an editor. Add the following configuration:
[Unit]
Description=IPCheck Demo Service
Wants=network.target
After=syslog.target network-online.target
[Service]
ExecStart=/usr/local/bin/ipcheck.sh
Restart=on-failure
RestartSec=20
KillMode=process
[Install]
WantedBy=multi-user.target
Save and exit the editor.
6.4. Enable and Start The Service
sudo systemctl enable ipcheck.service
sudo systemctl start ipcheck.service
6.5. Test the Service
Check the recent logs to verify the service is working:
sudo journalctl -n 20
