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

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:

When STNORESTART=yes is set, Syncthing/Pulse returns 3 as an exit code and Systemd will not restart it unless you add SuccessExitStatus=3 to the service file. A restart from the web gui would not work otherwise.

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

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

[Install]
WantedBy=multi-user.target

I am running OpenSuse 13.1 and I have no experience in systemd services and would like to explain the problems I had when I tried this guide.

Tried multiple different options including copying syncthing.service to systemd/user folder and so on.

$systemctl start syncthing Failed to issue method call

$systemctl --user start syncthing Failed to get D-Bus connection: Did not receive a reply

The solutions to my problem was provided here in proper order:

  1. Copy the systemd service from first post and save as syncthing@.service in folder: /etc/systemd/system/multi-user.target.wants/
  2. $systemctl enable syncthing@$USER.service
  3. $systemctl start syncthing@$USER.service

Now everything seems to be working fine.

Stopping/restarting would be a PITA. Especially the latter.

You’re supposed to run it as sudo systemctl start syncthing@USERNAME, not systemctl --user.

What I just said above applies. Also, the ArchLinux package actually displays a message post-installation telling you exactly this.

I did not miss the install message. Do you know why this is? I would like it better, when this service is controlled by the user itself, that is why I tried to get it working with systemctl --user.

Is there any reason why you can’t just sudo systemctl? The service runs as the user anyway. And it can restart itself once it’s started. (or you can kill it and have systemd restart it for you).

Like I said, as a user space process it should be controlled by the user. The user can not stop or start any services of this type, because the service was set by the super user. Correct if I am wrong but I think that the service is started at system start and therefore can affect the overall performance depending on the number of users using syncthing, repositories and so on. The user service manager (systemctl --user) is started on the first log in of the according user and its logs can only be viewed by the according user (privacy). I know for a single user system there is no difference but for multi user systems it makes sense to use the user service manager and I am always glad to keep my activities in user space :slight_smile: