Keeping Syncthing Running: Systemd & regular /etc/init.d

A couple more options: one for a systemd service file:

[Unit]
Description=Syncthing service for %i
After=network.target

[Service]
User=%i
Environment=STNORESTART=yes
ExecStart=/usr/bin/syncthing
Restart=on-success

[Install]
WantedBy=multi-user.target

And a debian init.d script based on the btsync one:

#!/bin/sh
### BEGIN INIT INFO
# Provides: syncthing
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $network
# Should-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Multi-user daemonized version of syncthing.
# Description: Starts the syncthing daemon for all registered users.
### END INIT INFO

# Replace with users you want to run syncthing clients for
syncthing_USERS="<your name here>"
DAEMON=/usr/local/bin/syncthing

startd() {
  for stuser in $syncthing_USERS; do
    HOMEDIR=$(getent passwd $stuser | awk -F: '{print $6}')
    if [ -f $config ]; then
      echo "Starting syncthiing for $stuser"
      start-stop-daemon -b -o -c $stuser -S -u $stuser -x $DAEMON
    else
      echo "Couldn't start syncthing for $stuser (no $config found)"
    fi
  done
}

stopd() {
  for stuser in $syncthing_USERS; do
    dbpid=$(pgrep -fu $stuser $DAEMON)
    if [ ! -z "$dbpid" ]; then
      echo "Stopping syncthing for $stuser"
      start-stop-daemon -o -c $stuser -K -u $stuser -x $DAEMON
    fi
  done
}

status() {
  for stuser in $syncthing_USERS; do
    dbpid=$(pgrep -fu $stuser $DAEMON)
    if [ -z "$dbpid" ]; then
      echo "syncthing for USER $stuser: not running."
    else
      echo "syncthing for USER $stuser: running (pid $dbpid)"
    fi
  done
}

case "$1" in
  start) startd
    ;;
  stop) stopd
    ;;
  restart|reload|force-reload) stopd && startd
    ;;
  status) status
    ;;
  *) echo "Usage: /etc/init.d/syncthing {start|stop|reload|force-reload|restart|status}"
     exit 1
   ;;
esac

exit 0

And one for OSX (from this Github issue):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>se.nym.syncthing</string>
    <key>Program</key>
    <string>/usr/local/bin/syncthing</string>
    <key>EnvironmentVariables</key>
    <dict>
        <key>HOME</key>
        <string>/Users/yourusername</string>
        <key>STNORESTART</key>
        <string>1</string>
    </dict>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
5 Likes

Hi following your steps (the init.d script), syncthing worked great in debian wheezy (raspbian) and also in Ubuntu 13.04, but when applying the same steps in CentOS 6.5, I have the following warning: /etc/init.d/syncthing: line 25: start-stop-daemon: command not found

do I have to make some changes in the script or I am completely wrong ? (I am a somekind of newbie and so confused between systemd - init.d)

regards

Didn’t Centos switch to Upstart? There is a script for that

Here is the simple Gentoo init.d script I use:

# cat /etc/init.d/syncthing-daemon

#!/sbin/runscript
# Distributed under the terms of the GNU General Public License v2

description="Syncthing replaces Dropbox and BitTorrent Sync with something open, trustworthy and decentralized."
description_start="Start syncthing-daemon server and web interface"
description_stop="Stop syncthing-daemon server and web interface"

depend() {
	need net localmount
}

start() {
	ebegin "Starting syncthing daemon"
	start-stop-daemon \
	--start \
	--make-pidfile \
	--pidfile /var/run/syncthing.pid \
	--user YOURUSERHERE \
	--background \
	--exec /usr/bin/syncthing-linux-386/syncthing \
	--stdout /var/log/syncthing.log \
	--stderr /var/log/syncthing.log
	eend $?
}

stop() {
	ebegin "Stopping syncthing daemon"
	start-stop-daemon \
	--stop \
	--pidfile /var/run/syncthing.pid
	eend $?
}

this script uses bashisms ( $() construct ), so should have started with /bin/bash even if /bin/sh is bash on your system.

What? The POSIX spec disagrees

1 Like

What are the advantages and disadvantages of running via systemd/upstart versus a user-specific @reboot crontab daemon entry?

Basically with systemd / upstart, it’s easier to define more options (start, stop, restart, get status, define dependance (need working internet connection for instance), priority of the process at load [start after every disks are mounted and X display manager is running], user, log, make pidfile, etc.).

jasonwryan thanks for the init.d script. I think the status command is not completely correct. It won’t set a non-zero return when one or more of the syncthing instances for each of the users is not running. This screws up with things like puppet that will check the status output to see if they need to restart the service.

I had the same issue on Debian.

I seem to have solved it by adding:

PATH=${PATH}

Otherwise, it does not know where to find start-stop-daemon.

Under:

END INIT INFO

When using systemd I found that I needed to create the config file in the users scripts directory. In fedora 20 that was

/etc/systemd/users/syncthing.service

and to control the script you then need to use

systemctl --user start syncthing

If you want to use the built in upgrade capabilities you will need to stop the service

systemctl --user stop syncthing

and then run syncthing as root

sudo syncthing

Then perform the upgrade, shut it down and restart the service.

At least this was the only way I could do it as I ran into permission issues as the service obviously runs under your account and by default may not have access to update the binaries.

This is my version of init script for debian. As you can see it runs only one instance and reduces the priority of the process. Also need to add the update block, but that’s for later.

(Git)

#!/bin/sh
### BEGIN INIT INFO
# Provides: syncthing
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start: $network
# Should-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Syncthing Daemon
# Description: Syncthing replaces proprietary sync and cloud services with something open, 
#              trustworthy and decentralized. 
#              Your data is your data alone and you deserve to choose where it is stored, 
#              if it is shared with some third party and how it's transmitted over the Internet.
### END INIT INFO

PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Syncthing"
NAME=syncthing
# DIR should be the path to the folder where the binary resides
DIR=/usr/bin
DAEMON=$DIR/$NAME
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME

# Arguments that should be forwarded to the binary (e.g.: "-home=/etc/syncthing")
DAEMON_ARGS=""

# Permissions
USER=www-data
GROUP=www-data


[ -x "$DAEMON" ] || exit 0

. /lib/init/vars.sh
. /lib/lsb/init-functions

do_start() {
    if [ -e $PIDFILE ]; then
        PID=`cat $PIDFILE`

        if ( ps -p $PID > /dev/null ); then
            log_failure_msg "$DESC '$NAME' is already running."
            return 1
        else
            rm -f $PIDFILE

            start-stop-daemon --start --background --chdir $DIR --chuid $USER:$GROUP --make-pidfile --pidfile $PIDFILE --quiet --iosched idle --nicelevel 19 --exec $DAEMON --test > /dev/null || return 1
            start-stop-daemon --start --background --chdir $DIR --chuid $USER:$GROUP --make-pidfile --pidfile $PIDFILE --quiet --iosched idle --nicelevel 19 --exec $DAEMON -- $DAEMON_ARGS || return 2
        fi
    else
        start-stop-daemon --start --background --chdir $DIR --chuid $USER:$GROUP --make-pidfile --pidfile $PIDFILE --quiet --iosched idle --nicelevel 19 --exec $DAEMON --test > /dev/null || return 1
        start-stop-daemon --start --background --chdir $DIR --chuid $USER:$GROUP --make-pidfile --pidfile $PIDFILE --quiet --iosched idle --nicelevel 19 --exec $DAEMON -- $DAEMON_ARGS || return 2
    fi
}

do_stop() {
    if [ -e $PIDFILE ]; then
        PID=`cat $PIDFILE`

        if ( ps -p $PID > /dev/null ); then
            start-stop-daemon --stop --retry 1 --signal 2 --quiet --pidfile $PIDFILE
            [ "$?" = 2 ] && return 2
        else
            log_failure_msg "$DESC '$NAME' is not running."
            rm -f $PIDFILE
            return 1
        fi
    else
        log_failure_msg "$DESC '$NAME' is not running."
        return 1
    fi
}

case "$1" in
    start)
        log_daemon_msg "Starting $DESC..." "$NAME"
        do_start

        case "$?" in
            0|1) log_end_msg 0 ;;
            1) log_end_msg 1 ;;
        esac
    ;;
    stop)
        log_daemon_msg "Stopping $DESC..." "$NAME"
        do_stop

        case "$?" in
            0|1) log_end_msg 0 ;;
            2) log_end_msg 1 ;;
        esac
    ;;
    restart)
        log_daemon_msg "Restarting $DESC..." "$NAME"
        do_stop

        case "$?" in
            0|1)
                do_start

                case "$?" in
                    0) log_end_msg 0 ;;
                    *) log_end_msg 1 ;;
                esac
            ;;
            *)
                log_end_msg 1
            ;;
        esac
    ;;
    status)
        if [ -e $PIDFILE ]; then
            PID=`cat $PIDFILE`

            if ( ps -p $PID > /dev/null ); then
                log_success_msg "$DESC '$NAME' is running (pid $PID)."
                exit 0
            else
                log_failure_msg "$DESC '$NAME' is not running."
                rm -f $PIDFILE
                exit 1
            fi
        else
            log_failure_msg "$DESC '$NAME' is not running."
            exit 1
        fi
    ;;
    *)
        log_action_msg "Usage: $SCRIPTNAME {start|stop|restart|status}"
        exit 0
    ;;
