Systemd Tutorial for Beginners: Units, Services, Targets, and systemctl

Deepak Prasad
Tested on Ubuntu 26.04 LTS (systemd 257)
Package systemd 257.4-1ubuntu3.2
Applies to RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora, Debian, Ubuntu, and other distributions with systemd
Privilege sudo or root for most systemctl changes; read-only inspection often works as a normal user
Scope Conceptual introduction to systemd units, targets, dependencies, and first systemctl checks. Points to dedicated guides for listing services, targets, logs, timers, and writing unit files—not a full command reference.
Related guides systemctl command
List services with systemctl
systemd targets
journalctl command
Create a systemd service

Systemd is the system and service manager on most modern Linux distributions. It brings the host to a usable state during boot, starts and stops daemons, tracks dependencies, and exposes tools such as systemctl, journalctl, and systemd-analyze.

If you are new to systemd, start with one idea: systemd manages units. A service is a unit, a target is a unit, a socket is a unit, and a timer is a unit. systemctl inspects and controls those units. This page explains how the pieces fit together and where to go for command depth, so it does not repeat the full systemctl command reference or the list services with systemctl walkthrough.

The examples below were tested on Ubuntu 26.04 with systemd 257. Your service names, default target, and enabled units will differ.


First commands to learn

These are the inspection commands worth memorizing before you write custom units:

Task Command
Check systemd version systemctl --version
Check overall system state systemctl is-system-running
List failed units systemctl --failed
Show default boot target systemctl get-default
Check one service systemctl status ssh.service
Read recent service logs journalctl -u ssh.service -n 20
Validate a unit file systemd-analyze verify /path/to/unit.service

Enable, disable, mask, and start or stop units through the same systemctl tool; the systemctl command cheat sheet covers those subcommands with examples.


Check systemd version and system state

Confirm the systemd build on the host before you follow distribution-specific documentation:

bash
systemctl --version
output
systemd 257 (257.4-1ubuntu3.2)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +IPE +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBCRYPTSETUP_PLUGINS +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK +BTF -XKBCOMMON -UTMP +SYSVINIT +LIBARCHIVE

Ask whether the manager considers the system healthy:

bash
systemctl is-system-running
output
degraded

degraded means at least one unit failed or is otherwise unhealthy. The host may still be usable. When you need the failing unit names, list them explicitly:

bash
systemctl --failed --no-pager

Understand systemd unit types

A unit is a named object systemd can load, start, and track. The suffix shows the type:

Unit type Example Purpose
.service ssh.service A daemon or process
.target multi-user.target A boot state or grouping of units
.socket ssh.socket Socket activation for a service
.timer apt-daily.timer Time-based activation; see systemd timers
.mount home.mount Filesystem mount unit
.path cups.path Start a unit when a path changes
.slice system.slice Resource-management grouping
.scope transient scope Externally created process grouping

Unit files are plain text. Administrators usually drop overrides under /etc/systemd/system, while distribution packages ship units under /usr/lib/systemd/system or /lib/systemd/system. For mount units instead of fstab, see mount a partition using systemd and mount filesystems in order with systemd.


Inspect one service end to end

Pick a daemon you know is running and read it the way systemd sees it. On this host, ssh.service is a useful example:

