Articles

Navigation ( archives ›› 2008 ›› September ›› 13 ›› Steam linux server init script in chrooted environment )

Steam linux server init script in chrooted environment

Posted on September 13, 2008, 4:56 pm EST

I have a Linux TF2 Server and Linux CSS Server on Debian, and I wanted to properly make an init script to start/stop the server and must run under a given user other than root.

Thanks to the initial post by scriptfu @ srcds.com and the updated portion by Arujei.

Introduction

First of all, everyone knows it isn't great to run a server with root privileges. It is better to run it under a user which has no association to root. This tutorial will be based no Debian operating system. Could be applied to any os. In this setup we will make sure that any user belonging to "tf2server" group could actually run the server. While the server is running, it will run it as the user "tf2server". Again, any user belonging to that group could start and stop the server successfully. As well, we will be installing the tf2server under the "/usr/local/games/tf2/"

First of all, need to make sure you have "sudo" properly setup.

CODE:
$ aptitude install sudo

Lets create a user called "tf2server" (note this will create a group called tf2server as well!:

CODE:
$ adduser tf2server

First of all, make sure you have the tf2 server installed in some location, I choose this (apply proper permissions):

CODE:
$ mkdir /usr/local/games/tf2/
$ chown -R tf2server:tf2server /usr/local/games/tf2

Lets alter the sudoers file:

CODE:
$ visudo /etc/sudoers

With this line

CODE:
%tf2server ALL=(tf2server) NOPASSWD: /usr/local/games/tf2/

Save this script inside the "/usr/local/games/tf2/" as "server-launch"

CODE:
#! /bin/sh

# Server options
TITLE='Source Dedicated Server'           # Script initialization title
LONGNAME='Team Fortress 2'                # Full title of game type
NAME='tf2'                                # Server handle for the screen session
DAEMON='srcds_run'                        # The server daemon
UPDATER='/usr/local/games/tf2/'           # The Steam updater. I recommend keeping it one directory below orangebox for tf2 servers.
STEAM='/usr/local/games/tf2/orangebox'    # STEAM to Steam installation
USER='tf2server'                          # User that this will be running under. Currently not functional part of this script.

# Game options
CLIENT='Team Fortress 2 Development Server'  #Game Server name.
IP='127.0.0.1'                            # IP of the server
PORT='27015'                              # Port number to
MAP='ctf_2fort'                           # Initial map to start
GAME='tf'                                 # Game type (tf|cstrike|valve|hl2mp)
SIZE='32'                                 # Maximum number of players
HIGHPRIORITY=1                            # Set server renice to -20 will make server take priority over all other applications on server. 1 being on and 0 being off.

# Server options string
OPTS="-game $GAME +hostname \"$CLIENT\" +map $MAP +ip $IP -port $PORT \
    -autoupdate +maxplayers $SIZE -pidfile $STEAM/$GAME/$NAME.pid"

INTERFACE="/usr/bin/screen -A -m -d -S $NAME"

# Screen command
CURRENT_USER=$(/usr/bin/whoami)

if [ "$CURRENT_USER" != "$USER" ]; then
    echo "$TITLE cannot run on user ($CURRENT_USER)";
    exit
fi

service_start() {
    # Check if the pid files currently exist
    if [ -f $STEAM/$GAME/$NAME.pid ] || [ -f $STEAM/$GAME/$NAME-screen.pid ]; then
        # Pid files allready exist check if the process is still running.
        if [ "$(ps -p `cat $STEAM/$GAME/$NAME.pid` | wc -l)" -gt 1 ]; then
            # Process is still running.
            echo -e "Cannot start $TITLE.  Server is already running."
        #exit 1
        else
        # Process exited with out cleaning up pid files.
            if [ "$(ps -p `cat $STEAM/$GAME/$NAME.pid` | wc -l)" -gt 1 ]; then
            # Screen is still running.
            # Get the process ID from the pid file we created earlier
                for id in `cat $STEAM/$GAME/$NAME-screen.pid`
                do kill -9 $id
                echo "Killing process ID $id"
                echo "Removing $TITLE screen pid file"
                rm -rf $STEAM/$GAME/$NAME-screen.pid
                break
                done
            fi
        # Remove server pid file
        echo "Removing $TITLE pid file"
        rm -rf $STEAM/$GAME/$NAME.pid

        # Wipe all old screen sessions
        screen -wipe 1> /dev/null 2> /dev/null
        service_start
        fi
    else
    # Server is not running start the server.
        if [ -x $STEAM/$DAEMON ]; then
            echo "Starting $TITLE - $LONGNAME - $CLIENT"
            echo "Server IP: $IP"
            echo "Server port: $PORT"
            echo "Server size: $SIZE players"
            CD $STEAM
            $INTERFACE $STEAM/$DAEMON $OPTS
            # Prevent race condition on SMP kernels
             sleep 1
            # Find and write current process id of the screen process
            ps -ef | grep SCREEN | grep "$NAME" | grep -v grep | awk '{ print $2}' > $STEAM/$GAME/$NAME-screen.pid
            echo "$TITLE screen process ID written to $STEAM/$GAME/$NAME-screen.pid"
            echo "$TITLE server process ID written to $STEAM/$GAME/$NAME.pid"

            echo "$TITLE started."
            # Was having problems with directory permisions due to FTP access making these files unreadable by users other than owner.
            chmod 666 $STEAM/$GAME/*.pid 1> /dev/null 2> /dev/null
            # Make any pid files created by different users owned by the set user.
            chown $USER $STEAM/$GAME/*.pid 1> /dev/null 2> /dev/null
            sleep 2
            if [ $HIGHPRIORITY = 1 ]; then
                renice -20 `cat $STEAM/$GAME/$NAME.pid` >/dev/null 2>&1
            fi
        fi
    fi
}

service_stop() {
    if [ -f $STEAM/$GAME/$NAME.pid ] || [ -f $STEAM/$GAME/$NAME-screen.pid ]; then
        echo "Stopping $TITLE - $LONGNAME."
        # Get the process ID from the pid file we created earlier
        for id in `cat $STEAM/$GAME/$NAME-screen.pid`
            do kill -9 $id
            echo "Killing process ID $id"
            echo "Removing $TITLE screen pid file"
            rm -rf $STEAM/$GAME/$NAME-screen.pid
            break
        done
        # Remove server pid file
        echo "Removing $TITLE pid file"
        rm -rf $STEAM/$GAME/$NAME.pid
        # Wipe all old screen sessions
        screen -wipe 1> /dev/null 2> /dev/null
        echo "$TITLE stopped."
    else
        echo -e "Cannot stop $TITLE.  Server is not running."
        #exit 1
    fi
}

service_clear() {
    # Removing all pid files
    echo "Removing all Service pid files."
    rm -rf $STEAM/$GAME/*.pid 1> /dev/null 2> /dev/null
}

service_update() {
    echo "Stopping and Clearing all Service files."
    service_stop
    sleep 2
    service_clear
    sleep 2
    echo "Updating Steam Updater"
    cd $UPDATER
    ./steam 1> /dev/null 2> /dev/null
    echo "Updating Game Files"
    ./steam -command update -game $GAME -dir . 1> /dev/null 2> /dev/null
    sleep 2
    service_start
}

case "$1" in
    'start')
        service_start
        ;;
    'stop')
        service_stop
        ;;
    'restart')
        service_stop
        sleep 1
        service_start
        ;;
    'clear')
        service_clear
        ;;
    'update')
        service_update
        ;;
    *)
        echo "Usage $0 start|stop|restart|clear|update"
esac

Since that script should run under the user specified, "tf2server", you could do the following:

CODE:
$ sudo -u tf2server /usr/local/games/tf2/server-launch

Or you could create your own local script that will have that inside, an example could be like this, save as "launchServer":

CODE:
#! /bin/sh
sudo -u tf2server /usr/local/games/tf2/server-launch $@

Now you can do commands such as:

  • ./launchServer start
  • ./launchServer stop
  • ./launchServer restart
  • ./launchServer update

Hope that helps anyone!

About this Article:

Comments (6) - Add yours, or View the replies

Categoy (Software)

Views (13043)

Digg it: Digg this article