Systemd
Systemd Architecture
Section titled “Systemd Architecture”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]Design Principles
Section titled “Design Principles”- 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.
Unit Types
Section titled “Unit Types”A unit is the fundamental object that systemd manages. Each unit has a configuration file and a Type that determines its behavior.
| Unit Type | File Extension | Description |
|---|---|---|
| Service | .service | A system service (daemon or one-shot) |
| Target | .target | A synchronization point for grouping units |
| Timer | .timer | A timer for activating other units |
| Socket | .socket | A socket for socket activation |
| Mount | .mount | A file system mount point |
| Automount | .automount | An automount point (mount on access) |
| Path | .path | A path for path-based activation |
| Slice | .slice | A cgroup slice for resource management |
| Scope | .scope | An externally created process group |
| Swap | .swap | A swap device |
| Device | .device | A kernel device |
Finding Unit Files
Section titled “Finding Unit Files”Systemd searches for unit files in several directories, with later directories overriding earlier Ones:
# Show the search pathsystemctl 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)Viewing Units
Section titled “Viewing Units”# List all installed unit filessystemctl list-unit-files
# List all active unitssystemctl list-units
# List all active servicessystemctl list-units --type=service
# List failed unitssystemctl --failed
# List timerssystemctl list-timers --all
# Show unit configurationsystemctl cat nginx.service
# Show unit propertiessystemctl show nginx.service
# Show specific propertysystemctl show nginx.service -p ExecStartsystemctl show nginx.service -p CPUUsageNSecsystemctl show nginx.service -p MemoryCurrent
# Check unit dependenciessystemctl list-dependencies nginx.servicesystemctl list-dependencies nginx.service --reverse
# Check what requires a targetsystemctl list-dependencies multi-user.target --reverseService Unit Files
Section titled “Service Unit Files”A .service file defines how a service is started, stopped, and managed. The file consists of Sections in INI-style format.
Complete Service Unit File Example
Section titled “Complete Service Unit File Example”[Unit]Description=My Application ServiceDocumentation=https://example.com/docsAfter=network-online.targetWants=network-online.targetRequires=redis.service
[Service]Type=simpleUser=myappGroup=myappWorkingDirectory=/opt/myappExecStart=/usr/bin/python3 /opt/myapp/app.pyExecStartPost=/bin/sleep 1ExecReload=/bin/kill -HUP $MAINPIDRestart=on-failureRestartSec=5TimeoutStartSec=30TimeoutStopSec=30StandardOutput=journalStandardError=inherit
# HardeningProtectSystem=strictPrivateTmp=yesNoNewPrivileges=yesProtectHome=yesReadWritePaths=/var/lib/myapp
[Install]WantedBy=multi-user.target[Unit] Section
Section titled “[Unit] Section”| Directive | Description |
|---|---|
Description | Human-readable description |
Documentation | URL 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 |
[Service] Section — Service Type
Section titled “[Service] Section — Service Type”| Type | Behavior | Use Case |
|---|---|---|
simple (default) | ExecStart is the main process. Systemd considers it started immediately. | Most daemons |
exec | ExecStart is the main process. Systemd waits for it to fork and exit. | Daemons that double-fork |
forking | ExecStart forks a child and the parent exits. Systemd waits for the parent to exit. | Traditional daemons |
oneshot | ExecStart runs and exits. Systemd waits for it to finish. | Scripts, initialization tasks |
dbus | Service acquires a name on D-Bus. Systemd considers it started when the name appears. | D-Bus services |
notify | Service sends sd_notify() when ready. Systemd waits for the notification. | Modern daemons with sd_notify |
notify-reload | Like notifyBut supports sd_notify(RELOADING=1) for reload. | Daemons with reload support |
idle | Like simpleBut started after all active jobs are dispatched. | Avoids blocking boot output |
[Service] Section — Lifecycle Directives
Section titled “[Service] Section — Lifecycle Directives”[Service]# Main processExecStart=/usr/bin/myapp --config /etc/myapp/config.yaml
# Pre-start checkExecStartPre=/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-cleanupExecStopPost=/bin/rm -f /var/run/myapp/initialized
# EnvironmentEnvironment="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[Service] Section — Restart Policy
Section titled “[Service] Section — Restart Policy”| Directive | Behavior |
|---|---|
Restart=no | Never restart (default) |
Restart=on-success | Restart if the process exits cleanly (exit code 0) |
Restart=on-failure | Restart if the process exits with non-zero or signal |
Restart=on-abnormal | Restart on signal, timeout, or watchdog |
Restart=on-abort | Restart on signal (not clean exit) |
Restart=on-watchdog | Restart on watchdog timeout |
Restart=always | Always restart, regardless of exit status |
Restart=on-failureRestartSec=5 # wait 5 seconds between restartsStartLimitBurst=5 # allow 5 restarts within...StartLimitIntervalSec=60 # ...60 seconds before giving upsystemctl — Service Management
Section titled “systemctl — Service Management”# Start/stop/restartsystemctl start nginxsystemctl stop nginxsystemctl 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 nginxsystemctl disable nginx
# Enable and start in one commandsystemctl enable --now nginx
# Check statussystemctl status nginx
# Check if a service is activesystemctl is-active nginx # outputs: active / inactive / failed
# Check if enabled at bootsystemctl 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 filesystemctl edit --full nginx # copies to /etc/systemd/system/nginx.service
# Show service logsjournalctl -u nginxjournalctl -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 usagesystemctl status nginxsystemctl show nginx -p MemoryCurrentsystemctl show nginx -p CPUUsageNSecsystemctl show nginx -p TasksCurrent
# Reset failed statesystemctl reset-failed nginx
# Mask/unmask (prevent a service from starting, even manually)systemctl mask nginxsystemctl unmask nginxTargets
Section titled “Targets”Targets are synchronization points that group units. They replace the SysV runlevel concept.
Target Equivalents to Runlevels
Section titled “Target Equivalents to Runlevels”| SysV Runlevel | systemd Target | Description |
|---|---|---|
| 0 | poweroff.target | Halt/shutdown |
| 1 | rescue.target | Single-user mode |
| 2, 4 | multi-user.target | Multi-user, no GUI |
| 3 | multi-user.target | Multi-user, no GUI |
| 5 | graphical.target | Multi-user with GUI |
| 6 | reboot.target | Reboot |
| — | emergency.target | Emergency shell |
| — | default.target | Symlink to the default target |
# View current targetsystemctl get-default
# Set default targetsystemctl set-default multi-user.target
# Change target (switch runlevel)systemctl isolate multi-user.target
# List active targetssystemctl list-units --type=targetCustom Targets
Section titled “Custom Targets”# Create a custom targetsystemctl add-wants multi-user.target myapp.target
# Create a unit file for the target# /etc/systemd/system/myapp.target[Unit]Description=My Application StackRequires=myapp.service redis.service postgresql.serviceAfter=myapp.service redis.service postgresql.serviceJournal (journald)
Section titled “Journal (journald)”systemd-journald is the logging daemon that collects and stores log messages from the kernel, Systemd units, and standard output/error of services.
Journalctl Usage
Section titled “Journalctl Usage”# Show all logs (newest first)journalctl
# Show boot logsjournalctl -b # current bootjournalctl -b -1 # previous bootjournalctl -b -5 # five boots agojournalctl --list-boots # list all boots with timestamps
# Filter by unitjournalctl -u nginxjournalctl -u nginx -u php-fpm # multiple units
# Filter by timejournalctl --since "2024-01-15 10:00:00"journalctl --since "2 hours ago"journalctl --since yesterdayjournalctl --until "2024-01-15 12:00:00"
# Filter by priorityjournalctl -p err # error and abovejournalctl -p warning # warning and abovejournalctl -p debug # all messages
# Priority levels: emerg(0), alert(1), crit(2), err(3), warning(4), notice(5), info(6), debug(7)
# Filter by processjournalctl _PID=1234journalctl _COMM=nginxjournalctl _UID=33
# Output formatjournalctl -o json # JSONjournalctl -o json-pretty # pretty JSONjournalctl -o verbose # full metadatajournalctl -o cat # just the message (no metadata)
# Follow live logsjournalctl -fjournalctl -u nginx -f
# Show disk usagejournalctl --disk-usage
# Vacuum logs (free space)journalctl --vacuum-size=500Mjournalctl --vacuum-time=30djournalctl --vacuum-files=10
# Export to syslog formatjournalctl -o syslog
# Kernel messagesjournalctl -kJournal Configuration
Section titled “Journal Configuration”[Journal]Storage=auto # auto, persistent, volatile, noneCompress=yes # compress log entriesSeal=yes # forward-secure sealing (FSSEC)SystemMaxUse=500M # max disk space for system journalSystemKeepFree=1G # keep at least 1G freeSystemMaxFileSize=50M # max size per journal fileMaxRetentionSec=30day # keep logs for 30 daysMaxFileSec=1week # rotate weeklyForwardToSyslog=yes # also forward to traditional syslog