The simplest method I've found for starting a persistent background service via systemd, which may be handy since you can then get it to report on subprocesses currently running as children via systemctl status ...
, etc., is via a service file like this:
[Unit]
Description=My Service
Requires=local-fs.target
After=rsyslog.service
[Service]
Type=forking
GuessMainPID=no
StandardInput=null
ExecStart=/absolute/path/to/wrapperScript.sh
[Install]
WantedBy=default.target
Some commentary:
The Description
will appear in the system log and boot console output.
You almost certainly want at least that Requires
.
The After=rsyslog
is not a necessity, and After
itself differs from Requires
in that the latter is an explicit dependency, whereas After
just means if rsyslog.service
is being run, start this afterward (see man systemd.unit
). Pretty sure Raspbian does use that by default, so this is not a bad thing to have and harmless in any case.
Type=forking
and the two next two lines are important.
If myservice
is capable of backgrounding itself, e.g., via a commandline parameter, you could specify it here. However, IMO using wrapperScript
is simpler and more flexible; keep reading.
Here's what wrapperScript.sh
might look like:
#!/bin/bash
log=/var/log/myservice.log
export PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin
exec &>>$log
echo $(date +"%D %T")" Starting..."
( exec /absolute/path/to/myservice -port :1234 &>>$log ) &
exit 0
Some commentary:
Use #!/bin/bash
, not #!/bin/sh
, because &>>
is a bashism meaning append redirect all output (standard and error). If you want to overwrite the log each time, make the first use &>
.
You can set $PATH
however you like, just beware it probably won't be set to anything by default, at least when this is started at boot by systemd.
The reason to redirect output to a log from the beginning, and output "Starting..." (actually it will look like 08/02/16 15:25:29 Starting...
) is in case something subsequently doesn't work out; you can at least confirm you got to this point. Note that when run at boot on a Pi without an RTC the timestamp won't be valid unless ntpd
has already done its work, which is unlikely. And there's no dependency available for the time being set right via ntp as far as I'm aware, so don't bother trying.
The format of the subshell exec
and fork (&
) is important. This ensures that your process replaces the shell instead of being run within it (actually that isn't that important, but it is tidier) and that this service fulfills the promise made in the service file, vis. Type=forking
. Which is critical.
The exit status doesn't mean systemd will assume the service has executed successfully; if a child process (myservice
) then exits with a non-zero status, it will count as failed.
I use this pattern with all kinds of things and for me, it is the simplest, most foolproof and flexible method without having to rely too much on subtleties of systemd features. Put another way, there is no doubt a more proper way, from a systemd usage perspective, to get more-or-less the same result, but for that you'll have to spend some time delving through the documentation, experimenting, and hoping your assumptions are correct. By instead using a simple shell controlled fork, we take the power back so to speak.
BTW (includes a few caveats):
You don't have to install this to run at boot in order to use it. Just leave a copy of the service file owned root in /etc/systemd/system
with the suffix .service
, run sudo systemctl daemon-reload
, and you can then use systemctl start whatever
to run it and systemctl status whatever
to check on it.
If you do want to install it to run at boot, use sudo systemctl enable whatever
and it will be included in default.target
.
This doesn't include any kind of "stop" behaviour. The process will be politely killed at shutdown/reboot which is fine for most things. If you want to stop myservice
, just sudo kill
it. It doesn't include any kind of restart either, hopefully you can figure out the logic for that.
ssh
it will work initially, but may be liable to mysteriously disappear a while after you disconnect. To get around that, have a look atman setsid
; this will ensure the process is re-parented by init. – goldilocks Aug 02 '16 at 19:04&
not thesetsid
thing) will not survive closing the ssh session.nohup
,tmux
orscreen
are worth investigating - if manual start is desired. – Ghanima Aug 02 '16 at 19:04supervisord
(easy to use) – Ghanima Aug 02 '16 at 19:07setsid
will survive and is probably a more robust choice thannohup
, which depends on the OS voluntarily reparenting (which it will, i.e., they both work, but at some point I noticedsetsid
is more reliable...YMMV). – goldilocks Aug 02 '16 at 19:53setsid
as I typed it without knowing your post. It was merely wrt the ampersand. – Ghanima Aug 02 '16 at 20:07