Mohamed Mansour's Personal Website
Articles
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!
