9.6. Creating and Modifying systemd Unit Files
systemctl commands work with unit files in the background. To make finer adjustments, system administrator must edit or create unit files manually. Table 9.2, “Systemd Unit Files Locations” lists three main directories where unit files are stored on the system, the /etc/systemd/system/ directory is reserved for unit files created or customized by the system administrator.
unit_name.type_extension
sshd.service as well as sshd.socket unit present on your system.
sshd.service, create the sshd.service.d/custom.conf file and insert additional directives there. For more information on configuration directories, see Section 9.6.4, “Modifying Existing Unit Files”.
sshd.service.wants/ and sshd.service.requires/ directories can be created. These directories contain symbolic links to unit files that are dependencies of the sshd service. The symbolic links are automatically created either during installation according to [Install] unit file options (see Table 9.11, “Important [Install] Section Options”) or at runtime based on [Unit] options (see Table 9.9, “Important [Unit] Section Options”). It is also possible to create these directories and symbolic links manually.
9.6.1. Understanding the Unit File Structure
- [Unit] — contains generic options that are not dependent on the type of the unit. These options provide unit description, specify the unit's behavior, and set dependencies to other units. For a list of most frequently used [Unit] options, see Table 9.9, “Important [Unit] Section Options”.
- [unit type] — if a unit has type-specific directives, these are grouped under a section named after the unit type. For example, service unit files contain the [Service] section, see Table 9.10, “Important [Service] Section Options” for most frequently used [Service] options.
- [Install] — contains information about unit installation used by
systemctl enableanddisablecommands, see Table 9.11, “Important [Install] Section Options” for a list of [Install] options.
Table 9.9. Important [Unit] Section Options
| Option[a] | Description |
|---|---|
Description | A meaningful description of the unit. This text is displayed for example in the output of the systemctl status command. |
Documentation | Provides a list of URIs referencing documentation for the unit. |
After[b] | Defines the order in which units are started. The unit starts only after the units specified in After are active. Unlike Requires, After does not explicitly activate the specified units. The Before option has the opposite functionality to After. |
Requires | Configures dependencies on other units. The units listed in Requires are activated together with the unit. If any of the required units fail to start, the unit is not activated. |
Wants | Configures weaker dependencies than Requires. If any of the listed units does not start successfully, it has no impact on the unit activation. This is the recommended way to establish custom unit dependencies. |
Conflicts | Configures negative dependencies, an opposite to Requires. |
[a]
For a complete list of options configurable in the [Unit] section, see the systemd.unit(5) manual page.
[b]
In most cases, it is sufficient to set only the ordering dependencies with After and Before unit file options. If you also set a requirement dependency with Wants (recommended) or Requires, the ordering dependency still needs to be specified. That is because ordering and requirement dependencies work independently from each other.
| |
Table 9.10. Important [Service] Section Options
| Option[a] | Description |
|---|---|
Type | Configures the unit process startup type that affects the functionality of ExecStart and related options. One of:
|
ExecStart | Specifies commands or scripts to be executed when the unit is started. ExecStartPre and ExecStartPost specify custom commands to be executed before and after ExecStart. Type=oneshot enables specifying multiple custom commands that are then executed sequentially. |
ExecStop | Specifies commands or scripts to be executed when the unit is stopped. |
ExecReload | Specifies commands or scripts to be executed when the unit is reloaded. |
Restart | With this option enabled, the service is restarted after its process exits, with the exception of a clean stop by the systemctl command. |
RemainAfterExit | If set to True, the service is considered active even when all its processes exited. Default value is False. This option is especially useful if Type=oneshot is configured. |
[a]
For a complete list of options configurable in the [Service] section, see the systemd.service(5) manual page.
| |
Table 9.11. Important [Install] Section Options
| Option[a] | Description |
|---|---|
Alias | Provides a space-separated list of additional names for the unit. Most systemctl commands, excluding systemctl enable, can use aliases instead of the actual unit name. |
RequiredBy | A list of units that depend on the unit. When this unit is enabled, the units listed in RequiredBy gain a Require dependency on the unit. |
WantedBy | A list of units that weakly depend on the unit. When this unit is enabled, the units listed in WantedBy gain a Want dependency on the unit. |
Also | Specifies a list of units to be installed or uninstalled along with the unit. |
DefaultInstance | Limited to instantiated units, this option specifies the default instance for which the unit is enabled. See Section 9.6.5, “Working with Instantiated Units” |
[a]
For a complete list of options configurable in the [Install] section, see the systemd.unit(5) manual page.
| |
Example 9.17. postfix.service Unit File
/usr/lib/systemd/system/postifix.service unit file as currently provided by the postfix package:
[Unit] Description=Postfix Mail Transport Agent After=syslog.target network.target Conflicts=sendmail.service exim.service [Service] Type=forking PIDFile=/var/spool/postfix/pid/master.pid EnvironmentFile=-/etc/sysconfig/network ExecStartPre=-/usr/libexec/postfix/aliasesdb ExecStartPre=-/usr/libexec/postfix/chroot-update ExecStart=/usr/sbin/postfix start ExecReload=/usr/sbin/postfix reload ExecStop=/usr/sbin/postfix stop [Install] WantedBy=multi-user.target
EnvironmentFile points to the location where environment variables for the service are defined, PIDFile specifies a stable PID for the main process of the service. Finally, the [Install] section lists units that depend on the service.
9.6.2. Creating Custom Unit Files
- Prepare the executable file with the custom service. This can be a custom-created script, or an executable delivered by a software provider. If required, prepare a PID file to hold a constant PID for the main process of the custom service. It is also possible to include environment files to store shell variables for the service. Make sure the source script is executable (by executing the
chmod a+x) and is not interactive. - Create a unit file in the
/etc/systemd/system/directory and make sure it has correct file permissions. Execute asroot:touch/etc/systemd/system/name.servicechmod 664/etc/systemd/system/name.serviceReplace name with a name of the service to be created. Note that file does not need to be executable. - Open the
name.servicefile created in the previous step, and add the service configuration options. There is a variety of options that can be used depending on the type of service you wish to create, see Section 9.6.1, “Understanding the Unit File Structure”. The following is an example unit configuration for a network-related service:[Unit] Description=service_description After=network.target [Service] ExecStart=path_to_executable Type=forking PIDFile=path_to_pidfile [Install] WantedBy=default.target
Where:- service_description is an informative description that is displayed in journal log files and in the output of the
systemctl statuscommand. - the
Aftersetting ensures that the service is started only after the network is running. Add a space-separated list of other relevant services or targets. - path_to_executable stands for the path to the actual service executable.
Type=forkingis used for daemons that make the fork system call. The main process of the service is created with the PID specified in path_to_pidfile. Find other startup types in Table 9.10, “Important [Service] Section Options”.WantedBystates the target or targets that the service should be started under. Think of these targets as of a replacement of the older concept of runlevels, see Section 9.3, “Working with systemd Targets” for details.
- Notify systemd that a new
name.servicefile exists by executing the following command asroot:systemctldaemon-reloadsystemctl start name.serviceWarning
Always run thesystemctl daemon-reloadcommand after creating new unit files or modifying existing unit files. Otherwise, thesystemctl startorsystemctl enablecommands could fail due to a mismatch between states of systemd and actual service unit files on disk.The name.service unit can now be managed as any other system service with commands described in Section 9.2, “Managing System Services”.
Example 9.18. Creating the emacs.service File
- Create a unit file in the
/etc/systemd/system/directory and make sure it has the correct file permissions. Execute asroot:~]#
touch~]#/etc/systemd/system/emacs.servicechmod 664/etc/systemd/system/emacs.service - Add the following content to the file:
[Unit] Description=Emacs: the extensible, self-documenting text editor [Service] Type=forking ExecStart=/usr/bin/emacs --daemon ExecStop=/usr/bin/emacsclient --eval "(kill-emacs)" Environment=SSH_AUTH_SOCK=%t/keyring/ssh Restart=always [Install] WantedBy=default.targetWith the above configuration, the/usr/bin/emacsexecutable is started in daemon mode on service start. The SSH_AUTH_SOCK environment variable is set using the "%t" unit specifier that stands for the runtime directory. The service also restarts the emacs process if it exits unexpectedly. - Execute the following commands to reload the configuration and start the custom service:
~]#
systemctl~]#daemon-reloadsystemctl start emacs.service
systemctl commands. For example, run systemctl status emacs to display the editor's status or systemctl enable emacs to make the editor start automatically on system boot.
Example 9.19. Creating a second instance of the sshd service
sshd service:
- Create a copy of the
sshd_configfile that will be used by the second daemon:~]#
cp /etc/ssh/sshd{,-second}_config - Edit the
sshd-second_configfile created in the previous step to assign a different port number and PID file to the second daemon:Port 22220 PidFile /var/run/sshd-second.pid
See thesshd_config(5) manual page for more information onPortandPidFileoptions. Make sure the port you choose is not in use by any other service. The PID file does not have to exist before running the service, it is generated automatically on service start. - Create a copy of the systemd unit file for the
sshdservice:~]#
cp /usr/lib/systemd/system/sshd.service /etc/systemd/system/sshd-second.service - Alter the
sshd-second.servicecreated in the previous step as follows:- Modify the
Descriptionoption:Description=OpenSSH server second instance daemon
- Add sshd.service to services specified in the
Afteroption, so that the second instance starts only after the first one has already started:After=syslog.target network.target auditd.service sshd.service
- The first instance of sshd includes key generation, therefore remove the ExecStartPre=/usr/sbin/sshd-keygen line.
- Add the
-f /etc/ssh/sshd-second_configparameter to thesshdcommand, so that the alternative configuration file is used:ExecStart=/usr/sbin/sshd -D -f /etc/ssh/sshd-second_config $OPTIONS
- After the above modifications, the sshd-second.service should look as follows:
[Unit] Description=OpenSSH server second instance daemon After=syslog.target network.target auditd.service sshd.service [Service] EnvironmentFile=/etc/sysconfig/sshd ExecStart=/usr/sbin/sshd -D -f /etc/ssh/sshd-second_config $OPTIONS ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s [Install] WantedBy=multi-user.target
- If using SELinux, add the port for the second instance of sshd to SSH ports, otherwise the second instance of sshd will be rejected to bind to the port:
~]#
semanage port -a -t ssh_port_t -p tcp 22220 - Enable sshd-second.service, so that it starts automatically upon boot:
~]#
systemctl enable sshd-second.serviceVerify if the sshd-second.service is running by using thesystemctl statuscommand. Also, verify if the port is enabled correctly by connecting to the service:~]$
ssh -p 22220 user@serverIf the firewall is in use, please make sure that it is configured appropriately in order to allow connections to the second instance of sshd.
systemd, see the Red Hat Knowledgebase article How to set limits for services in RHEL 7 and systemd. These limits need to be set in the service's unit file. Note that systemd ignores limits set in the /etc/security/limits.conf and /etc/security/limits.d/*.conf configuration files. The limits defined in these files are set by PAM when starting a login session, but daemons started by systemd do not use PAM login sessions.
9.6.3. Converting SysV Init Scripts to Unit Files
postfix service on Red Hat Enterprise Linux 6:
#!/bin/bash # # postfix Postfix Mail Transfer Agent # # chkconfig: 2345 80 30 # description: Postfix is a Mail Transport Agent, which is the program \ # that moves mail from one machine to another. # processname: master # pidfile: /var/spool/postfix/pid/master.pid # config: /etc/postfix/main.cf # config: /etc/postfix/master.cf ### BEGIN INIT INFO # Provides: postfix MTA # Required-Start: $local_fs $network $remote_fs # Required-Stop: $local_fs $network $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: start and stop postfix # Description: Postfix is a Mail Transport Agent, which is the program that # moves mail from one machine to another. ### END INIT INFO
Finding the Service Description
Description option in the [Unit] section of the unit file. The LSB header might contain similar data on the #Short-Description and #Description lines.
Finding Service Dependencies
Table 9.12. Dependency Options from the LSB Header
| LSB Option | Description | Unit File Equivalent |
|---|---|---|
Provides | Specifies the boot facility name of the service, that can be referenced in other init scripts (with the "$" prefix). This is no longer needed as unit files refer to other units by their file names. | – |
Required-Start | Contains boot facility names of required services. This is translated as an ordering dependency, boot facility names are replaced with unit file names of corresponding services or targets they belong to. For example, in case of postfix, the Required-Start dependency on $network was translated to the After dependency on network.target. | After, Before |
Should-Start | Constitutes weaker dependencies than Required-Start. Failed Should-Start dependencies do not affect the service startup. | After, Before |
Required-Stop, Should-Stop | Constitute negative dependencies. | Conflicts |
Finding Default Targets of the Service
WantedBy option in the [Install] section of the unit file. For example, postfix was previously started in runlevels 2, 3, 4, and 5, which translates to multi-user.target and graphical.target on Red Hat Enterprise Linux 7. Note that the graphical.target depends on multiuser.target, therefore it is not necessary to specify both, as in Example 9.17, “postfix.service Unit File”. You might find information on default and forbidden runlevels also at #Default-Start and #Default-Stop lines in the LSB header.
Finding Files Used by the Service
EnvironmentFile unit file option. The PID file specified on the #pidfile init script line is imported to the unit file with the PIDFile option.
postfix init script shows the block of code to be executed at service start.
conf_check() {
[ -x /usr/sbin/postfix ] || exit 5
[ -d /etc/postfix ] || exit 6
[ -d /var/spool/postfix ] || exit 5
}
make_aliasesdb() {
if [ "$(/usr/sbin/postconf -h alias_database)" == "hash:/etc/aliases" ]
then
# /etc/aliases.db might be used by other MTA, make sure nothing
# has touched it since our last newaliases call
[ /etc/aliases -nt /etc/aliases.db ] ||
[ "$ALIASESDB_STAMP" -nt /etc/aliases.db ] ||
[ "$ALIASESDB_STAMP" -ot /etc/aliases.db ] || return
/usr/bin/newaliases
touch -r /etc/aliases.db "$ALIASESDB_STAMP"
else
/usr/bin/newaliases
fi
}
start() {
[ "$EUID" != "0" ] && exit 4
# Check that networking is up.
[ ${NETWORKING} = "no" ] && exit 1
conf_check
# Start daemons.
echo -n $"Starting postfix: "
make_aliasesdb >/dev/null 2>&1
[ -x $CHROOT_UPDATE ] && $CHROOT_UPDATE
/usr/sbin/postfix start 2>/dev/null 1>&2 && success || failure $"$prog start"
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $lockfile
echo
return $RETVAL
}conf_check() and make_aliasesdb(), that are called from the start() function block. On closer look, several external files and directories are mentioned in the above code: the main service executable /usr/sbin/postfix, the /etc/postfix/ and /var/spool/postfix/ configuration directories, as well as the /usr/sbin/postconf/ directory.
ExecStart, ExecStartPre, ExecStartPost, ExecStop, and ExecReload options. In case of postfix on Red Hat Enterprise Linux 7, the /usr/sbin/postfix together with supporting scripts are executed on service start. Consult the postfix unit file at Example 9.17, “postfix.service Unit File”.
9.6.4. Modifying Existing Unit Files
/usr/lib/systemd/system/ directory. System Administrators should not modify these files directly, therefore any customization must be confined to configuration files in the /etc/systemd/system/ directory. Depending on the extent of the required changes, pick one of the following approaches:
- Create a directory for supplementary configuration files at
/etc/systemd/system/unit.d/. This method is recommended for most use cases. It enables extending the default configuration with additional functionality, while still referring to the original unit file. Changes to the default unit introduced with a package upgrade are therefore applied automatically. See the section called “Extending the Default Unit Configuration” for more information. - Create a copy of the original unit file
/usr/lib/systemd/system/in/etc/systemd/system/and make changes there. The copy overrides the original file, therefore changes introduced with the package update are not applied. This method is useful for making significant unit changes that should persist regardless of package updates. See the section called “Overriding the Default Unit Configuration” for details.
/etc/systemd/system/. To apply changes to unit files without rebooting the system, execute:
systemctl daemon-reloaddaemon-reload option reloads all unit files and recreates the entire dependency tree, which is needed to immediately apply any change to a unit file. As an alternative, you can achieve the same result with the following command:
init qsystemctl restart name.serviceImportant
systemd drop-in configuration file for the service as described in the section called “Extending the Default Unit Configuration” and the section called “Overriding the Default Unit Configuration”. Then manage this service in the same way as a normal systemd service.
network service, do not modify the /etc/rc.d/init.d/network initscript file. Instead, create new directory /etc/systemd/system/network.service.d/ and a systemd drop-in file /etc/systemd/system/network.service.d/my_config.conf. Then, put the modified values into the drop-in file. Note: systemd knows the network service as network.service, which is why the created directory must be called network.service.d
Extending the Default Unit Configuration
/etc/systemd/system/. If extending a service unit, execute the following command as root:
mkdir /etc/systemd/system/name.service.d/touch /etc/systemd/system/name.service.d/config_name.conf[Unit] Requires=new_dependency After=new_dependency
[Service] Restart=always RestartSec=30
root:
systemctldaemon-reloadsystemctl restart name.service
Example 9.20. Extending the httpd.service Configuration
~]#mkdir~]#/etc/systemd/system/httpd.service.d/touch/etc/systemd/system/httpd.service.d/custom_script.conf
/usr/local/bin/custom.sh, insert the following text to the custom_script.conf file:
[Service] ExecStartPost=/usr/local/bin/custom.sh
~]#systemctl~]#daemon-reloadsystemctl restart httpd.service
Note
/etc/systemd/system/ take precedence over unit files in /usr/lib/systemd/system/. Therefore, if the configuration files contain an option that can be specified only once, such as Description or ExecStart, the default value of this option is overridden. Note that in the output of the systemd-delta command, described in the section called “Monitoring Overriden Units”, such units are always marked as [EXTENDED], even though in sum, certain options are actually overridden.
Overriding the Default Unit Configuration
/etc/systemd/system/ directory. To do so, execute the following command as root:
cp /usr/lib/systemd/system/name.service /etc/systemd/system/name.serviceroot:
systemctldaemon-reloadsystemctl restart name.service
Example 9.21. Changing the timeout limit
httpd service:
- Copy the
httpdunit file to the/etc/systemd/system/directory:cp /usr/lib/systemd/system/httpd.service /etc/systemd/system/httpd.service - Open file
/etc/systemd/system/httpd.serviceand specify theTimeoutStartUSecvalue in the[Service]section:... [Service] ... PrivateTmp=true TimeoutStartSec=10 [Install] WantedBy=multi-user.target ...
- Reload the
systemddaemon:systemctl daemon-reload - Optional. Verify the new timeout value:
systemctl show httpd -p TimeoutStartUSec
Note
DefaultTimeoutStartSec in the /etc/systemd/system.conf file. See Section 9.1, “Introduction to systemd”.
Monitoring Overriden Units
systemd-delta[EQUIVALENT] /etc/systemd/system/default.target → /usr/lib/systemd/system/default.target [OVERRIDDEN] /etc/systemd/system/autofs.service → /usr/lib/systemd/system/autofs.service --- /usr/lib/systemd/system/autofs.service 2014-10-16 21:30:39.000000000 -0400 +++ /etc/systemd/system/autofs.service 2014-11-21 10:00:58.513568275 -0500 @@ -8,7 +8,8 @@ EnvironmentFile=-/etc/sysconfig/autofs ExecStart=/usr/sbin/automount $OPTIONS --pid-file /run/autofs.pid ExecReload=/usr/bin/kill -HUP $MAINPID -TimeoutSec=180 +TimeoutSec=240 +Restart=Always [Install] WantedBy=multi-user.target [MASKED] /etc/systemd/system/cups.service → /usr/lib/systemd/system/cups.service [EXTENDED] /usr/lib/systemd/system/sssd.service → /etc/systemd/system/sssd.service.d/journal.conf 4 overridden configuration files found.
systemd-delta. Note that if a file is overridden, systemd-delta by default displays a summary of changes similar to the output of the diff command.
Table 9.13. systemd-delta Difference Types
| Type | Description |
|---|---|
|
[MASKED]
|
Masked unit files, see Section 9.2.7, “Disabling a Service” for description of unit masking.
|
|
[EQUIVALENT]
|
Unmodified copies that override the original files but do not differ in content, typically symbolic links.
|
|
[REDIRECTED]
|
Files that are redirected to another file.
|
|
[OVERRIDEN]
|
Overridden and changed files.
|
|
[EXTENDED]
|
Files that are extended with .conf files in the
/etc/systemd/system/unit.d/ directory.
|
|
[UNCHANGED]
|
Unmodified files are displayed only when the
--type=unchanged option is used.
|
systemd-delta after system update to check if there are any updates to the default units that are currently overridden by custom configuration. It is also possible to limit the output only to a certain difference type. For example, to view just the overridden units, execute:
systemd-delta --type=overridden9.6.5. Working with Instantiated Units
Requires or Wants options), or with the systemctl start command. Instantiated service units are named the following way:
template_name@instance_name.service
unit_name@.service
Wants setting in a unit file:
Wants=getty@ttyA.service,getty@ttyB.service
getty@.service file, reads the configuration from it, and starts the services.
Table 9.14. Important Unit Specifiers
| Unit Specifier | Meaning | Description |
|---|---|---|
%n | Full unit name | Stands for the full unit name including the type suffix. %N has the same meaning but also replaces the forbidden characters with ASCII codes. |
%p | Prefix name | Stands for a unit name with type suffix removed. For instantiated units %p stands for the part of the unit name before the "@" character. |
%i | Instance name | Is the part of the instantiated unit name between the "@" character and the type suffix. %I has the same meaning but also replaces the forbidden characters for ASCII codes. |
%H | Host name | Stands for the hostname of the running system at the point in time the unit configuration is loaded. |
%t | Runtime directory | Represents the runtime directory, which is either /run for the root user, or the value of the XDG_RUNTIME_DIR variable for unprivileged users. |
systemd.unit(5) manual page.
getty@.service template contains the following directives:
[Unit] Description=Getty on %I ... [Service] ExecStart=-/sbin/agetty --noclear %I $TERM ...
Description= is resolved as Getty on ttyA and Getty on ttyB.

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.