Systemd#
Introduction#
Systemd is the standard init system and service manager for most modern Linux distributions including Ubuntu, Debian, Fedora, CentOS, and Arch Linux. It replaces the traditional SysV init system with a more powerful and flexible approach to managing system startup, services, logging, and system state.
Systemd uses unit files to define services, timers, mount points, and other system resources. These declarative configuration files specify dependencies, execution parameters, and restart behavior, making service management more predictable and easier to debug than shell scripts.
Services Management#
The systemctl command is the primary tool for controlling systemd services.
It allows administrators to start, stop, restart, enable, and disable services,
as well as query their status and manage dependencies. Understanding these
commands is essential for Linux system administration.
# Start/stop/restart a service
$ systemctl start app.service
$ systemctl stop app.service
$ systemctl restart app.service
# Reload service configuration (without restart)
$ systemctl reload app.service
# Reload systemd after modifying unit files
$ systemctl daemon-reload
# Enable/disable service at boot
$ systemctl enable app.service
$ systemctl disable app.service
# Check service status
$ systemctl status app.service
$ systemctl is-active app.service
$ systemctl is-enabled app.service
# List units
$ systemctl list-units # all loaded units
$ systemctl list-units --type=service # only services
$ systemctl list-units --state=failed # failed units
$ systemctl list-unit-files # all installed unit files
# Show unit dependencies
$ systemctl list-dependencies app.service
# Mask/unmask (completely disable a service)
$ systemctl mask app.service
$ systemctl unmask app.service
Viewing Logs with journalctl#
Systemd includes a centralized logging system called the journal, which collects
logs from all services, the kernel, and system messages. The journalctl
command provides powerful filtering and querying capabilities that make
troubleshooting much easier than parsing traditional log files in /var/log.
The journal stores logs in a binary format with rich metadata including timestamps, priority levels, unit names, and process IDs. This enables efficient filtering by service, time range, or severity level.
# View logs for a service
$ journalctl -u app.service
# Follow logs in real-time (like tail -f)
$ journalctl -u app.service -f
# Show logs since last boot
$ journalctl -u app.service -b
# Show logs from last hour
$ journalctl -u app.service --since "1 hour ago"
# Show logs between dates
$ journalctl -u app.service --since "2024-01-01" --until "2024-01-02"
# Filter by priority (emerg, alert, crit, err, warning, notice, info, debug)
$ journalctl -u app.service -p err
# Show kernel messages (like dmesg)
$ journalctl -k
# Show disk usage by journal
$ journalctl --disk-usage
# Clean old logs (keep last 1G)
$ journalctl --vacuum-size=1G
# Clean logs older than 2 weeks
$ journalctl --vacuum-time=2weeks
Service Unit File#
A systemd service unit file is a configuration file that defines how to manage
a background service or daemon. Unit files use an INI-style format with three
main sections: [Unit] for metadata and dependencies, [Service] for
process execution parameters, and [Install] for installation targets.
Place custom unit files in /etc/systemd/system/ for system services. After
creating or modifying a unit file, run systemctl daemon-reload to reload
the systemd configuration.
# /etc/systemd/system/app.service
#
# $ systemctl daemon-reload
# $ systemctl enable app.service
# $ systemctl start app.service
[Unit]
Description=My Application
After=network.target
Wants=network-online.target
[Service]
Type=simple
User=appuser
Group=appgroup
WorkingDirectory=/path/to/app
ExecStart=/usr/bin/python3 app.py
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=10
# Environment variables
Environment=NODE_ENV=production
EnvironmentFile=/etc/app/env
# Security hardening options
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
Service Types#
The Type= directive tells systemd how the service notifies that it has
finished starting. Choosing the correct type ensures systemd accurately tracks
the service state and manages dependencies properly.
Type=simple Default. Process started by ExecStart is the main process.
Type=forking Process forks and parent exits. Use with PIDFile=.
Type=oneshot Process exits after completing. Use for scripts.
Type=notify Like simple, but service sends notification when ready.
Type=idle Like simple, but waits until other jobs finish.
Restart Policies#
The Restart= directive controls when systemd automatically restarts a
service after it exits. Use RestartSec= to add a delay between restart
attempts, preventing rapid restart loops that could overwhelm the system.
Restart=no Don't restart (default)
Restart=on-success Restart only on clean exit (exit code 0)
Restart=on-failure Restart on non-zero exit, signal, timeout
Restart=on-abnormal Restart on signal, timeout, watchdog
Restart=always Always restart regardless of exit status
Timer Unit File#
Systemd timers are a modern replacement for cron jobs, offering better integration with the service manager, logging, and dependency handling. A timer unit activates a corresponding service unit based on time events. Unlike cron, timers can trigger on boot, on service activation, or on calendar schedules.
Each timer requires a matching service file with the same base name (e.g.,
backup.timer triggers backup.service).
Managing Timers#
# List all active timers with next/last run times
$ systemctl list-timers
# List all timers including inactive
$ systemctl list-timers --all
# Show when a specific timer will next execute
$ systemctl list-timers backup.timer
# Example output:
# NEXT LEFT LAST PASSED UNIT ACTIVATES
# Mon 2024-01-08 02:00:00 UTC 5h left Sun 2024-01-07 02:00:00 UTC 18h ago backup.timer backup.service
# Enable and start a timer
$ systemctl enable backup.timer
$ systemctl start backup.timer
# Check timer status
$ systemctl status backup.timer
# Manually trigger the associated service (for testing)
$ systemctl start backup.service
# View timer logs
$ journalctl -u backup.timer
$ journalctl -u backup.service
Timer Unit Example#
# /etc/systemd/system/backup.timer
#
# $ systemctl daemon-reload
# $ systemctl enable backup.timer
# $ systemctl start backup.timer
[Unit]
Description=Daily backup timer
[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=1h
[Install]
WantedBy=timers.target
# /etc/systemd/system/backup.service
[Unit]
Description=Backup job
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Timer Options#
Timers support two types of triggers: monotonic timers that fire relative to
a specific event (boot, activation), and realtime timers that fire based on
calendar time. Use Persistent=true to run missed jobs after system downtime.
OnBootSec=10min Run 10 minutes after boot
OnUnitActiveSec=1h Run 1 hour after service last activated
OnCalendar=daily Run daily at midnight
OnCalendar=weekly Run weekly on Monday at midnight
OnCalendar=hourly Run every hour
OnCalendar=*:0/15 Run every 15 minutes
Persistent=true Run immediately if missed while system was off
RandomizedDelaySec= Add random delay to prevent thundering herd
Calendar Syntax Examples#
Systemd calendar expressions use the format DayOfWeek Year-Month-Day
Hour:Minute:Second. Use * as a wildcard for any value and / for
intervals. The systemd-analyze calendar command validates and normalizes
calendar expressions.
*-*-* 00:00:00 Daily at midnight
*-*-* *:00:00 Every hour
*-*-* *:*:00 Every minute
Mon *-*-* 00:00:00 Every Monday at midnight
Mon,Fri *-*-* 17:00 Monday and Friday at 5pm
*-*-01 00:00:00 First day of every month
*-01-01 00:00:00 January 1st every year
2024-*-* 00:00:00 Every day in 2024
# Test and validate calendar expressions
$ systemd-analyze calendar "Mon *-*-* 09:00"
User Services#
Systemd supports user-level services that run without root privileges in the user’s session. User services are ideal for personal daemons, development servers, or user-specific background tasks like syncing or notifications.
By default, user services only run while the user is logged in. Enable lingering to keep services running after logout, which is essential for servers or long-running background tasks.
# Enable lingering (services run without login)
$ sudo loginctl enable-linger $USER
# Create user service directory
$ mkdir -p ~/.config/systemd/user/
# Place unit files in ~/.config/systemd/user/
# Manage with --user flag
$ systemctl --user daemon-reload
$ systemctl --user enable app.service
$ systemctl --user start app.service
$ systemctl --user status app.service
# View user service logs
$ journalctl --user -u app.service -f
Enable persistent journal storage to preserve user service logs across reboots:
$ sudo vim /etc/systemd/journald.conf
[Journal]
Storage=persistent
$ sudo systemctl restart systemd-journald
Analyzing Boot Performance#
Systemd provides built-in tools to analyze boot performance and identify slow services that delay system startup. Use these commands to optimize boot time and diagnose startup issues.
# Show total boot time breakdown
$ systemd-analyze
# Show time taken by each unit (sorted by duration)
$ systemd-analyze blame
# Show critical chain (services blocking boot)
$ systemd-analyze critical-chain
# Generate visual boot chart as SVG
$ systemd-analyze plot > boot.svg
Core Dumps with coredumpctl#
Systemd includes systemd-coredump which automatically captures and stores
core dumps when processes crash. The coredumpctl command lets you list,
inspect, and debug these core dumps. This is invaluable for debugging crashes
in C/C++ applications running as systemd services.
# List all core dumps
$ coredumpctl list
# List core dumps for a specific executable
$ coredumpctl list /usr/bin/myapp
# Show info about the most recent core dump
$ coredumpctl info
# Show info for a specific PID
$ coredumpctl info 12345
# Launch debugger (gdb) on most recent core dump
$ coredumpctl debug
# Debug a specific executable's core dump
$ coredumpctl debug /usr/bin/myapp
# Export core dump to a file
$ coredumpctl dump -o core.dump
# Export core dump for specific PID
$ coredumpctl dump 12345 -o core.dump
Configure core dump storage in /etc/systemd/coredump.conf:
[Coredump]
Storage=external # external, journal, or none
Compress=yes # compress stored core dumps
MaxUse=1G # max disk space for core dumps
KeepFree=1G # min free space to maintain
ProcessSizeMax=2G # max size of process to dump
Useful Paths#
/etc/systemd/system/ System unit files (admin-created)
/usr/lib/systemd/system/ System unit files (package-installed)
/run/systemd/system/ Runtime unit files (temporary)
~/.config/systemd/user/ User unit files
/etc/systemd/journald.conf Journal configuration
/etc/systemd/coredump.conf Core dump configuration
/etc/systemd/system.conf System manager configuration
/var/lib/systemd/coredump/ Stored core dumps