bash
systemctl status ssh.service --no-pager
output
● ssh.service - OpenBSD Secure Shell server
     Loaded: loaded (/usr/lib/systemd/system/ssh.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-06-07 13:55:41 IST; 7h ago
TriggeredBy: ● ssh.socket
   Main PID: 1606 (sshd)
     CGroup: /system.slice/ssh.service
             └─1606 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"

The Loaded line shows which unit file systemd used and whether the unit is enabled at boot. Active shows the runtime state. When you need the exact file contents and any drop-ins, ask systemd directly:

bash
systemctl cat ssh.service --no-pager

That output is safer than opening paths by hand because it reflects what systemd actually loaded. For listing many services, filtering enabled versus running units, and reading list-unit-files output, use the list services with systemctl guide instead of repeating those commands here.


Targets and boot state

A target is a unit that represents a system state. multi-user.target is the usual non-graphical multi-user state; graphical.target adds display manager services on desktop systems.

One quick check shows what systemd will aim for on the next boot:

bash
systemctl get-default
output
graphical.target

default.target is normally a symlink under /etc/systemd/system/ that points at the real target, such as multi-user.target or graphical.target. Listing active targets, changing the default, switching with isolate, and using rescue or emergency mode are covered in manage systemd targets in Linux so this tutorial does not duplicate that workflow.


Wants, Requires, Conflicts, Before, and After

Dependency directives answer two different questions: what must run, and in what order.

Directive Meaning
Wants= Start listed units too, but do not fail this unit just because a wanted unit fails
Requires= Stronger dependency; if the required unit fails to start, this unit is affected
Conflicts= Negative relationship; conflicting units cannot run together
Before= Ordering only: this unit starts before the listed unit
After= Ordering only: this unit starts after the listed unit

A common beginner mistake is treating After=network.target as a dependency. It controls ordering, not requirement. Combine After= with Wants= or Requires= when another unit must actually be up.

To see what a target pulls in, run systemctl list-dependencies multi-user.target. The systemd targets guide explains how that tree relates to boot and recovery modes.


Read service logs with journalctl

Systemd stores service output in the journal. One unit is enough to confirm the path works:

bash
journalctl -u ssh.service -n 5 --no-pager
output
Jun 07 14:27:41 server1 sshd-session[14020]: pam_unix(sshd:session): session opened for user golinuxcloud(uid=1000) by golinuxcloud(uid=0)
Jun 07 14:28:12 server1 sshd-session[14502]: Accepted publickey for golinuxcloud from 10.0.2.2 port 56873 ssh2: RSA SHA256:QctH5c77yvxCJMG6WUQfAfwvfxRR4VBhFK+1rAFsoCY
Jun 07 14:28:12 server1 sshd-session[14502]: pam_unix(sshd:session): session opened for user golinuxcloud(uid=1000) by golinuxcloud(uid=0)

Filtering by boot, time range, priority, and multiple units belongs in the journalctl command guide. For how journald stores logs and persistent storage options, see systemd-journald logging and enable persistent journald logging.


Analyze boot time with systemd-analyze

When boot feels slow, systemd-analyze critical-chain shows which units sat on the critical path:

bash
systemd-analyze critical-chain --no-pager
output
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

graphical.target @1min 54.276s
└─power-profiles-daemon.service @1min 54.024s +250ms
  └─multi-user.target @1min 54.015s
    └─plymouth-quit-wait.service @11.932s +1min 42.081s
      └─systemd-user-sessions.service @11.840s +65ms
        └─network.target @11.769s
          └─NetworkManager.service @8.197s +3.569s

A long line is not always a problem; some units wait by design. Use this view to decide where deeper investigation is worth the time.


Validate a unit file before you install it

Before copying a custom unit into /etc/systemd/system/, check syntax with systemd-analyze verify. A minimal oneshot example:

ini
[Unit]
Description=GoLinuxCloud demo oneshot service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/bin/printf systemd-demo-ok\n

[Install]
WantedBy=multi-user.target

Save that as /tmp/glc-systemd-demo.service, then validate it:

bash
systemd-analyze verify /tmp/glc-systemd-demo.service
echo "verify exit=$?"
output
verify exit=0

verify exit=0 means the file passed static checks. Installing the unit, writing [Service] and [Install] sections, and running daemon-reload are covered in create a systemd service in Linux. For boot or shutdown scripts, see run a script at startup or run a script before shutdown. For calendar jobs, compare systemd timers with crontab.


Test work with systemd-run

systemd-run starts a transient unit under /run/systemd/transient/, which is useful when you want to test a command without installing a permanent unit file:

bash
systemd-run --unit=glc-systemd-demo-sleep /bin/sleep 20
output
Running as unit: glc-systemd-demo-sleep.service; invocation ID: 0f3abe383ea64c87acef24ec5f365441

Confirm the transient unit appeared:

bash
systemctl status glc-systemd-demo-sleep.service --no-pager

The status line Transient: yes confirms systemd will discard the unit when it finishes. Stop it early when you are done testing:

bash
systemctl stop glc-systemd-demo-sleep.service

Where to go next

Your next task Dedicated guide
Full systemctl syntax and troubleshooting systemctl command
List running, failed, enabled, or inactive services List services with systemctl
Change default target, isolate, rescue, emergency systemd targets
Filter logs by boot, time, unit, priority journalctl command
Write and enable a custom .service unit Create a systemd service
Schedule recurring jobs systemd timers
Run a service as a specific user systemd service as user or group

References


Summary

Systemd organizes Linux boot and runtime administration around units. Service units run processes, target units describe boot states such as multi-user.target or graphical.target, and other unit types handle mounts, sockets, and timers. systemctl is the primary inspection and control tool; journalctl reads service logs; systemd-analyze checks unit syntax and boot timing.

This beginner tutorial stays at the concept layer: unit types, dependency keywords, one full service inspection, and safe validation with systemd-analyze verify. When you need command breadth, service lists, target changes, log filters, or a complete custom unit walkthrough, use the dedicated guides linked above rather than treating this page as the only systemd reference on the site.


Frequently Asked Questions

1. What is systemd in Linux?

systemd is the system and service manager used by many Linux distributions. It starts the system, manages services, handles dependencies, tracks units, and provides tools such as systemctl and journalctl.

2. What is a systemd unit?

A systemd unit is a configuration object managed by systemd. Unit types include service, target, socket, mount, timer, path, slice, scope, device, automount, and swap units.

3. What is the difference between a service and a target in systemd?

A service unit describes a process or daemon. A target unit groups other units and represents a system state, such as multi-user.target or graphical.target.

4. How do I check the default boot target in systemd?

Use systemctl get-default. The default target is commonly represented through default.target, which aliases or links to a real target such as multi-user.target or graphical.target.

5. If a systemd system uses multi-user.target as the default boot target, which file is the default target symlink?

The default target is normally represented by /etc/systemd/system/default.target, which points or aliases to the selected target such as multi-user.target. The target unit file itself is commonly under /usr/lib/systemd/system or /lib/systemd/system depending on the distribution.

6. How do I check logs for a systemd service?

Use journalctl -u service-name.service. Add -n 50 for recent lines and --no-pager for non-interactive output. For filters by boot, time, and priority, see the dedicated journalctl guide linked from this tutorial.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration