Running subsonic standalone as daemon automatically on Linux

Tutorials, tips and tricks.

Moderator: moderators

Running subsonic standalone as daemon automatically on Linux

Postby jigsaw » Sun Mar 08, 2009 3:39 pm

Hi all

I realized shortly after completing this that wintermute already posted a bash-script for starting subsonic. However personally I prefer to have all services running as dedicated users to prevent any security breaches and such on my server. No offense to wintermute :)

Here's at least how Subsonic is handled by my system, free for anybody to use :)

Subsonic is started automatically by init at boot time on runlevels 3-5 run as the user subsonic
This is done without modifying the original subsonic.sh at all to avoid having to do updates after upgrading Subsonic
PS: However some changes to subsonic.sh could improve the init-script somewhat

init-script put in /etc/init.d/subsonic
Code: Select all
#!/bin/sh
#
# chkconfig: 345 99 05
# /etc/init.d/subsonic
#
# Description: Linux startup-script for Subsonic standalone
#

[ ! -d /usr/bin ] && exit

# On RedHat AS 3 and above, use runuser rather than su
SU="su"
if [ -f "/etc/redhat-release" -a -x "/sbin/runuser" ]; then
    SU="runuser"
fi

if [ -f "/etc/redhat-release" ]; then
        LOCKFILE=/var/lock/subsys/subsonic
fi

PATH="$PATH:/bin:/usr/bin"
export PATH

SUBSONIC_USERNAME=subsonic
SERVICENAME="Subsonic Media Streamer"
SUBSONIC_HOME="/var/subsonic/"

# Source function library.
. /etc/rc.d/init.d/functions

# Functions for starting and stopping subsonic
start() {
        echo -n $"Starting $SERVICENAME: "
        # Start subsonic and pipe any output to syslog ( then there's no need to modify subsonic.sh at all )
        $SU - "$SUBSONIC_USERNAME" -s /bin/sh -c "$SUBSONIC_HOME/subsonic.sh" | logger -p daemon.info -t subsonic
        # Check if subsonic started since we are not getting RETVAL from subsonic.sh
        getpid
        if [ $PID ]; then
            success && RETVAL=0
        else
            failure && RETVAL=1
        fi
        echo
        [ $RETVAL = 0 ] && touch $LOCKFILE
        return $RETVAL
}
stop() {
        echo -n "Stopping $SERVICENAME: "
        kill $PID
        # Check if subsonic terminated since we are not getting RETVAL from kill ( killproc with pidfile would solve this )
        sleep 1
        getpid
        if [ $PID ]; then
            failure && RETVAL=1
        else
            success && RETVAL=0
        fi
        echo
        [ $RETVAL = 0 ] && rm -f $LOCKFILE
        return $RETVAL
}
status() {
        if [ $PID ]; then
             echo -n "$SERVICENAME is running.. Found PID $PID"
        else
             echo -n "$SERVICENAME is not running.."
        fi
        echo

}
getpid() {
      # Using a pidfile would be better, but would have to modify subsonic.sh to do that, so for now..
        PID=`ps -u $SUBSONIC_USERNAME -f | grep java | grep subsonic-booter-jar-with-dependencies.jar | awk '{print $2}' `
}

RETVAL=0
# See how we were called.
case "$1" in
  start)
   # Get the PID if Subsonic is running
   getpid
        if [ $PID ]; then
            status
        else
            start
        fi
        ;;
  stop)
   # Get the PID if Subsonic is running
   getpid
        if [ $PID ]; then
            stop
        else
            status
        fi
        ;;
  status)
   # Get the PID if Subsonic is running
   getpid
        status
        ;;
  restart)
        stop
        start
        ;;
  *)
        echo "Usage: subsonic {start|stop|status|restart}"
        exit 1
esac
exit $RETVAL



To setup the subsonic user and register the init-script
Code: Select all
sudo adduser subsonic -c "Subsonic Media Streamer" -d /var/subsonic -M -s /sbin/nologin
sudo chown -R subsonic.subsonic /var/subsonic
sudo chmod og+x /etc/init.d/subsonic
sudo chkconfig --add subsonic


Example of usage
Code: Select all
$ sudo service subsonic
Usage: subsonic {start|stop|status|restart}
$ sudo service subsonic status
Subsonic Media Streamer is not running..
$ sudo service subsonic start
Starting Subsonic Media Streamer:                          [  OK  ]
$ sudo service subsonic status
Subsonic Media Streamer is running.. Found PID 31136
$ sudo service subsonic stop
Stopping Subsonic Media Streamer:                          [  OK  ]
$ sudo service subsonic status
Subsonic Media Streamer is not running..
Currently without Subsonic due to hardware failure :(
User avatar
jigsaw
 
Posts: 242
Joined: Sat Oct 13, 2007 12:01 pm
Location: Stavanger, Norway

Postby sindre_mehus » Mon Mar 09, 2009 12:51 pm

Very nice, jigsaw, thank you!

Feel free to suggest modifications to subsonic.sh to make it easier to integrate with scripts like this.
User avatar
sindre_mehus
 
Posts: 1955
Joined: Tue Nov 29, 2005 6:19 pm
Location: Oslo, Norway

Postby jigsaw » Mon Mar 09, 2009 11:16 pm

sindre_mehus wrote:Feel free to suggest modifications to subsonic.sh to make it easier to integrate with scripts like this.

Well, certainly :)

By adding this code-block in the end of subsonic.sh the init-script could be simpler and more like the standards ( at least as far as I can tell from init scripts delivered along with apps like Apache, Tomcat etc )
Code: Select all
case $1 in
            --pidfile=?*)
                  PIDFILE=${1#--pidfile=}
                  ;;
esac

# Write pid to pidfile if it is defined, if PIDFILE is not defined, we ignore this part
if [ $! -a $PIDFILE ]; then
    echo $! > ${PIDFILE}
elif [ ! $! ]; then
    echo
    echo "Did not get PID from startup.. Check logs for error.."
    exit 1
fi



PS: I also removed the echo-lines from subsonic.sh, as the init-script provides sufficient feedback at startup and shutdown.

The init-script would then need to be like this
Code: Select all
#!/bin/sh
#
# chkconfig: 345 99 05
# /etc/init.d/subsonic
#
# Description: Linux startup-script for Subsonic standalone
#

[ ! -d /usr/bin ] && exit

# On RedHat AS 3 and above, use runuser rather than su
SU="su"
if [ -f "/etc/redhat-release" -a -x "/sbin/runuser" ]; then
    SU="runuser"
fi

if [ -f "/etc/redhat-release" ]; then
        LOCKFILE=/var/lock/subsys/subsonic
fi

PATH="$PATH:/bin:/usr/bin"
export PATH

USER=subsonic
SERVICENAME="Subsonic Media Streamer"
SUBSONIC_HOME="/var/subsonic/"
PIDFILE="$SUBSONIC_HOME/subsonic.pid"
PROG="$SUBSONIC_HOME/subsonic.sh"
OPTIONS="--pidfile=${PIDFILE}"

# Source function library.
. /etc/rc.d/init.d/functions

# Functions for starting and stopping subsonic
start() {
        echo -n "Starting $SERVICENAME: "
        # Start subsonic
        daemon --pidfile=$PIDFILE --user=$USER $PROG $OPTIONS
   RETVAL=$?
        echo
        [ $RETVAL = 0 ] && touch $LOCKFILE
        return $RETVAL
}
stop() {
        echo -n "Stopping $SERVICENAME: "
        killproc -p $PIDFILE
   RETVAL=$?
        echo
        [ $RETVAL = 0 ] && rm -f $LOCKFILE
        return $RETVAL
}
status() {
        if [ -s $PIDFILE ]; then
             echo -n "$SERVICENAME is running.."
        else
             echo -n "$SERVICENAME is not running.."
        fi
        echo

}

RETVAL=0
# See how we were called.
case "$1" in
  start)
        if [ -s $PIDFILE ]; then
            status
        else
            start
        fi
        ;;
  stop)
        if [ -s $PIDFILE ]; then
            stop
        else
            status
        fi
        ;;
  status)
        status
        ;;
  restart)
        stop
        start
        ;;
  *)
        echo "Usage: subsonic {start|stop|status|restart}"
        exit 1
esac
exit $RETVAL


The last thing I'm not too happy with is the fact that I had to create 5-6 variables in the init-script. This could seem a bit messy as some of the init-variables are in subsonic.sh and then some are in the init-script. I guess one option would be to have all the variables in the subsonic.properties file ( or maybe a subsonic.env file? ) Then both subsonic.sh and the init-script could source that file.
Currently without Subsonic due to hardware failure :(
User avatar
jigsaw
 
Posts: 242
Joined: Sat Oct 13, 2007 12:01 pm
Location: Stavanger, Norway

Postby Pathduck » Thu Mar 19, 2009 2:16 pm

This is great, good job - maybe Sindre can include this in the standard Subsonic once its "perfected" - I have a couple of issues with it though :D

- You seem to assume Redhat, but this wont work on Ubuntu for instance:
LOCKFILE=/var/lock/subsys/subsonic.
Better to have the user set the full path to dir himself, or:
LOCKFILE=$SUBSONIC_HOME/subsonic.lck

This part didnt seem to work:
success && RETVAL=0
It just output something like "106: success: not found"
I changed it to just return the value so you can check on that.

Also:
echo -n $"Starting $SERVICENAME: "
This just puts out: "$Starting Subsonic..." with the "$".
Should the $ be there at all before the string?

This is in bash on ubuntu 8.10. I have a little experience with such scripts but I might have misunderstood something?
Pathduck
 
Posts: 27
Joined: Wed Mar 18, 2009 10:14 pm

Postby jigsaw » Thu Mar 19, 2009 10:44 pm

Pathduck wrote:This is great, good job - maybe Sindre can include this in the standard Subsonic once its "perfected"

Thank you :)

Pathduck wrote:- You seem to assume Redhat, but this wont work on Ubuntu for instance:
LOCKFILE=/var/lock/subsys/subsonic.
Better to have the user set the full path to dir himself, or:
LOCKFILE=$SUBSONIC_HOME/subsonic.lck

You are quite correct, I am assuming Redhat, which may be too specific. However using SUBSONIC_HOME defies the purpose, on Redhat at least.
You could read about it here

A short excerpt of why:
This method of shutting down is ordered such that processes are killed as gracefully as possible. During a shutdown, the script /etc/rc.d/init.d/killall checks the /var/lock/subsys/ directory to see if any subsystems are still locked. If a service's subsystem is locked after all other services have been stopped (i.e. step 1 above has completed), the killall script uses the subsystem filename to call service <initscript> stop. This attempts to stop the service gracefully before handing off to steps 2 through 4, which forcefully terminate the process itself.

Pathduck wrote:This part didnt seem to work:
success && RETVAL=0
It just output something like "106: success: not found"
I changed it to just return the value so you can check on that.

Also:
echo -n $"Starting $SERVICENAME: "
This just puts out: "$Starting Subsonic..." with the "$".
Should the $ be there at all before the string?

This is in bash on ubuntu 8.10. I have a little experience with such scripts but I might have misunderstood something?

I think the main issue is that you are comparing Ubuntu, which is based on Debian, with Redhat. There are some subtle differences ( and probably quite a few huge ones :P )
Maybe you could use my first version and ubuntify it?

If you'd check out this link you could create a debian version which also could be included in the package? The link is for another application, but I think it shows quite nicely the differences between the two version.
I'd be happy to do it myself, but seeing as I do not have a Ubuntu system at my immediate disposal it would probably be far quicker for you to do it?
Currently without Subsonic due to hardware failure :(
User avatar
jigsaw
 
Posts: 242
Joined: Sat Oct 13, 2007 12:01 pm
Location: Stavanger, Norway

Postby Pathduck » Wed Mar 25, 2009 4:56 pm

Well, I dont really know how important the lockfile is, won't the OS do the stop() routine when shutting down? At least it does on RHEL5 (at work)...

Anyway, here's the script I'm using now, it works well on Ubuntu, only minor adjustments to the original:

Code: Select all
#!/bin/sh
#
# chkconfig: 345 99 05
# /etc/init.d/subsonic
#
# Description: Linux startup-script for Subsonic standalone
#

[ ! -d /usr/bin ] && exit

# On RedHat AS 3 and above, use runuser rather than su
SU="su"
if [ -f "/etc/redhat-release" -a -x "/sbin/runuser" ]; then
    SU="runuser"
fi

export PATH="$PATH:/bin:/usr/bin"

SUBSONIC_USERNAME=root
SERVICENAME="Subsonic Media Streamer"
SUBSONIC_HOME="/var/subsonic/"
LOCKFILE=/var/subsonic/subsonic.lock

# Source function library.
#. /etc/rc.d/init.d/functions

# Functions for starting and stopping subsonic
start() {
        echo -n "Starting $SERVICENAME: "
        # Start subsonic and pipe any output to syslog ( then there's no need to modify subsonic.sh at all )
        $SU - "$SUBSONIC_USERNAME" -s /bin/sh -c "$SUBSONIC_HOME/subsonic.sh" | logger -p daemon.info -t subsonic
        # Check if subsonic started since we are not getting RETVAL from subsonic.sh
        getpid
        if [ $PID ]; then
            RETVAL=0
        else
            RETVAL=1
        fi
        echo
        [ $RETVAL = 0 ] && touch $LOCKFILE
        return $RETVAL
}
stop() {
        echo -n "Stopping $SERVICENAME: "
        kill $PID
        # Check if subsonic terminated since we are not getting RETVAL from kill ( killproc with pidfile would solve this )
        sleep 1
        getpid
        if [ $PID ]; then
            RETVAL=1
        else
            RETVAL=0
        fi
        echo
        [ $RETVAL = 0 ] && rm -f $LOCKFILE
        return $RETVAL
}
status() {
        if [ $PID ]; then
             echo -n "$SERVICENAME is running.. Found PID $PID"
        else
             echo -n "$SERVICENAME is not running.."
        fi
        echo

}
getpid() {
      # Using a pidfile would be better, but would have to modify subsonic.sh to do that, so for now..
        PID=`ps -u $SUBSONIC_USERNAME -f | grep java | grep subsonic-booter-jar-with-dependencies.jar | awk '{print $2}' `
}

RETVAL=0
# See how we were called.
case "$1" in
  start)
   # Get the PID if Subsonic is running
   getpid
        if [ $PID ]; then
            status
        else
            start
        fi
        ;;
  stop)
   # Get the PID if Subsonic is running
   getpid
        if [ $PID ]; then
            stop
        else
            status
        fi
        ;;
  status)
   # Get the PID if Subsonic is running
   getpid
        status
        ;;
  restart)
        stop
        start
        ;;
  *)
        echo "Usage: subsonic {start|stop|status|restart}"
        exit 1
esac
exit $RETVAL

Pathduck
 
Posts: 27
Joined: Wed Mar 18, 2009 10:14 pm

Postby wintermute » Thu Apr 02, 2009 8:18 pm

No offense to wintermute Smile

None taken :)

Your script is nice. I appreciate if it (or a variant of it) will ship with Subsonic :)
wintermute
 
Posts: 14
Joined: Tue Jan 27, 2009 5:10 am

Postby sindre_mehus » Fri Apr 03, 2009 6:12 am

Thanks for you effort!
I'll definitely try to incorporate it in Subsonic once I get around to it.
User avatar
sindre_mehus
 
Posts: 1955
Joined: Tue Nov 29, 2005 6:19 pm
Location: Oslo, Norway

Postby jigsaw » Fri Apr 10, 2009 1:15 pm

One more change to the subsonic.sh
Change the ">" to a ">>" so that the subsonic.log doesn't get overwritten with every restart of the service.
I just had a thumbnail issue which I was investigating and in an effort to solve it I restarted the service, resulting in loosing the entire log..

From:
Code: Select all
${JAVA} -Xmx${MAX_MEMORY}m  -Dsubsonic.home=${SUBSONIC_HOME} -Dsubsonic.port=${SUBSONIC_PORT} \
-Dsubsonic.contextPath=${SUBSONIC_CONTEXT_PATH} -jar subsonic-booter-jar-with-dependencies.jar > ${LOG} 2>&1 &

To:
Code: Select all
${JAVA} -Xmx${MAX_MEMORY}m  -Dsubsonic.home=${SUBSONIC_HOME} -Dsubsonic.port=${SUBSONIC_PORT} \
-Dsubsonic.contextPath=${SUBSONIC_CONTEXT_PATH} -jar subsonic-booter-jar-with-dependencies.jar >> ${LOG} 2>&1 &
Currently without Subsonic due to hardware failure :(
User avatar
jigsaw
 
Posts: 242
Joined: Sat Oct 13, 2007 12:01 pm
Location: Stavanger, Norway

Postby sindre_mehus » Mon Apr 13, 2009 11:54 am

Hi,

I've updated subsonic.sh so that it takes the following command line arguments:

Code: Select all
Usage: subsonic.sh [options]
  --help               This small usage guide.
  --home=DIR           The directory where Subsonic will create files.
                       Make sure it is writable. Default: /var/subsonic
  --port=PORT          The port on which Subsonic will listen for
                       incoming HTTP traffic. Default: 8080
  --context-path=PATH  The context path, i.e., the last part of the Subsonic
                       URL. Typically '/' or '/subsonic'. Default '/'
  --max-memory=MB      The memory limit (max Java heap size) in megabytes.
                       Default: 64
  --pidfile=PIDFILE    Write PID to this file. Default not created.


Please find it here: http://subsonic.svn.sourceforge.net/vie ... xt%2Fplain

Comments are welcome.[/code]
User avatar
sindre_mehus
 
Posts: 1955
Joined: Tue Nov 29, 2005 6:19 pm
Location: Oslo, Norway

Postby jigsaw » Wed Apr 15, 2009 10:30 pm

That works nicely :)
Except that I still add the extra '>' to the startup-line to avoid having the log overwritten every time.

I've modified my init-script to be compatible with the new subsonic.sh
Feel free to use it.
PS: I fixed it up a bit after I realized two bugs in the script following a power outage on my server.

The chkconfig now starts subsonic before Apache and stops it after Apache, this allows any proxy set up in Apache to work on boot.
I removed the lockfile-things as it cluttered it up and didn't provide anything for Subsonic after all.

It's still Red Hat / Fedora specific as it uses init-functions

Code: Select all
#!/bin/sh
#
# chkconfig: 345 80 10
# /etc/init.d/subsonic
#
# Description: Linux startup-script for Subsonic standalone
#

[ ! -d /usr/bin ] && exit

PATH="$PATH:/bin:/usr/bin"
export PATH

USER=subsonic
SERVICENAME="Subsonic Media Streamer"
SUBSONIC_HOME="/var/subsonic/"
PIDFILE="$SUBSONIC_HOME/subsonic.pid"
PROG="$SUBSONIC_HOME/subsonic.sh"

# Source function library.
. /etc/rc.d/init.d/functions

# Functions for starting and stopping subsonic
start() {
        if [ $RETVAL = 1 ]; then
            echo "Will cleanup and try to start.."
            rm -f $PIDFILE
        fi

        echo -n "Starting $SERVICENAME "
        # Start subsonic
        daemon --pidfile=$PIDFILE --user=$USER $PROG "--pidfile=$PIDFILE --home=$SUBSONIC_HOME"
   RETVAL=$?
        echo
        return $RETVAL
}
stop() {
        echo -n "Stopping $SERVICENAME "
        killproc -p $PIDFILE
   RETVAL=$?
        echo
        return $RETVAL
}
status() {
        if [ -r $PIDFILE ]; then
            check_pid
            if [ $RETVAL = 0 ]; then
                echo -n "$SERVICENAME is running"
            else
                echo -n "Pidfile found, but subsys is dead"
            fi
        else
            echo -n "$SERVICENAME is not running"
        fi
        echo
        return $RETVAL
}

check_pid() {
        RETVAL=0
        if [ -r $PIDFILE ]; then
            PID=`cat $PIDFILE`
            PS_PID=`ps -u $USER -f | grep $PID | grep subsonic-booter-jar-with-dependencies.jar | awk '{print $2 }'`
            [ ! $PS_PID ] && RETVAL=1
        fi
        return $RETVAL
}

RETVAL=0
# See how we were called.
case "$1" in
  start)
        if [ -r $PIDFILE ]; then
            status
            [ $RETVAL = 1 ] && start
        else
            start
        fi
        ;;
  stop)
        if [ -r $PIDFILE ]; then
            stop
        else
            status
        fi
        ;;
  status)
        status
        ;;
  restart)
        stop
        start
        ;;
  *)
        echo "Usage: subsonic {start|stop|status|restart}"
        exit 1
esac
exit $RETVAL
Currently without Subsonic due to hardware failure :(
User avatar
jigsaw
 
Posts: 242
Joined: Sat Oct 13, 2007 12:01 pm
Location: Stavanger, Norway

Running subsonic standalone as daemon automatically on Linux

Postby tgeorge73 » Wed Jul 01, 2009 2:54 pm

Thanks for all the great information... However I ran into one snag that I thought I'd share in case others get it too... Prior to finding this I had run subsonic by manually executing the shell script whenever I rebooted my machine... Then, after applying the above changes to make it work as a service, whenever I started the service and tried to access the site I got an HTTP 503 error... (stopping the service and starting subsonic manually via the shell script worked fine). I eventually tracked it down to permissions. In addition to changing the owner of the /var/subsonic folder structure, I also had to change the owner of the /tmp/subsonic folder from my user account to the subsonic account since it already had been created by earlier manual startups before finding this thread. When reviewing the subsonic log files I saw the java exceptions about access denied to the musicFolderCache files...
tgeorge73
 
Posts: 1
Joined: Wed Jul 01, 2009 1:14 pm

Postby twent4 » Sat Jul 25, 2009 3:47 am

hey guys, pardon the newbie talk, but did anyone figure out a way to modify this to work with deb/ubuntu? thanks.
twent4
 
Posts: 17
Joined: Tue Jul 07, 2009 1:06 am

Postby binoculars » Sat Aug 01, 2009 12:44 pm

Hello, I found this nice wiki:
http://oaktechnologies.net/jamwiki/en/Subsonic
Thought that main.jsp part could be handy for someone else... Enjoy :D
binoculars
 
Posts: 1
Joined: Sat Aug 01, 2009 12:40 pm

Postby Pathduck » Fri Sep 04, 2009 7:23 pm

binoculars wrote:Hello, I found this nice wiki:
http://oaktechnologies.net/jamwiki/en/Subsonic
Thought that main.jsp part could be handy for someone else... Enjoy :D


OR you could pay some money (choose what you want!) to support a great product and get rid of the ads that way!

... :roll:
Pathduck
 
Posts: 27
Joined: Wed Mar 18, 2009 10:14 pm

Next

Return to Tutorials

Who is online

Users browsing this forum: No registered users and 1 guest