Example 1. Allowing units to be enabled
The following snippet (highlighted) allows a unit (e.g.
foo.service) to be enabled via systemctl enable
:
[Unit]
Description=Foo
[Service]
ExecStart=/usr/sbin/foo-daemon
[Install]
WantedBy=multi-user.target
After running systemctl enable
, a symlink
/etc/systemd/system/multi-user.target.wants/foo.service linking
to the actual unit will be created. It tells systemd to pull in
the unit when starting multi-user.target. The inverse systemctl
disable
will remove that symlink again.
Example 2. Overriding vendor settings
There are two methods of overriding vendor settings in unit
files: copying the unit file from /usr/lib/systemd/system to
/etc/systemd/system and modifying the chosen settings.
Alternatively, one can create a directory named unit.d/ within
/etc/systemd/system and place a drop-in file name.conf there that
only changes the specific settings one is interested in. Note
that multiple such drop-in files are read if present, processed
in lexicographic order of their filename.
The advantage of the first method is that one easily overrides
the complete unit, the vendor unit is not parsed at all anymore.
It has the disadvantage that improvements to the unit file by the
vendor are not automatically incorporated on updates.
The advantage of the second method is that one only overrides the
settings one specifically wants, where updates to the unit by the
vendor automatically apply. This has the disadvantage that some
future updates by the vendor might be incompatible with the local
changes.
This also applies for user instances of systemd, but with
different locations for the unit files. See the section on unit
load paths for further details.
Suppose there is a vendor-supplied unit
/usr/lib/systemd/system/httpd.service with the following
contents:
[Unit]
Description=Some HTTP server
After=remote-fs.target sqldb.service
Requires=sqldb.service
AssertPathExists=/srv/webserver
[Service]
Type=notify
ExecStart=/usr/sbin/some-fancy-httpd-server
Nice=5
[Install]
WantedBy=multi-user.target
Now one wants to change some settings as an administrator:
firstly, in the local setup, /srv/webserver might not exist,
because the HTTP server is configured to use /srv/www instead.
Secondly, the local configuration makes the HTTP server also
depend on a memory cache service, memcached.service, that should
be pulled in (Requires=) and also be ordered appropriately
(After=). Thirdly, in order to harden the service a bit more, the
administrator would like to set the PrivateTmp= setting (see
systemd.exec(5) for details). And lastly, the administrator would
like to reset the niceness of the service to its default value of
0.
The first possibility is to copy the unit file to
/etc/systemd/system/httpd.service and change the chosen settings:
[Unit]
Description=Some HTTP server
After=remote-fs.target sqldb.service memcached.service
Requires=sqldb.service memcached.service
AssertPathExists=/srv/www
[Service]
Type=notify
ExecStart=/usr/sbin/some-fancy-httpd-server
Nice=0
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
Alternatively, the administrator could create a drop-in file
/etc/systemd/system/httpd.service.d/local.conf with the following
contents:
[Unit]
After=memcached.service
Requires=memcached.service
# Reset all assertions and then re-add the condition we want
AssertPathExists=
AssertPathExists=/srv/www
[Service]
Nice=0
PrivateTmp=yes
Note that for drop-in files, if one wants to remove entries from
a setting that is parsed as a list (and is not a dependency),
such as AssertPathExists= (or e.g. ExecStart= in service units),
one needs to first clear the list before re-adding all entries
except the one that is to be removed. Dependencies (After=, etc.)
cannot be reset to an empty list, so dependencies can only be
added in drop-ins. If you want to remove dependencies, you have
to override the entire unit.
Example 3. Top level drop-ins with template units
Top level per-type drop-ins can be used to change some aspect of
all units of a particular type. For example by creating the
/etc/systemd/system/service.d/ directory with a drop-in file, the
contents of the drop-in file can be applied to all service units.
We can take this further by having the top-level drop-in
instantiate a secondary helper unit. Consider for example the
following set of units and drop-in files where we install an
OnFailure= dependency for all service units.
/etc/systemd/system/failure-handler@.service:
[Unit]
Description=My failure handler for %i
[Service]
Type=oneshot
# Perform some special action for when %i exits unexpectedly.
ExecStart=/usr/sbin/myfailurehandler %i
We can then add an instance of failure-handler@.service as an
OnFailure= dependency for all service units.
/etc/systemd/system/service.d/10-all.conf:
[Unit]
OnFailure=failure-handler@%N.service
Now, after running systemctl daemon-reload
all services will have
acquired an OnFailure= dependency on failure-handler@%N.service.
The template instance units will also have gained the dependency
which results in the creation of a recursive dependency chain. We
can break the chain by disabling the drop-in for the template
instance units via a symlink to /dev/null:
mkdir /etc/systemd/system/failure-handler@.service.d/
ln -s /dev/null /etc/systemd/system/failure-handler@.service.d/10-all.conf
systemctl daemon-reload
This ensures that if a failure-handler@.service instance fails it
will not trigger an instance named
failure-handler@failure-handler.service.