Skip to content

Systemd

Systemd is a system and service manager for Linux, serving as the init system (PID 1) and providing A suite of tools for managing services, devices, mounts, timers, and more. It replaced the Traditional SysV init system and is used by default on virtually every major Linux distribution.

graph TD
    A[systemd PID 1] --> B[Service Manager]
    A --> C[Device Manager]
    A --> D[Mount Manager]
    A --> E[Timer Manager]
    A --> F[Socket Manager]
    A --> G[Target Manager]
    A --> H[Swap Manager]
    A --> I[Journal Daemon - journald]
    A --> J[Logind - User Session Manager]
    A --> K[udevd - Device Manager]
    A --> L[resolved - DNS Resolver]
    A --> M[Networkd - Network Manager]
    A --> N[timesyncd - NTP Client]
  • Socket activation: Services are started on-demand when a connection arrives on their socket, reducing boot time and resource usage.
  • Parallel startup: Dependencies are resolved, and services without dependencies start in parallel.
  • Unit-based configuration: Everything managed by systemd is represented as a “unit” with a declarative configuration file.
  • Cgroup tracking: Each service runs in its own cgroup, making resource management and cleanup reliable.
  • Journal: Structured logging with indexed, searchable log data.

A unit is the fundamental object that systemd manages. Each unit has a configuration file and a Type that determines its behavior.

Unit TypeFile ExtensionDescription
Service.serviceA system service (daemon or one-shot)
Target.targetA synchronization point for grouping units
Timer.timerA timer for activating other units
Socket.socketA socket for socket activation
Mount.mountA file system mount point
Automount.automountAn automount point (mount on access)
Path.pathA path for path-based activation
Slice.sliceA cgroup slice for resource management
Scope.scopeAn externally created process group
Swap.swapA swap device
Device.deviceA kernel device

Systemd searches for unit files in several directories, with later directories overriding earlier Ones:

Terminal window
# Show the search path
systemctl show -p UnitPath
# Typical search order:
# 1. /etc/systemd/system/ (administrator overrides)
# 2. /run/systemd/system/ (runtime configuration)
# 3. /usr/lib/systemd/system/ (package-installed units)
Terminal window
# List all installed unit files
systemctl list-unit-files
# List all active units
systemctl list-units
# List all active services
systemctl list-units --type=service
# List failed units
systemctl --failed
# List timers
systemctl list-timers --all
# Show unit configuration
systemctl cat nginx.service
# Show unit properties
systemctl show nginx.service
# Show specific property
systemctl show nginx.service -p ExecStart
systemctl show nginx.service -p CPUUsageNSec
systemctl show nginx.service -p MemoryCurrent
# Check unit dependencies
systemctl list-dependencies nginx.service
systemctl list-dependencies nginx.service --reverse
# Check what requires a target
systemctl list-dependencies multi-user.target --reverse

A .service file defines how a service is started, stopped, and managed. The file consists of Sections in INI-style format.

[Unit]
Description=My Application Service
Documentation=https://example.com/docs
After=network-online.target
Wants=network-online.target
Requires=redis.service
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/app.py
ExecStartPost=/bin/sleep 1
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
TimeoutStartSec=30
TimeoutStopSec=30
StandardOutput=journal
StandardError=inherit
# Hardening
ProtectSystem=strict
PrivateTmp=yes
NoNewPrivileges=yes
ProtectHome=yes
ReadWritePaths=/var/lib/myapp
[Install]
WantedBy=multi-user.target
DirectiveDescription
DescriptionHuman-readable description
DocumentationURL to documentation
After=Start after the listed units (ordering, not dependency)
Before=Start before the listed units
Requires=Hard dependency — if the listed unit fails, this unit fails
Wants=Soft dependency — start if available, continue if not
Requisite=Hard dependency — fail immediately if not already running
Conflicts=If the listed unit is running, this unit cannot start
PartOf=When the listed unit is stopped/restarted, this unit is too
TypeBehaviorUse Case
simple (default)ExecStart is the main process. Systemd considers it started immediately.Most daemons
execExecStart is the main process. Systemd waits for it to fork and exit.Daemons that double-fork
forkingExecStart forks a child and the parent exits. Systemd waits for the parent to exit.Traditional daemons
oneshotExecStart runs and exits. Systemd waits for it to finish.Scripts, initialization tasks
dbusService acquires a name on D-Bus. Systemd considers it started when the name appears.D-Bus services
notifyService sends sd_notify() when ready. Systemd waits for the notification.Modern daemons with sd_notify
notify-reloadLike notifyBut supports sd_notify(RELOADING=1) for reload.Daemons with reload support
idleLike simpleBut started after all active jobs are dispatched.Avoids blocking boot output

[Service] Section — Lifecycle Directives

