systemd
is an initialization system and service manager that has emerged as the new standard for Linux distributions. Though the learning curve for systemd
can be steep due to its intricate adoption, mastering it can greatly streamline server administration tasks. Familiarizing yourself with the tools and daemons comprised within systemd
will enable you to unlock its potential and flexibility, or at the very least, perform tasks more seamlessly.
In this guide, we will look at the systemctl
command, a vital management instrument for governing the initialization system. We will explore techniques for managing services, checking statuses, modifying system states, and interacting with configuration files.
It's important to note that not all Linux distributions have implemented systemd
as their default initialization system. If you encounter the error bash: systemctl is not installed when following this guide, it is probable that your machine employs a different initialization system.
Managing Services
The main function of an initialization system is to launch components that need to be initialized following the booting of the Linux kernel (commonly referred to as "userland" components). Additionally, the initialization system is responsible for managing services and daemons while the system is operating. With this context, we will commence with several basic service management procedures.
Within systemd
, the primary subjects of most actions are "units," which signify resources that systemd
can oversee. Units are categorized by the kind of resource they embody and are defined using files called unit files. The category of each unit can be deduced from the suffix appended to the file.
For service management operations, the target units will be service units, which possess unit files with a .service suffix. Nevertheless, in the majority of service management commands, you can exclude the .service suffix, as systemd
can easily discern that you likely intend to interact with a service utilizing service management commands.
Starting and Stopping Services
To start a systemd
service with the instructions in the service unit file, use the start
command. If operating as a non-root user, sudo
will be necessary, as this action impacts the state of the operating system:
sudo systemctl start application.service
As previously noted, systemd
will search for *.service files for service management commands, permitting the command to be input like this:
sudo systemctl start application
While this format is suitable for general administration, we will utilize the .service suffix for the subsequent commands to explicitly denote the target being worked with.
To halt an active service, apply the stop
command:
sudo systemctl stop application.service
Restarting and Reloading
To restart a functioning service, employ the restart
command:
sudo systemctl restart application.service
If the application concerned can reload configuration files (without restarting), initiate this process using the reload
command:
sudo systemctl reload application.service
If uncertain whether the service can reload its configuration, issue the reload-or-restart
command. This will lead to the configuration being reloaded if possible. If not, the service will restart to apply the updated configuration:
sudo systemctl reload-or-restart application.service
Enabling and Disabling Services
The aforementioned commands are helpful for initiating or terminating services during the present session. To instruct systemd
to automatically start services at boot, they must be enabled.
To start a service at boot, utilize the enable
command:
sudo systemctl enable application.service
This action generates a symbolic link from a system copy of the service file (typically in /lib/systemd/system or /etc/systemd/system) to the location on disk where systemd
searches for files to autorun (usually /etc/systemd/system/some_target.target.wants). We will look at what a target is later in this manual).
To disable automatic start of a service, input:
sudo systemctl disable application.service
This will eliminate the symbolic link that signified the service should initiate automatically.
Keep in mind that enabling the service will not activate it in the current session. To both start the service and enable it at boot, you must provide both commands, start
and enable
.
Checking the status of services
To check the status of a service on your system, utilize the status
command:
systemctl status application.service
This provides information on the service's status, control group hierarchy, and initial log entries.
For instance, when verifying the status of a Nginx server, the following output might be displayed:
Output
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2015-01-27 19:41:23 EST; 22h ago
Main PID: 495 (nginx)
CGroup: /system.slice/nginx.service
├─495 nginx: master process /usr/bin/nginx -g pid /run/nginx.pid; error_log stderr;
└─496 nginx: worker process
Jan 27 19:41:23 desktop systemd[1]: Starting A high performance web server and a reverse proxy server...
Jan 27 19:41:23 desktop systemd[1]: Started A high performance web server and a reverse proxy server.
This offers a comprehensive overview of the application's current status and alerts you to any issues or necessary actions.
There are also methods to check for specific statuses. For instance, to determine whether a module is presently active, use the is-active
command:
systemctl is-active application.service
This returns the module's current status, typically active or inactive. If active, the exit code will be "0," making the result easier to parse in shell scripts.
To see if a module is enabled, apply the is-enabled
command:
systemctl is-enabled application.service
This displays whether the service is enabled or disabled and sets the output code to "0" or "1" based on the command's inquiry.
The third check involves determining if the module is in a failed state, indicating an issue with starting the unit:
systemctl is-failed application.service
This returns active if functioning correctly or failed in case of an error. If the module was deliberately stopped, it may return unknown or inactive. An output status of "0" signifies a failure, while an output status of "1" represents a different status.
System State Overview
While the previous commands are useful for managing single services, they offer limited insight into the overall system state. Several systemctl
commands can help provide this information.
Listing Current Units
To display a list of all active units recognized by systemd
, use the list-units
command:
systemctl list-units
This reveals a list of all units currently active within the system. The output may appear as follows:
Output
UNIT LOAD ACTIVE SUB DESCRIPTION
atd.service loaded active running ATD daemon
avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
dbus.service loaded active running D-Bus System Message Bus
dcron.service loaded active running Periodic Command Scheduler
dkms.service loaded active exited Dynamic Kernel Modules System
[email protected] loaded active running Getty on tty1
. . .
The output consists of the following columns:
-
UNIT: The
systemd
unit name -
LOAD: Indicates if the unit’s configuration has been parsed by
systemd
. The configuration of loaded units is stored in memory. - ACTIVE: A summary state indicating whether the unit is active. This typically reveals whether the unit has started successfully.
- SUB: A more detailed state providing additional information about the unit. This often varies depending on the unit type, state, and how the unit operates.
- DESCRIPTION: A brief description of what the unit is/does.
By default, the list-units
command only shows active units. Thus, all entries will display loaded in the LOAD column and active in the ACTIVE column. Executing systemctl
without additional commands produces the same display:
systemctl
To obtain different information, add extra flags. For example, use the --all
flag to see all units systemd
has loaded (or attempted to load), irrespective of their current activity:
systemctl list-units --all
This displays any unit that systemd
loaded or tried to load, regardless of its system state. Some units become inactive after running, while others may not be found on disk after systemd
attempts to load them.
You can use other flags to filter the results. For example, the --state=
flag specifies the LOAD, ACTIVE, or SUB states to display. Keep the --all
flag so that systemctl
shows non-active units:
systemctl list-units --all --state=inactive
Another common filter is the --type=
filter. To display only units of a particular type, use:
systemctl list-units --type=service
Listing All Unit Files
The list-units
command only displays units that systemd
has tried to parse and load into memory. Since systemd
only reads the units it deems necessary, this list may not include all available units. To view every unit file within systemd
paths, including those not attempted to load, use the list-unit-files
command:
systemctl list-unit-files
Units represent resources known to systemd
. As not all unit definitions are necessarily read in this view, it only presents information about the files themselves. The output features two columns: the unit file and its state.
Output
UNIT FILE STATE
proc-sys-fs-binfmt_misc.automount static
dev-hugepages.mount static
dev-mqueue.mount static
proc-fs-nfsd.mount static
proc-sys-fs-binfmt_misc.mount static
sys-fs-fuse-connections.mount static
sys-kernel-config.mount static
sys-kernel-debug.mount static
tmp.mount static
var-lib-nfs-rpc_pipefs.mount static
org.cups.cupsd.path enabled
. . .
States are typically enabled, disabled, static, or masked. In this context, static means the unit file lacks an install section required to enable a unit. As such, these units cannot be enabled. This usually implies that the unit carries out a one-time action or serves as a dependency for another unit and should not be run independently.
Next, we'll discuss the meaning of masked.
Unit Management
We've been working with services and displaying unit and unit file information that systemd
recognizes. To learn more specific information about units, we can use additional commands.
Displaying a Unit File
To display the unit file that systemd
has loaded into its system, utilize the cat
command (introduced in systemd
version 209). For example, to display the unit file for the atd scheduling daemon, enter:
systemctl cat atd.service
Output
[Unit]
Description=ATD daemon
[Service]
Type=forking
ExecStart=/usr/bin/atd
[Install]
WantedBy=multi-user.target
The output reveals the unit file as recognized by the currently running systemd
process. This is important if you've recently modified unit files or if you're overriding specific options in a unit file fragment (we'll discuss this later).
Displaying Dependencies
To view a unit's dependency tree, use the list-dependencies
command:
systemctl list-dependencies sshd.service
This shows a hierarchy outlining the dependencies that must be addressed to start the given unit. Dependencies include units either required or wanted by the units above them.
Output
sshd.service
├─system.slice
└─basic.target
├─microcode.service
├─rhel-autorelabel-mark.service
├─rhel-autorelabel.service
├─rhel-configure.service
├─rhel-dmesg.service
├─rhel-loadmodules.service
├─paths.target
├─slices.target
. . .
The recursive dependencies are only displayed for .target units, which indicate system states. To recursively list all dependencies, include the --all
flag.
To display reverse dependencies (units depending on the specified unit), include the --reverse
flag. The --before
and --after
flags are also helpful, showing units that depend on the specified unit starting before or after themselves, respectively.
Checking Unit Properties
To view a unit's low-level properties, use the show
command. This displays a list of properties set for the specified unit in a key=value format:
systemctl show sshd.service
Output
Id=sshd.service
Names=sshd.service
Requires=basic.target
Wants=system.slice
WantedBy=multi-user.target
Conflicts=shutdown.target
Before=shutdown.target multi-user.target
After=syslog.target network.target auditd.service systemd-journald.socket basic.target system.slice
Description=OpenSSH server daemon
. . .
To display a single property, use the -p
flag with the property name. For example, to see conflicts related to the sshd.service unit, enter:
systemctl show sshd.service -p Conflicts
Output
Conflicts=shutdown.target
Masking and Unmasking Units
We've seen how to stop or disable a service, but systemd
also enables marking a unit as entirely unstartable, either automatically or manually, by linking it to /dev/null. This is called masking the unit and can be accomplished with the mask
command:
sudo systemctl mask nginx.service
This prevents the Nginx service from starting, either automatically or manually, as long as it remains masked.
When checking the list-unit-files, the service now appears as masked:
systemctl list-unit-files
Output
. . .
kmod-static-nodes.service static
ldconfig.service static
mandb.service static
messagebus.service static
nginx.service masked
quotaon.service static
rc-local.service static
rdisc.service disabled
rescue.service static
. . .
Attempting to start the service produces the following message:
sudo systemctl start nginx.service
Output
Failed to start nginx.service: Unit nginx.service is masked.
To unmask a unit and make it available for use again, use the unmask
command:
sudo systemctl unmask nginx.service
This returns the unit to its previous state, allowing it to be started or enabled.
Editing Unit Files
The specific format for unit files falls outside the scope of this guide, but systemctl
includes built-in tools for editing and modifying unit files when adjustments are required. This feature was introduced in systemd
version 218.
By default, the edit
command opens a snippet for the specified unit:
sudo systemctl edit nginx.service
This blank file allows you to override or add directives to the unit definition. A directory is created in the /etc/systemd/system directory, with the unit's name appended with .d. For example, a directory called nginx.service.d is created for the nginx.service.
Inside this directory, an override.conf snippet is created. When the unit is loaded, systemd
merges the override snippet with the full unit file in memory. The snippet's directives take precedence over those in the original unit file.
If you prefer to edit the entire unit file instead of creating a snippet, use the --full
flag:
sudo systemctl edit --full nginx.service
This command opens the current unit file in the editor, where you can make modifications. Upon exiting the editor, the modified file is saved to /etc/systemd/system, overriding the system's unit definition (typically found in /lib/systemd/system).
To remove any changes you've made, delete the unit's .d configuration directory or the modified service file from /etc/systemd/system. For example, to remove a snippet, enter:
sudo rm -r /etc/systemd/system/nginx.service.d
To remove a fully modified unit file, enter:
sudo rm /etc/systemd/system/nginx.service
After deleting the file or directory, reload the systemd
process so it no longer references these files and reverts to using the system copies. This can be done by entering:
sudo systemctl daemon-reload
Adjusting the System State (Runlevel) with Targets
Targets represent unique unit files that describe a system state or synchronization point. Like other units, the files that define targets can be identified by their suffix, which in this case is .target. Although they don't do much on their own, targets are utilized to group other units together.
Targets help bring the system to certain states, similar to runlevels in other init systems. They serve as a reference for when specific functions are accessible, allowing the desired state to be specified instead of the individual units needed to achieve that state.
For example, a swap.target indicates that swap is ready to be used. Units involved in this process can synchronize with this target by specifying in their configuration that they are WantedBy= or RequiredBy= the swap.target. Units that require swap to be available can specify this condition using the Wants=, Requires=, and After= specifications to indicate the nature of their relationship.
Getting and Setting the Default Target
Systemd
has a default target that it utilizes when booting the system. Satisfying the dependencies of that single target brings the system to the desired state. To identify your system's default target, enter:
systemctl get-default
Output
Multi-user.target
To set a different default target, use the set-default
command. For example, if you have a graphical desktop installed and want the system to boot into it by default, change your default target accordingly:
sudo systemctl set-default graphical.target
Listing Available Targets
To view a list of available targets on your system, enter:
systemctl list-unit-files --type=target
Multiple targets can be active simultaneously. An active target signifies that systemd
has attempted to start all units linked to the target and has not tried to stop them again. To view all active targets, enter:
systemctl list-units --type=target
Isolating Targets
Starting all units associated with a target and stopping all units not part of the dependency tree is possible. The command to achieve this is called isolate
, which is akin to changing the runlevel in other initialization systems.
For example, if operating in a graphical environment with an active graphical.target, you can shut down the graphical system and transition the system into a multi-user command line state by isolating the multi-user.target. Since graphical.target depends on multi-user.target but not vice versa, all graphical units will be stopped.
Before isolating a target, you might want to review its dependencies to ensure you're not stopping essential services:
systemctl list-dependencies multi-user.target
Once you're satisfied with the units that will remain active, isolate the target by entering:
sudo systemctl isolate multi-user.target
Using Shortcuts for Important Events
Targets are designed for significant events like powering off or rebooting. However, systemctl
also offers shortcuts that provide extra functionality.
For example, to enter rescue (single-user) mode, use the rescue
command instead of isolate
rescue.target:
sudo systemctl rescue
This adds the benefit of notifying all logged-in users about the event.
To halt the system, use the halt
command:
sudo systemctl halt
For a complete shutdown, employ the poweroff
command:
sudo systemctl poweroff
To restart, use the reboot
command:
sudo systemctl reboot
These commands inform logged-in users of the event, which running or isolating the target alone won't do. Note that most machines link the shorter, more conventional commands for these operations to work correctly with systemd
.
For instance, to reboot the system, you can typically type:
sudo reboot
Wrapping Up
By now, you should be acquainted with the fundamental features and capabilities of the systemctl
command, allowing you to interact with and manage a systemd
instance. The systemctl
utility serves as the primary interaction point for service and system state management.
While systemctl
primarily works with the main systemd
process, other components in the systemd
ecosystem are controlled by different utilities. Other functionalities, like log management and user sessions, are managed by separate daemons and management utilities (journald
/journalctl
and logind
/loginctl
, respectively). Taking the time to familiarize yourself with these other tools and daemons will make management tasks easier.