Skip to main content

systemd

systemd is the init system and service manager used by virtually all modern Linux distributions. As PID 1, it is the first process after the kernel boots and the parent of all other processes. It manages service lifecycle, logging, timers, and system state.

What Is systemd in Simple Terms

When a Linux server boots, the kernel starts exactly one process: PID 1. That process is responsible for starting everything else — all system services, all application daemons, all background jobs. On all modern Linux distributions (Ubuntu, Debian, RHEL, CentOS, Amazon Linux, Arch), PID 1 is systemd.

systemd replaced the older SysV init system and fundamentally changed how Linux service management works. Instead of shell scripts in /etc/init.d/, services are described in declarative unit files. Instead of sequential startup, services start in parallel where dependencies allow. Instead of syslog only, logs go to the journal (journald) with structured metadata.

systemd boot sequence:

◈ DIAGRAM
Kernel
|
v
PID 1: systemd starts
|
v
Read unit files
/usr/lib/systemd/system/
/etc/systemd/system/
|
v
Resolve dependencies
(After=, Requires=, Wants=)
|
v
Start units in parallel
(where dependencies allow)
|
+-- sshd.service
+-- postgresql.service
+-- nginx.service (after network.target)
+-- myapp.service (after postgresql.service)
|
v
multi-user.target reached -- server is ready

How It Works

systemd reads unit files that describe each service, then manages their lifecycle. It handles dependencies, restarts failures, and collects logs.

TEXT
Kernel boots
|
v
systemd (PID 1) starts
|
v
Reads unit files from:
/etc/systemd/system/ (admin-created, highest priority)
/usr/lib/systemd/system/ (package-installed)
|
v
Resolves dependencies (After=, Requires=, Wants=)
|
v
Starts services in parallel where possible
nginx start does NOT wait for postgresql start
unless nginx unit has: After=postgresql.service
|
v
Target reached: multi-user.target
Server is ready

Unit types:

TEXT
.service A daemon or one-shot process
.socket Network socket (activates a service on connection)
.timer Scheduled execution (replacement for cron)
.mount Filesystem mount point
.target Group of units (like a runlevel)
.path Filesystem path monitoring
Most common for DevOps: .service and .timer

Essential systemctl commands:

Bash
## Start, stop, restart a service
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx
## Reload config without restarting (sends SIGHUP)
sudo systemctl reload nginx
## Enable at boot (creates symlink in target's wants directory)
sudo systemctl enable nginx
sudo systemctl enable --now nginx ## enable AND start immediately
## Disable from boot
sudo systemctl disable nginx
## Check status
systemctl status nginx
## nginx.service - A high performance web server
## Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
## Active: active (running) since Mon 2024-01-15 10:00:00 UTC; 2h ago
## Process: 1100 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)
## Main PID: 1101 (nginx)
## Show all services and their state
systemctl list-units --type=service
systemctl list-units --type=service --state=failed
## Reload systemd after editing unit files
sudo systemctl daemon-reload

Reading journald logs:

Bash
## Logs for a specific service
journalctl -u nginx
## Follow logs live
journalctl -u nginx -f
## Last 50 lines
journalctl -u nginx -n 50
## Logs since a time
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx --since "2024-01-15 10:00" --until "2024-01-15 11:00"
## Only error and above
journalctl -u nginx -p err
## All logs without pager
journalctl -u nginx --no-pager | grep ERROR

Practical Commands

Bash
## The complete service management workflow
sudo systemctl daemon-reload ## after editing unit files
sudo systemctl enable myapp ## start at boot
sudo systemctl start myapp ## start now
systemctl status myapp ## verify running
journalctl -u myapp -f ## follow logs
sudo systemctl restart myapp ## restart
sudo systemctl stop myapp ## stop
sudo systemctl disable myapp ## do not start at boot

Troubleshooting

Symptom Command What to Look For
Service not starting journalctl -u servicename -n 50 Error messages from last start attempt
Service keeps restarting systemctl status servicename Restart count and exit code
Unit file change not picked up sudo systemctl daemon-reload Must reload after editing unit files
Boot slow systemd-analyze blame Services taking longest to start
Tip

systemctl status servicename is always the first command when a service is not working. It shows the active state, recent log lines, the PID, and the exit code if the service failed. The last few log lines alone resolve 80% of simple service failures.

Remember

After editing a systemd unit file, you must run sudo systemctl daemon-reload for systemd to pick up the changes. Editing the file without reloading means the changes are invisible to systemd — it still runs the old configuration.

Frequently Asked Questions

What specifically did systemd replace, and why did most distributions switch?

systemd replaced SysV init and, on some distros, Upstart — both of which started services sequentially via shell scripts in runlevel directories, which was slow and made expressing dependencies (start B only after A is actually ready, not just after A's script exits) awkward. systemd starts independent services in parallel, supports socket activation (deferring a service's start until its socket receives a connection), and provides a uniform way to declare dependencies, restart policies, and resource limits via unit files instead of ad hoc shell logic.

What's a common mistake when debugging a systemd service that won't start?

Only checking `systemctl status`, which often truncates the useful error, instead of running `journalctl -u <service> -xe` for the full log including the actual process's stderr output and systemd's own diagnostic context. Another frequent issue: editing a unit file directly under `/lib/systemd/system` instead of creating an override with `systemctl edit <service>` or a drop-in under `/etc/systemd/system/<service>.d/`, which gets silently overwritten on the next package upgrade.