esac

Hi, I am using syncthing as systemd user service via systemctl --user in arch linux. The user service file is the one from the 1st post. The service fails after syncthing tries to restart itself, e.g. after config update or suspend. Here is the systemd journal:

Okt 16 14:15:14 t-laptop syncthing[7515]: [GZKC7] 14:15:14 INFO: Paused state detected, possibly woke up from standby. Restarting in 1m0s. Okt 16 14:16:14 t-laptop syncthing[7515]: [GZKC7] 14:16:14 INFO: Restarting Okt 16 14:16:14 t-laptop syncthing[7515]: [GZKC7] 14:16:14 OK: Exiting Okt 16 14:16:14 t-laptop systemd[5885]: syncthing.service: main process exited, code=exited, status=3/NOTIMPLEMENTED Okt 16 14:16:14 t-laptop systemd[5885]: Unit syncthing.service entered failed state.

Does anyone have similiar issues? If I just run syncthing from the console, a restart via the web interface works.

Could anyone tell if the systemd user service works if installed in $XDG_CONFIG_HOME/systemd/user?

Thanks

I just looked a little bit closer and the service file works like this: if pulse/syncthing exists with exit code 0 then systemd will restart it, because it sets environment variable STNORESTART=yes so that pulse/syncthing will not restart but just exit. In my case pulse/syncthing exists with exit code 3, meaning program not running, therefore systemd will not restart it. I fixed it for me by adding SuccessExitStatus=3 to the [Service] of the systemd service file.

I looked at the source code, but I my knowledge of Go ends there :slight_smile: My question would be: What are possible exit codes and why it is not 0 in my case ?

Yeah sure, but you have to start it with: systemctl --user start MYSERVICE. If you want to have it started automatically, use systemctl --user enable MYSERVICE. Read more about it here: https://wiki.archlinux.org/index.php/Systemd/User

It works well for enabling the service and starting it, but upon stopping it enters a failed state. Starting again seems to work well (GUI is OK), but apparently I did something wrong and systemd doesn’t know exactly how to stop the service.

➜  ~  systemctl --user start syncthing 
➜  ~  systemctl --user status syncthing
syncthing.service - Syncthing service for 
   Loaded: loaded (/home/steko/.config/systemd/user/syncthing.service; enabled)
   Active: active (running) since ven 2014-10-17 17:36:41 CEST; 1s ago
 Main PID: 3289 (syncthing)
   CGroup: /user.slice/user-1000.slice/user@1000.service/syncthing.service
           └─3289 /home/steko/Scaricati/syncthing/syncthing

ott 17 17:36:41 ogma systemd[2003]: Starting Syncthing service for ...
ott 17 17:36:41 ogma systemd[2003]: Started Syncthing service for .
➜  ~  systemctl --user is-enabled syncthing
enabled
➜  ~  systemctl --user stop syncthing
➜  ~  systemctl --user status syncthing
syncthing.service - Syncthing service for 
   Loaded: loaded (/home/steko/.config/systemd/user/syncthing.service; enabled)
   Active: failed (Result: exit-code) since ven 2014-10-17 17:38:14 CEST; 2s ago
  Process: 3289 ExecStart=/home/steko/Scaricati/syncthing/syncthing (code=exited, status=2)
 Main PID: 3289 (code=exited, status=2)

ott 17 17:36:41 ogma systemd[2003]: Starting Syncthing service for ...
ott 17 17:36:41 ogma systemd[2003]: Started Syncthing service for .
ott 17 17:38:14 ogma systemd[2003]: Stopping Syncthing service for ...
ott 17 17:38:14 ogma systemd[2003]: syncthing.service: main process exited,...NT
ott 17 17:38:14 ogma systemd[2003]: Stopped Syncthing service for .
ott 17 17:38:14 ogma systemd[2003]: Unit syncthing.service entered failed state.

This means syncthing has stopped with exit code 2. I don’t know what happened, but it says here that there was a Misuse of shell builtins (according to Bash documentation). Maybe a permission problem?

Exit codes are a bit further up the file :wink:

Thanks, I should have searched for exit :smiley: