1. Introduction
Most of the popular, modern Linux distributions use systemd to manage services. Services like sshd or getty come with unit files provided by their vendors. Because it isn’t recommended to edit this configuration, we need a different way to modify the service settings.
systemd supports two ways to achieve this goal. We can extend the configuration to change the selected parameters only. The rest of the upstream configuration still applies. In this way, we can benefit from service updates. On the contrary, overriding the configuration shadows the upstream one completely.
In this tutorial, we’ll learn about both of these ways to alter service settings.
2. Extending the Configuration
Because we’ll work with the ssh server sshd as an example, we need to install it. On a Fedora-based system, we use dnf:
$ sudo dnf install openssh-server
We can extend the vendor’s configuration by creating and filling a file override. conf in the /etc/systemd/system/<service_name>.service.d directory. Note that the directory name consists of the service name followed by the d suffix. If this directory doesn’t exist, we need to create it.
While editing the override.conf file, we should obey the same rules as for the regular unit file. As an example, let’s change the RestartSec setting for the sshd daemon with an entry in the Service section:
$ cat /etc/systemd/system/sshd.service.d/override.conf
[Service]
RestartSec=50
For the changes to take effect, we need to reload services with systemctl:
$ sudo systemctl daemon-reload
Then, we can restart the sshd daemon:
$ sudo systemctl restart sshd.service
Finally, let’s check the service status:
$ systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/sshd.service.d
└─override.conf
Active: active (running) since Mon 2023-07-31 18:29:25 CEST; 4min 45s ago
# ...
The Drop-In entry indicates that our change is taken into account.
We can make our work easier by using the edit verb of the systemctl command. It’ll create the services directory sshd.service.d and allow editing the override.conf file:
$ sudo systemctl edit sshd.service
We’re provided with the commented-out upstream configuration of the service for a better overview.
2.1. Multiple Drop-in Files and Naming Convention
override.conf is nothing but a default name given by the systemctl edit. We can use an arbitrary name because the corresponding service is denoted by the name of the folder. Moreover, we can create multiple overriding configuration files. Therefore, we should name them so that their names reflect their purposes.
The files are applied in lexigraphic order. We can take advantage of it by starting the file names with numbers, such as 10_, 20_, and so on. Then, if the same setting is modified in a few files, the one with the highest number takes precedence.
As an example, let’s modify RestartSec for sshd twice. Let’s set it to 50 seconds in the 10_RestartSec_50.conf:
$ cat /etc/systemd/system/sshd.service.d/10_RestartSec_50.conf
[Service]
RestartSec=50
In the 99_RestartSec_100.conf file, we set it to 100 seconds:
$ cat /etc/systemd/system/sshd.service.d/99_RestartSec_100.conf
[Service]
RestartSec=100
Subsequently, we need to reload services and restart sshd. Finally, let’s check the status of sshd:
$ systemctl status sshd
● sshd.service - OpenSSH server daemon
Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/sshd.service.d
└─10_RestartSec_50.conf, 99_RestartSec_100.conf
# ...
We see that both drop-ins are listed. Let’s dot the ‘i’ and inspect the RestartUSec parameter, which takes value after RestartSec:
$ systemctl show sshd --property=RestartUSec
RestartUSec=1min 40s
3. Overriding the Configuration
Instead of modifying the existing configuration, we can completely cut ourselves off from the upstream unit file. We need to create a new configuration file <service_name>.service in the /etc/systemd/system folder, which will replace the vendor’s version. Let’s do it right away with the edit –full command to systemctl:
$ sudo systemctl edit --full sshd.service
This time, an editor with no commented-out copy of settings shows up:
We can change anything we want. In our case, let’s modify RestartSec again:
[Service]
RestartSec=50
Next, we need to reload the daemons and restart the service. Finally, let’s check its status:
$ systemctl status sshd.service
● sshd.service - OpenSSH server daemon
Loaded: loaded (/etc/systemd/system/sshd.service; enabled; vendor preset: disabled)
Active: active (running) since Tue 2023-08-01 16:39:04 CEST; 6min ago
Docs: man:sshd(8)
# ...
Now, we don’t have the Drop-In entry, as the unit file is replaced instead of being extended. We’re informed about it in the Loaded line, which shows the unit file path.
4. Detecting the Service Modification
To determine the status of the service in terms of its modification, let’s use the system-delta command. Throughout this tutorial, we’ll use the syntax:
$ systemd-delta [OPTIONS]
First, let’s issue the command without options. Consequently, it lists all services that were changed in one way or another. Assuming that we’ve modified the sshd service configuration with a drop-in file, we’ll find in the output:
$ systemd-delta
# ...
[EXTENDED] /usr/lib/systemd/system/sshd.service → /etc/systemd/system/sshd.service.d/override.conf
# ...
The EXTENDED type tells us about the modification and leads to the drop-in configuration file.
On the other hand, if the custom configuration is created and shadows the original one, we’ll obtain a different result:
$ systemd-delta
# ...
[OVERRIDDEN] /etc/systemd/system/sshd.service → /usr/lib/systemd/system/sshd.service
# ...
Now, the OVERRIDDEN entry points to the custom configuration file.
In the overridden case, we’re provided with the diff-like details of the change:
$ systemd-delta
# ...
--- /usr/lib/systemd/system/sshd.service 2022-01-20 23:51:44.000000000 +0100
+++ /etc/systemd/system/sshd.service 2023-08-01 16:37:59.049605208 +0200
@@ -11,7 +11,7 @@
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
-RestartSec=42s
+RestartSec=50s
4.1. More on the Modification Type
The systemd-delta command recognizes more ways of service modification. We can use a type name to query services with the –type option. So, let’s examine some of them. First, to find all unchanged services, we should use the type unchanged:
$ systemd-delta --type unchanged
[UNCHANGED] /etc/sysctl.d/99-sysctl.conf
[UNCHANGED] /usr/lib/sysctl.d/10-default-yama-scope.conf
# ...
Next, let’s list all overridden configurations. Additionally, we’re going to suppress the diff output with the –diff=false option:
$ systemd-delta --type overridden --diff=false
[OVERRIDDEN] /etc/systemd/system/instsvcdrv.service → /usr/lib/systemd/system/instsvcdrv.service
[OVERRIDDEN] /etc/systemd/system/sshd.service → /usr/lib/systemd/system/sshd.service
2 overridden configuration files found.
The services that are modified by the overriding drop-in file can be found in the type extended:
$ systemd-delta --type extended
[EXTENDED] /usr/lib/systemd/system/systemd-hostnamed.service → /usr/lib/systemd/system/systemd-hostnamed.service.d/disable-privatedevices.conf
[EXTENDED] /usr/lib/systemd/system/systemd-logind.service → /usr/lib/systemd/system/systemd-logind.service.d/10-grub2-logind-service.conf
# ...
9 overridden configuration files found.
The other types are: masked, equivalent, and redirected.
5. Restoring the Original Configuration
Deleting the custom configuration is pretty simple — all we need is to remove the overriding files and reload services. So, in the drop-in case, we should remove the files from the /etc/systemd/system/<service_name>.service.d directory. When the configuration is replaced, we should remove the <service_name>.service from the /etc/systemd/system directory.
Finally, let’s issue the commands to reload the config and restart the service:
$ sudo systemctl daemon-reload
$ sudo systemctl restart <service_name>.service
6. Working With Templates
The service template is a service unit file that can take a parameter. In this way, we can create multiple, different instances of the same service. The name of the service instance looks like:
<service_name>@<argument>.service
Let’s take a look at getty, a well-known template service. Its task is to bring up a text pseudo-terminal TTY. The terminal identifier is the template argument. So, let’s open a pseudo-terminal with Alt+Ctrl+F3. Afterward, let’s check the active services to find a getty instance:
$ systemctl --type=service --state=active | grep getty
[email protected] loaded active running Getty on tty3
Next, we’re going to find the corresponding unit file:
$ sudo systemctl list-unit-files --state=enabled | grep getty
[email protected] enabled enabled
Note the at sign ‘@’ indicating a template unit file of this service.
We can modify both the template and instances of the service. When creating a drop-in files directory or a unit file for the template, we should follow the service name with a sole @. For service instances, @ is followed additionally by the template parameter.
As an example, to edit the getty template, let’s issue:
$ sudo systemctl edit getty@
In the case of the getty instance, we should use:
$ sudo systemctl edit getty@tty5
6.1. Working Example
As an example, let’s change the way the user logs in to the pseudo-terminal. We’re going to get an automatic login for user joe in tty5. Thus, we should change the corresponding instance getty@tty5 of the service. Let’s do that with systemctl edit:
$ sudo systemctl edit getty@tty5
In the editor, let’s find the commented-out ExecStart entry with the calling of the agetty command:
# ExecStart=-/sbin/agetty -o '-p -- \\u' --noclear - $TERM
By adding the -a joe option, we allow automatic login for joe. Now, the new Service section looks like:
[Service]
ExecStart=
ExecStart=-/sbin/agetty -a joe -o '-p -- \\u' --noclear - $TERM
The important part is to reset ExecStart before setting it to a new value. We should do that because multiple definitions of this parameter are not allowed — unless it’s a oneshot service.
Now, let’s save the modifications and change the default file name override.conf to something more meaningful, like joe_auto_login.conf. At last, let’s reload daemons and press Alt+Ctrl+F5. We’ll jump into the pseudo-terminal with the login name set to joe.
Finally, let’s check the service status:
$ systemctl status getty@tty5
● [email protected] - Getty on tty5
Loaded: loaded (/usr/lib/systemd/system/[email protected]; disabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/[email protected]
└─joe_auto_login.conf
# ...
7. Conclusion
In this article, we studied two ways to modify the systemd services configuration, without touching the upstream unit file. First, we discovered the difference between extending and overriding the configuration. Then, we got into the details of both approaches.
We learned about the structure and naming convention of files that extend the configuration. Then, we searched for the altered services according to the way of their modification.
Finally, we took a look at the template services. As an example, we allowed automatic login to a selected pseudo-terminal by adjusting the getty instance.