Fedora systemd Services
This document describes the guidelines for systemd services, for use and inclusion in Fedora packages.
Definitions
Since systemd includes some concepts which are extensions of previous concepts, the following definitions may be useful:
Service: A process or task executed and controlled by the init system
(e.g. systemd). + Traditional Service: A service which is explicitly started
or stopped, either by the init system at boot or manually by a superuser. In
systemd, one of several types of service controlled by a .service
file. + Activated service: A service that is not (or not necessarily)
started explicitly by the user but start when certain other events happen or
certain state becomes true. + Socket-activated Service: A service which is
waiting for traffic across a socket before activating. In systemd,
controlled by a .socket
file. + D-Bus service: A service which activates
in response to a message from the D-Bus system bus. + Unit file: The systemd
equivalent of a SysV initscript.
Unit Files
Each package that contains software that wants/needs to start a traditional service at boot MUST have a systemd unit file.
Ideally, systemd unit files are reusable across distributions and shipped with the upstream packages. Please consider working with upstream to integrate the systemd files you prepare in the upstream sources. Information for developers on how to integrate systemd support best with their build system you may find in daemon(8).
Naming
Unit files for traditional services have a naming scheme of
foobar.service. When considering what basename to use, keep in mind that
we’d like to use the same service names for software across
distributions. We’d also like to ship the .service
files in the upstream
packages. These desires create a few guides for naming a unit file:
-
Follow upstream if they’re already distributing a
.service
file and it’s not likely to conflict with other packages. -
Look at packages in other distros or talk with the maintainers of those packages and upstream to try to come up with a common name.
-
Unit files should be named after the software implementation that they support as opposed to the generic type of software. So, a good name would be
apache-httpd.service
and bad names would behttpd.service
orapache.service
as there are multiple httpd implementations and multiple projects produced by the apache foundation.
For backwards compatibility you may also want to create a symlink from an
older, name to the new name. In the above example, for instance, Fedora has
always used httpd
for the service. When creating the new
apache-httpd.service
file, also create a symlink named httpd.service
that points at apache-httpd.service
. Then end users that are used to
using service httpd
will have it continue to work.
Basic format
[Unit]
Every .service
file must begin with a [Unit]
section:
[Unit] Description=A brief human readable string describing the service (not the .service file!) Documentation=man:foo.service(8) man:foo.conf(5) http://www.foo.org/docs/
The Description=
line must not exceed 80 characters, and must describe
the service, and not the .service
file. For example, "Apache Web Server"
is a good description, but "Starts and Stops the Apache Web Server" is a bad
one.
Documentation field
Systemd in Fedora 17+ has support for defining documentation in unit files
via the Documentation=
field (it is ignored in older releases, so it is
safe to keep one systemd unit file across all branches). System
administrators will be looking at the contents of the Documentation=
field
to determine what the service is, how to configure it, and where to locate
additional documentation relating to the service. Accordingly, packagers are
strongly encouraged to include any available sources in the Documentation=
field which provide this information. If a man page or info page is present
in the package, refer to it using man:manpage
or info:infofile
respectively. If the documentation is in plaintext, use
file://path/to/file
. Lastly, if no local documentation exists in the
package, but it exists at a URL, use the URL (with http://
) in this
field. Multiple URIs can be added to the Documentation=
field, as a space
separated list. For details on URI definitions and formatting, please refer
to the uri(7)
manpage (man uri
).
[Service]
Next, the .service
file must have a [Service]
section:
[Service] Type=... ExecStart=... ExecReload=...
The Type=
setting is very important. For D-Bus services this should be
"dbus", for traditional services "forking" is usually a good idea, for
services not offering any interfaces to other services "simple" is best.
For "one-shot" scripts "oneshot" is ideal, often combined with
RemainAfterExit=
. See
systemd.service(5)
for further discussion on the topic. Since "simple" is the default type,
.service
files which would normally set Type=simple
may simply omit
the Type
line altogether.
BusName=
should be set for all services connecting to D-Bus. (i.e. it is
a must for those where Type=dbus
, but might make sense otherwise, too)
Omit this option if your service does not take a name on the bus.
ExecStart=
is necessary for all services. This line defines the string
that you would run to start the daemon, along with any necessary options.
ExecReload=
should be specified for all services supporting reload. It
is highly recommended to add code here that synchronously reloads the
configuration file here (i.e. /bin/kill -HUP $MAINPID
is usually a poor
choice, due to its asynchronous nature). Omit this option if your service
does not support reloading.
[Install]
Finally, the .service
file should have an [Install]
section:
[Install] WantedBy=...
The recommended parameters for WantedBy=
are either graphical.target
(services related to the graphical user interface) or multi-user.target
(for everything else). When the user (or our scriptlets) invoke systemctl
enable
the service will be set to start in these targets.
For more information regarding these options see systemd.unit(5) and systemd.service(5).
EnvironmentFiles and support for /etc/sysconfig files
The EnvironmentFiles=
line in the [Service]
section of .service
files is used to support loading environment variables that can be used in
unit files. For instance, if your sysv-initscript used a file in
/etc/sysconfig to set command line options, you can use
EnvironmentFiles=
like so:
Example:
[Service] Type=forking EnvironmentFile=-/etc/sysconfig/httpd ExecStart=/usr/sbin/httpd $OPTIONS ExecReload=/usr/sbin/httpd $OPTIONS -k restart
You may then refer to variables set in the /etc/sysconfig/httpd
file
with ${FOOBAR}
and $FOOBAR
, in the ExecStart=
lines (and related
lines). (${FOOBAR}
expands the variable into one word, $FOOBAR
splits up the variable value at whitespace into multiple words)
The "-" on the EnvironmentFile=
line ensures that no error messages is
generated if the environment file does not exist. Since many of these files
were optional in sysvinit, you should include the "-" when using this
directive.
Fields to avoid
For most services, we do not want to use requirement dependencies in the
[Unit]
section, such as Requires=
or Wants=
. Instead exclusively
use ordering dependencies: Before=
and After=
. This is used to
implement loose coupling: if someone asks two services to start at the same
time, systemd will properly order their startup but not make it strictly
necessary to run one if the other is started.
If you use a requirement dependency, use Wants=
rather than
Requires=
, to make things a little bit more robust. If you use a
requirement dependency in almost all cases you should also add an ordering
dependency, as ordering and requirement dependencies are orthogonal in
systemd.
Here’s an example of this common case:
-
A web application needs postgresql to store its data.
-
It is set to start
After
postgresql. On startup, the web application does not start until postgresql does. -
Once running, the system administrator needs to restart postgresql due to a config tweak.
-
Since only
After
was used, the web application may be temporarily unable to serve some requests but it does not need to restart in order to serve pages after the database comes back up.
Avoid referring to runlevelX.target
units in all lines taking unit names
(such as WantedBy
), these are legacy names existing for compatibility
with SysV only.
Avoid Names=
(in the [Unit]
section). Usually it is a better idea to
symlink an additional name in the file system. Note that a name listed in
Names=
is only useful when a service file is already loaded. However,
systemd loads only the service files actually referred to in another loaded
service, and uses the filenames during the search. Hence a name in
Names=
is not useful as a search key, but a symlink in the file system
is. Also do not put a (redundant) Names=foobar.service
line into a file
called foobar.service
. We want to keep our service files short.
Unit files should avoid using StandardOutput=
or StandardError=
. The
default is the right choice for almost all cases, and using the default
allows users to change global defaults in /etc/systemd/system.conf.
Activation
Systemd allows for three forms of activated services: #Hardware activation, #Socket activation, and #DBus activation.
Hardware activation
Hardware activation occurs when a service is installed but only turns on if
a certain type of hardware is installed. Enabling of the service is normally
done with a udev rule. At this time we do not have further guidance on how
to write those udev rules. The service itself installs its .service
files in the normal places and are installed by the normal
systemd scriptlets. These services should
never be enabled by the package as they will be enabled by udev.
Socket activation
Socket activation occurs when a service allows systemd to listen for
connections to a specific socket and, when systemd receives a connection on
that socket, it starts the service. To do this, the upstream source needs to
have some minor coding work to let systemd listen for connections on the
socket and there needs to be a .socket
file in
%{_lib}/systemd/system/
that tells systemd to listen to that socket and
what to start when a connection is received. This is similar in function to
inetd and some, but not all, services coded to work with inetd will work
with socket activation.
However, socket activation can also be used to allow parallel startup of
services. If a service supports systemd socket activation as described above
and we additionally start it explicitly on boot, then systemd will start it
but allow things that depend on it to startup at the same time. If the
dependent service makes a request to the socket activatable service before
it has come up, then systemd will cause the request to wait until the socket
activatable service has come up and can process the request. To achieve this
effect, the service must be socket activatable as described above, the
.service
file for the service needs to have a Wants=
line for the
.socket
, and the service must autostart.
Note that certain socket activated services (notably network listening ones)
require FESCo approval - see
Packaging:DefaultServices for details. Once you
have permission, you can package the .socket
file and use the systemd
scriptlets that enable the service by default. You need to also check the
.service
file to make sure it has a Wants=
entry on the .socket
file as that ensures that starting the service will also inform systemd of
the socket.
Timer activation
All packages with timed execution which already depend on systemd (for example because they contain systemd units) must use timer units instead of cron jobs, with no dependency or requirements on a crontab.
Packages which do not already depend or require systemd must not use timer units but instead depend and have requirement on crontabs, to avoid introducing unnecessary new dependencies on systemd directly.
DBus activation
In order to allow parallel startup of a D-Bus service and its consumers it
is essential that D-Bus services can be bus activated and the D-Bus
activation request is forwarded from the D-Bus system bus to systemd so that
you end up with only a single instance of the service, even if a service is
triggered by both boot-up and activation. If historically your D-Bus service
was not bus-activated but started via a SysV init script, it should be
updated to use bus activation. This may be implemented by dropping a D-Bus
.service
file in /usr/share/dbus-1/system-services/
and use the
SystemdService=
directive therein to redirect the activation to systemd.
Here’s an example for a D-Bus bus-activable service. The ConsoleKit bus activation file /usr/share/dbus-1/system-services/org.freedesktop.ConsoleKit.service:
[D-BUS Service] Name=org.freedesktop.ConsoleKit Exec=/usr/sbin/console-kit-daemon --no-daemon User=root SystemdService=console-kit-daemon.service
And the matching systemd unit file /usr/lib/systemd/system/console-kit-daemon.service:
[Unit] Description=Console Manager [Service] Type=dbus BusName=org.freedesktop.ConsoleKit ExecStart=/usr/sbin/console-kit-daemon --no-daemon
As you can see SystemdService=
is used in the D-Bus activation file to
bind the systemd service to the D-Bus service.
Traditionally, bus activated D-Bus services could not be disabled without uninstalling them entirely. systemd allows you to disable services by making D-Bus invoke an alias systemd service name (that can be created or removed to enable/disable activation) as an intermediary for the real service.
You can easily implement disabling by directing the D-Bus service to an
alias name of the real service file (in the filesystem this shows up as a
symlink placed in /etc/systemd/system to the real service file). This alias
is then controlled via "systemctl enable" and "systemctl disable". It is a
good idea (though technically not necessary) to name this alias name after
the D-Bus bus name of the service, prefixed with "dbus-". Example for Avahi,
a service that the admin might need to disable: set
SystemdService=dbus-org.freedesktop.Avahi.service
instead of
SystemdService=avahi-daemon.service
in the D-Bus activation file, and
then make dbus-org.freedesktop.Avahi.service
an optional alias of
avahi-daemon.service that can be controlled via the Alias=
directive in
the [Install]
section of the systemd service file. This directive is
then read by "systemctl enable" and "systemctl disable" to create
resp. remove a symlink to make the service available resp. unavailable under
this additional name. A full example for the Avahi case:
Here is the D-Bus .service file for Avahi (/usr/share/dbus-1/system-services/org.freedesktop.Avahi.service):
[D-BUS Service] Name=org.freedesktop.Avahi SystemdService=dbus-org.freedesktop.Avahi.service # This service should not be bus activated if systemd isn't running, # so that activation won't conflict with the init script startup. Exec=/bin/false
Here is the Avahi systemd unit .service
file
(/usr/lib/systemd/system/avahi-daemon.service):
[Unit] Description=Avahi mDNS/DNS-SD Stack Requires=avahi-daemon.socket [Service] Type=dbus BusName=org.freedesktop.Avahi ExecStart=/usr/sbin/avahi-daemon -s ExecReload=/usr/sbin/avahi-daemon -r NotifyAccess=main [Install] WantedBy=multi-user.target Also=avahi-daemon.socket Alias=dbus-org.freedesktop.Avahi.service
The Alias=
line ensures that the existance of the
/etc/systemd/system/dbus-org.freedesktop.Avahi.service symlink can be
controlled by "systemctl enable" and "systemctl disable".
Note that the creation/removal of the alias symlinks should be done with "systemctl enable" and "systemctl disable" only. You should not create these symlinks manually.
In general, it is also recommended to supply native systemd units for all services that are already bus activatable, so that these services can be controlled and supervised centrally like any other service with tools such as systemctl. A similar logic like the one shown above should apply.
See the D-Bus documentation for more information about bus activation: http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-starting-services
Automatic restarting
If you package a long-running service, please consider enabling systemd’s automatic restart feature for it, to improve reliability by making sure the system automatically attempts recovering a failing daemon. Please use
[Service] ... Restart=on-failure
or
[Service] ... Restart=on-abnormal
in your unit’s .service
file for this.
The former will tell systemd to restart the daemon as soon as it fails
regardless of the precise reason. It’s a good choice for most long-running
services. Some daemons require a way to escape constant restarting by
exiting with any non-zero exit code. For those services use
Restart=on-abnormal
, which will still restart the daemon when it fails
"abnormally", on unclean signal, core dump, timeout or watchdog exits, but
not on unclean exit codes. It is recommended to to enable automatic restarts
for all long-running services, but which setting is the right one, and
whether it is useful at all depends on the specific service. Please consult
the
systemd.service(5)
man page for more information on the various settings.
Private devices and networking
If you package a long-running system service, please consider enabling
systemd’s PrivateDevices=
and PrivateNetwork=
settings for it, in
order to improve security and minimize the attack surface.
When PrivateDevices=yes
is set in the [Service] section of a systemd
service unit file, the processes run for the service will run in a private
file system namespace where /dev is replaced by a minimal version that only
includes the device nodes /dev/null, /dev/zero, /dev/full, /dev/urandom,
/dev/random, /dev/tty as well as the submounts /dev/shm, /dev/pts,
/dev/mqueue, /dev/hugepages, and the /dev/stdout, /dev/stderr, /dev/stdin
symlinks. No device nodes for physical devices will be included,
however. Furthermore, the CAP_MKNOD capability is removed. Finally, the
"devices" cgroup controller is used to ensure that no access to device nodes
except the listed ones is possible. This is an efficient way to take away
physical device access for services, thus minimizing the attack surface.
When PrivateNetwork=yes
is set in the [Service] section of a systemd
service unit file, the processes run for the service will run in a private
network namespace whith a private loopback network interface, and no other
network devices. Network communication between host and service can not be
initiated. This is an efficient way to take away network access for
services, thus minimizing the attack surface.
By default both switches default to "no".
Note that PrivateDevices=yes
should not be used for:
-
Services that actually require physical device access
-
Services which may be used to execute arbitrary user or administrator supplied programs (such as cron, …). We shouldn’t limit what people can do with these services.
-
This option creates a new file system namespace where mount/umount propagation is turned off back into the host. This means that mounts made by the service will stay private to the service. Thus this option should not be used by services which shall be able to establish mounts in the host.
Note that PrivateNetwork=yes
should not be used for:
-
Services that actually require network access (with the exception of daemons only needing socket activation)
-
Services which may be used to execute arbitrary user or administrator supplied programs. (see above)
-
Services which might need to resolve non-system user and group names. Since on some setups resolving non-system users might require network access to an LDAP or NIS server, enabling this option on might break resolving of these user names. Note however that system users/groups are always resolvable even without network access. Hence it is safe to enable this option for daemons which just need to resolve their own system user or group name.
-
This also disconnects the AF_UNIX abstract namespace from the host (In case you wonder what this refers to: sockets listed in /proc/net/unix that start with an @ are in the abstract namespace, those which start in / are in the file system namespace). This means that services which listen or connect to AF_UNIX sockets in the abstract namespaces might break. AF_UNIX sockets in the file system continue to work correctly even with PrivateNetwork?=yes. We strongly recommend anyway to stop using abstract namespace AF_UNIX sockets, as they bring very little benefit these days. If your package uses them please consider moving them into the file system into a subdirectory in /run (system services) or $XDG_RUNTIME_DIR (user services).
-
This also disconnects the AF_NETLINK and AF_AUDIT socket families from the host. For services requiring auditing, that need to subscribe to network configuration changes, or want to subscribe to hardware devices coming and going (udev) PrivateNetwork?=yes cannot be used hence.
For further details see the systemd.exec(5) man page.
Packaging
Filesystem locations
Packages with systemd unit files must put them into
%{_unitdir}
. %{_unitdir}
evaluates to /usr/lib/systemd/system on all
Fedora systems (F-15+). Unit files are architecture independent (hence, not
%{_lib}
) and needed early in the boot process.
Please note that in order for the %{_unitdir}
macro to exist, your
package must have:
BuildRequires: systemd-rpm-macros
Unit files in spec file scriptlets
Information on proper handling of unit files in spec file scriptlets can be found here: Packaging:Scriptlets#Systemd.
Tmpfiles.d
tmpfiles.d is a service provided systemd in Fedora 15 and later for managing temporary files and directories for daemons. For more information on how to use Tmpfiles.d in Fedora Packages, please see: Packaging:Tmpfiles.d.