One of the systemd feature is to create the init service unit file for starting your program automatically at different run levels without manual and explicit call out. The full documentation is available at: https://wiki.debian.org/systemd/Services. This section guides you on how to write such unit file.
This section covers all the file properties.
Systemd unit file is stored under various locations, notably:
/usr/local/lib/systemd/system
/etc/systemd/system
/etc/systemd/user
$HOME/.config/systemd/user
When placing the unit file, one must ensures the access is available for execution (e.g. read and execute permission).
Unit file carries a strict ".service
" file extension.
Now you need to determine the service types.
simple
- basic startup based on ExecStart= is specified but neither Type= nor BusName= are. the unit started immediately after the main service process has been forked off. Note that this means systemctl start command lines for simple services will report success even if the service's binary cannot be invoked successfully (for example because the selected User= doesn't exist, or the service binary is missing).exec
- The exec type is similar to simple, but the service manager will consider the unit started immediately after the main service binary has been executed. The service manager will delay starting of follow-up units until that point. Note that this means systemctl start command lines for exec services will report failure when the service's binary cannot be invoked successfully (for example because the selected User= doesn't exist, or the service binary is missing).forking
- it is expected that the process configured with ExecStart= will call fork() as part of its start-up. The parent process is expected to exit when start-up is complete and all communication channels are set up. The child continues to run as the main service process, and the service manager will consider the unit started when the parent process exits.oneshot
- Behavior of oneshot is similar to simple; however, the service manager will consider the unit started after the main process exits.dbus
- Behavior of dbus is similar to simple; however, it is expected that the service acquires a name on the D-Bus bus, as configured by BusName=.notify
- it is expected that the service sends a notification message via sd_notify(3) or an equivalent call when it has finished starting up.idle
- Behavior of idle is very similar to simple; however, actual execution of the service program is delayed until all active jobs are dispatched.In any cases, always choose simple
is good enough.
Depending on your program, some daemon requires a different environment (chkroot
) to operate properly. You can also restrict the service run. There are so many configurations available that you want to refer to the man page:
$ man systemd.exec.5
Among the common ones are:
WorkingDirectory= (change directory before executing processes)
RootDirectory= (chroot)
User=
Group=
UMask=
Environment= (variables)
The next thing is to set the start point, dependencies, and defining its init position. Keep in mind that Systemd facilitates parallelism so you need to coordinate your program accordingly. Among them are:
Before=
(services that requires ours to run before theirs)After=
(services that must be started before ours)WantedBy=
(required services due to dependencies .including run level)Run level definition is available at its man page or http://refspecs.linuxfoundation.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/runlevels.html:
$ man systemd.unit.5
Generally, for run levels, there are:
poweroff.target
(and runlevel0.target
is a symbolic link to it).rescue.target
(and runlevel1.target
is a symbolic link to it).multi-user.target
(and runlevel3.target
is a symbolic link to it).graphical.target
(and runlevel5.target
is a symbolic link to it).reboot.target
(and runlevel6.target
is a symbolic link to it).emergency.target
.To query service, you can use:
$ systemctl list-units --all --type service
$ systemctl list-units --all --type target
If we put all the above together, we should get a following example:
# Contents of /selected/location/myservice.service
[Unit]
Description=This is my service
After=network.target
Before=udisk2.service
[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/myservice start
ExecStop=/usr/local/bin/myservice stop
[Install]
WantedBy=multi-user.target
After placing the service unit file into the corresponding location, you can proceed to test it. Try the following command accordingly:
$ systemctl daemon-reload
$ systemctl enable myservice.service
$ systemctl start myservice.service
$ systemctl stop myservice.service
$ systemctl disable myservice.service
That's all for writing systemd init service unit file.