Section titled “[Service] Section — Lifecycle Directives”
[Service]
# Main process
ExecStart=/usr/bin/myapp --config /etc/myapp/config.yaml
# Pre-start check
ExecStartPre=/usr/bin/myapp --validate-config
# Post-start (runs after ExecStart)
ExecStartPost=/usr/bin/touch /var/run/myapp/initialized
# Reload (sent on systemctl reload)
ExecReload=/bin/kill -HUP $MAINPID
# Stop (default: SIGTERM)
ExecStop=/usr/bin/myapp --shutdown
# Stop post-cleanup
ExecStopPost=/bin/rm -f /var/run/myapp/initialized
# Environment
Environment="NODE_ENV=production"
Environment="LOG_LEVEL=info"
EnvironmentFile=/etc/myapp/environment
# Pass environment file (allows variable expansion)
EnvironmentFile=-/etc/myapp/env.local # - means file is optional
DirectiveBehavior
Restart=noNever restart (default)
Restart=on-successRestart if the process exits cleanly (exit code 0)
Restart=on-failureRestart if the process exits with non-zero or signal
Restart=on-abnormalRestart on signal, timeout, or watchdog
Restart=on-abortRestart on signal (not clean exit)
Restart=on-watchdogRestart on watchdog timeout
Restart=alwaysAlways restart, regardless of exit status
Restart=on-failure
RestartSec=5 # wait 5 seconds between restarts
StartLimitBurst=5 # allow 5 restarts within...
StartLimitIntervalSec=60 # ...60 seconds before giving up
Terminal window
# Start/stop/restart
systemctl start nginx
systemctl stop nginx
systemctl restart nginx
# Reload configuration (sends SIGHUP or uses ExecReload)
systemctl reload nginx
# Reload daemon configuration (after editing unit files)
systemctl daemon-reload
# Enable/disable (start on boot)
systemctl enable nginx
systemctl disable nginx
# Enable and start in one command
systemctl enable --now nginx
# Check status
systemctl status nginx
# Check if a service is active
systemctl is-active nginx # outputs: active / inactive / failed
# Check if enabled at boot
systemctl is-enabled nginx # outputs: enabled / disabled
# Edit unit file (opens override file)
systemctl edit nginx # creates /etc/systemd/system/nginx.service.d/override.conf
# Edit the full unit file
systemctl edit --full nginx # copies to /etc/systemd/system/nginx.service
# Show service logs
journalctl -u nginx
journalctl -u nginx -f # follow (like tail -f)
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since "2024-01-01" --until "2024-01-02"
# Show service cgroup resource usage
systemctl status nginx
systemctl show nginx -p MemoryCurrent
systemctl show nginx -p CPUUsageNSec
systemctl show nginx -p TasksCurrent
# Reset failed state
systemctl reset-failed nginx
# Mask/unmask (prevent a service from starting, even manually)
systemctl mask nginx
systemctl unmask nginx

Targets are synchronization points that group units. They replace the SysV runlevel concept.

SysV Runlevelsystemd TargetDescription
0poweroff.targetHalt/shutdown
1rescue.targetSingle-user mode
2, 4multi-user.targetMulti-user, no GUI
3multi-user.targetMulti-user, no GUI
5graphical.targetMulti-user with GUI
6reboot.targetReboot
emergency.targetEmergency shell
default.targetSymlink to the default target
Terminal window
# View current target
systemctl get-default
# Set default target
systemctl set-default multi-user.target
# Change target (switch runlevel)
systemctl isolate multi-user.target
# List active targets
systemctl list-units --type=target
Terminal window
# Create a custom target
systemctl add-wants multi-user.target myapp.target
# Create a unit file for the target
# /etc/systemd/system/myapp.target
[Unit]
Description=My Application Stack
Requires=myapp.service redis.service postgresql.service
After=myapp.service redis.service postgresql.service

systemd-journald is the logging daemon that collects and stores log messages from the kernel, Systemd units, and standard output/error of services.

Terminal window
# Show all logs (newest first)
journalctl
# Show boot logs
journalctl -b # current boot
journalctl -b -1 # previous boot
journalctl -b -5 # five boots ago
journalctl --list-boots # list all boots with timestamps
# Filter by unit
journalctl -u nginx
journalctl -u nginx -u php-fpm # multiple units
# Filter by time
journalctl --since "2024-01-15 10:00:00"
journalctl --since "2 hours ago"
journalctl --since yesterday
journalctl --until "2024-01-15 12:00:00"
# Filter by priority
journalctl -p err # error and above
journalctl -p warning # warning and above
journalctl -p debug # all messages
# Priority levels: emerg(0), alert(1), crit(2), err(3), warning(4), notice(5), info(6), debug(7)
# Filter by process
journalctl _PID=1234
journalctl _COMM=nginx
journalctl _UID=33
# Output format
journalctl -o json # JSON
journalctl -o json-pretty # pretty JSON
journalctl -o verbose # full metadata
journalctl -o cat # just the message (no metadata)
# Follow live logs
journalctl -f
journalctl -u nginx -f
# Show disk usage
journalctl --disk-usage
# Vacuum logs (free space)
journalctl --vacuum-size=500M
journalctl --vacuum-time=30d
journalctl --vacuum-files=10
# Export to syslog format
journalctl -o syslog
# Kernel messages
journalctl -k
/etc/systemd/journald.conf
[Journal]
Storage=auto # auto, persistent, volatile, none
Compress=yes # compress log entries
Seal=yes # forward-secure sealing (FSSEC)
SystemMaxUse=500M # max disk space for system journal
SystemKeepFree=1G # keep at least 1G free
SystemMaxFileSize=50M # max size per journal file
MaxRetentionSec=30day # keep logs for 30 days
MaxFileSec=1week # rotate weekly
ForwardToSyslog=yes # also forward to traditional syslog