4

I made a program in Go. That program compiles and runs very well on the raspi, when I start it via ssh. To start the program correct, I need to set some flags.

myservice -port :1234

The program is a microservice, which is a simple http server. Now I want the program to run in the background, also when I am not connected via ssh. I tried different solutions to use systemd, but it didn't work. What is a simple solution to get my program run in the background?

  • 1
    Have you tried appending " &" (without the quotes but with a leading space) to the end of the command? – Steve Robillard Aug 2 '16 at 18:44
  • No. Not until now. But that looks good. – apxp Aug 2 '16 at 18:47
  • Beware if you do that via ssh it will work initially, but may be liable to mysteriously disappear a while after you disconnect. To get around that, have a look at man setsid; this will ensure the process is re-parented by init. – goldilocks Aug 2 '16 at 19:04
  • 1
    ... but that (the & not the setsid thing) will not survive closing the ssh session. nohup, tmux or screen are worth investigating - if manual start is desired. – Ghanima Aug 2 '16 at 19:04
  • 1
    ... and here's your bronze badge Moderator Overflow – Ghanima Aug 2 '16 at 19:25
5

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.