Writing systemd Unit Files
When writing systemd unit files, it is recommended to consider
the following suggestions:
1. If possible, do not use the Type=forking setting in service
files. But if you do, make sure to set the PID file path
using PIDFile=. See systemd.service(5) for details.
2. If your daemon registers a D-Bus name on the bus, make sure
to use Type=dbus in the service file if possible.
3. Make sure to set a good human-readable description string
with Description=.
4. Do not disable DefaultDependencies=, unless you really know
what you do and your unit is involved in early boot or late
system shutdown.
5. Normally, little if any dependencies should need to be
defined explicitly. However, if you do configure explicit
dependencies, only refer to unit names listed on
systemd.special(7) or names introduced by your own package to
keep the unit file operating system-independent.
6. Make sure to include an [Install] section including
installation information for the unit file. See
systemd.unit(5) for details. To activate your service on
boot, make sure to add a WantedBy=multi-user.target or
WantedBy=graphical.target directive. To activate your socket
on boot, make sure to add WantedBy=sockets.target. Usually,
you also want to make sure that when your service is
installed, your socket is installed too, hence add
Also=foo.socket in your service file foo.service, for a
hypothetical program foo.
Installing systemd Service Files
At the build installation time (e.g. make install
during package
build), packages are recommended to install their systemd unit
files in the directory returned by pkg-config systemd
--variable=systemdsystemunitdir
(for system services) or
pkg-config systemd --variable=systemduserunitdir
(for user
services). This will make the services available in the system on
explicit request but not activate them automatically during boot.
Optionally, during package installation (e.g. rpm -i
by the
administrator), symlinks should be created in the systemd
configuration directories via the enable
command of the
systemctl(1) tool to activate them automatically on boot.
Packages using autoconf
(1) are recommended to use a configure
script excerpt like the following to determine the unit
installation path during source configuration:
PKG_PROG_PKG_CONFIG
AC_ARG_WITH([systemdsystemunitdir],
[AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],,
[with_systemdsystemunitdir=auto])
AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [
def_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
AS_IF([test "x$def_systemdsystemunitdir" = "x"],
[AS_IF([test "x$with_systemdsystemunitdir" = "xyes"],
[AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])])
with_systemdsystemunitdir=no],
[with_systemdsystemunitdir="$def_systemdsystemunitdir"])])
AS_IF([test "x$with_systemdsystemunitdir" != "xno"],
[AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])])
AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"])
This snippet allows automatic installation of the unit files on
systemd machines, and optionally allows their installation even
on machines lacking systemd. (Modification of this snippet for
the user unit directory is left as an exercise for the reader.)
Additionally, to ensure that make distcheck
continues to work, it
is recommended to add the following to the top-level Makefile.am
file in automake
(1)-based projects:
AM_DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
Finally, unit files should be installed in the system with an
automake excerpt like the following:
if HAVE_SYSTEMD
systemdsystemunit_DATA = \
foobar.socket \
foobar.service
endif
In the rpm(8) .spec file, use snippets like the following to
enable/disable the service during installation/deinstallation.
This makes use of the RPM macros shipped along systemd. Consult
the packaging guidelines of your distribution for details and the
equivalent for other package managers.
At the top of the file:
BuildRequires: systemd
%{?systemd_requires}
And as scriptlets, further down:
%post
%systemd_post foobar.service foobar.socket
%preun
%systemd_preun foobar.service foobar.socket
%postun
%systemd_postun
If the service shall be restarted during upgrades, replace the
"%postun" scriptlet above with the following:
%postun
%systemd_postun_with_restart foobar.service
Note that "%systemd_post" and "%systemd_preun" expect the names
of all units that are installed/removed as arguments, separated
by spaces. "%systemd_postun" expects no arguments.
"%systemd_postun_with_restart" expects the units to restart as
arguments.
To facilitate upgrades from a package version that shipped only
SysV init scripts to a package version that ships both a SysV
init script and a native systemd service file, use a fragment
like the following:
%triggerun -- foobar < 0.47.11-1
if /sbin/chkconfig --level 5 foobar ; then
/bin/systemctl --no-reload enable foobar.service foobar.socket >/dev/null 2>&1 || :
fi
Where 0.47.11-1 is the first package version that includes the
native unit file. This fragment will ensure that the first time
the unit file is installed, it will be enabled if and only if the
SysV init script is enabled, thus making sure that the enable
status is not changed. Note that chkconfig
is a command specific
to Fedora which can be used to check whether a SysV init script
is enabled. Other operating systems will have to use different
commands here.