Свой сервер

Linux-сервер Killing Floor: скрипт запуска через screen, автоперезапуск, обновление по cron и раздача карт через nginx

Эта статья продолжает гайд по установке сервера KF1 на Linux: здесь собраны скрипты, которые выкладывали REGETT и Oyashiro на форуме killingfloor.ru в 2012 году. Пути в примерах: сервер в /opt/KFDS, SteamCMD в /opt/SteamCMD. Подставьте свои.

server.sh: запуск, остановка и автоперезапуск

Один файл, из зависимостей только screen (sudo apt-get install screen). Сервер работает в отдельном screen-сеансе, а «контроллер» через watch каждые 30 секунд вызывает server.sh check и поднимает сервер, если сеанса нет. Падения можно писать в лог.

#! /bin/sh
## v0.0.2
PATH=/usr/bin:/usr/sbin:/bin:/sbin
# Имя screen-сеанса сервера
SERVER_NAME="MyServer"
# Папка System сервера
GAME_PATH="/opt/KFDS/System"
# Имя контроллера
CONTROLLER="MyController"
# Папка, где лежит этот скрипт
PWD_PATH=$(dirname `readlink -f $0`)
# Лог падений: false или путь, например /var/log/kf-crashes.txt
CRASH_LOG="false"

check(){
PID=`ps fax | grep $SERVER_NAME | grep SCREEN | awk '{print $1}'`
if [ -z "$PID" ]
then
 if [ "$CRASH_LOG" != "false" ]
 then
  echo $(date +%d.%m.%Y%t%H:%M:%S%t)"- Game server is crashed!" >>$CRASH_LOG
 fi
 echo "Game server is not running!"
 start
else
 echo "Game server is running..."
fi
}
start(){
cd $GAME_PATH && screen -AmdS $SERVER_NAME ./ucc-bin server KF-BioticsLab.rom?game=KFmod.KFGameType?VACSecured=true?MaxPlayers=6?ini=KillingFloor.ini -nohomedir
echo "Starting Game server...!"
}
controller(){
if test -r "${PWD_PATH}/PPID"
then
 echo "$CONTROLLER is running..."
else
 watch -n 30 "$PWD_PATH/server.sh check" >>/dev/null &
 echo $!>${PWD_PATH}/PPID
 echo "Starting Game server and AutoRestart..."
fi
}
stop(){
if [ "$1" = "controller" ]
then
 if test -r "${PWD_PATH}/PPID"
 then
  PID=`cat ${PWD_PATH}/PPID`
  kill $PID
  rm -rf ${PWD_PATH}/PPID
 else
  echo "Controller not running!"
 fi
else
 PID=`ps fax | grep $1 | grep SCREEN | awk '{ print $1 }'`
 if [ -z "$PID" ]
 then
  echo "$1 not running!"
 else
  kill $PID
 fi
fi
}
case "$1" in
start) controller ;;
stop) echo "Stopping Game server and AutoRestart..."; stop controller; stop ${SERVER_NAME} ;;
restart) stop ${SERVER_NAME}; start ;;
check) check ;;
*) echo "Usage: $0 {start|stop|restart|check}"; exit 1
esac
exit 0

Использование: ./server.sh start, ./server.sh stop, ./server.sh restart. Файл PPID рядом со скриптом хранит PID контроллера, не удаляйте его вручную. Сегодня ту же задачу проще решить юнитом systemd с Restart=always, но скрипт удобен, если systemd под рукой нет.

Шпаргалка по screen

КомандаЧто делает
screen -dmS MyServer командаЗапустить команду в новом сеансе в фоне
screen -lsСписок всех сеансов
screen -r MyServerПодключиться к сеансу (консоль сервера)
Ctrl+A, затем DОтключиться, оставив сервер работать
screen -wipeУбрать «мёртвые» сеансы

Закрывать окно консоли сервера через exit или Ctrl+C нельзя — это остановит сервер.

Ежедневное обновление через SteamCMD и cron

Сервер нужно остановить перед обновлением и запустить после. Сценарий для SteamCMD, /opt/KFDS/update.txt:

login USERNAME PASSWORD
force_install_dir /opt/KFDS/
app_update 215360 validate
exit

215360 — app ID сервера KF1 для Linux (для Windows — 215350). Серверу KF1 нужен вход в SteamCMD обычным аккаунтом Steam, покупать игру на нём не обязательно. Заведите для сервера отдельный аккаунт без Steam Guard: пароль хранится в файле открытым текстом, поэтому дайте ему права только для пользователя сервера (chmod 600 update.txt). Обёртка /opt/KFDS/updater.sh (не забудьте chmod +x):

#!/bin/sh
/opt/KFDS/server.sh stop
/opt/SteamCMD/steamcmd.sh +runscript /opt/KFDS/update.txt
/opt/KFDS/server.sh start

В /etc/crontab добавьте строку, например ежедневно в 6:00:

00 6 * * * user /opt/KFDS/updater.sh

Перечитать конфигурацию cron можно без перезапуска службы: killall -HUP cron. Вместо правки /etc/crontab задание можно положить отдельным файлом в /etc/cron.d/.

Раздача сжатых карт через nginx

Для быстрой загрузки карт клиентами (редирект) Apache избыточен, хватит лёгкого nginx:

sudo apt-get install nginx
sudo mkdir /opt/files

Пример /etc/nginx/conf.d/default.conf: первый блок отбрасывает запросы к посторонним именам, второй раздаёт файлы по IP сервера.

server {
    listen 80;
    server_name _;
    return 444;
}
server {
    listen 80;
    server_name 111.222.333.444;
    access_log off;
    location ~* \.(uz2|7z|zip|rar)$ {
        root /opt/files/;
        expires 30d;
    }
    location ~ /\.ht { deny all; }
}

Проверка и перезапуск: sudo nginx -t, затем sudo systemctl restart nginx. Положите .uz2 в /opt/files/ и пропишите адрес в RedirectToURL секции [IpDrv.HTTPDownload] в KillingFloor.ini.

Чтобы файлы забирала только игра, а не любой браузер, можно пускать к .uz2 лишь клиентов с user-agent Unreal:

location ~* \.uz2$ {
    if ( $http_user_agent !~ Unreal ) { return 444; }
    root /opt/files/;
    expires 30d;
}

Держите сжатые файлы вне общедоступного корня сайта: тогда скачать их можно будет только по прямой ссылке http://адрес/имя.uz2 и только из игры.

Вариант попроще: init.d и проверка через cron

Так делали в 2011 году в теме «Создание сервера на Linux» (mangust, Ren, форум killingfloor.ru) на Debian. Сервер тогда ставили через уже устаревший HLDSUpdateTool, но сама схема автозапуска годится и сейчас, если systemd нет.

Автозапуск при загрузке. Скрипт в /etc/init.d/ (например, KFautostart), значения в кавычках замените своими:

#! /bin/sh
PATH=/usr/bin:/usr/sbin:/bin:/sbin
SCREEN_NAME="kfserver"
GAME_PATH="/home/KF1/system"
start()
{
cd $GAME_PATH && screen -AmdS $SCREEN_NAME ./ucc-bin server [параметры запуска сервера]
}
stop()
{
PID=`ps fax | grep $SCREEN_NAME | grep SCREEN | awk '{ print $1 }'`
kill $PID
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart}"
exit 1
esac
exit 0

Сделайте файл исполняемым и зарегистрируйте его командой update-rc.d KFautostart defaults.

Подъём после падения. Задание cron раз в минуту проверяет, есть ли screen-сеанс сервера, и запускает его, если нет (вариант Ren):

#!/bin/sh
if [[ `screen -ls |grep имя_screen` ]]
then
echo
else
команда запуска или скрипт
fi

Строка для crontab: * * * * * /путь/к/скрипту. Скрипт server.sh выше делает то же самое без cron, через watch.

Цикл перезапуска с сохранением логов и rc.local. Вариант baikal_87 из темы «не стартует скрипт из rc.local» (форум killingfloor.ru). Скрипт kf1.sh запускает в screen второй скрипт:

#! /bin/bash
screen -A -m -d -S skf ./kf2.sh

kf2.sh в бесконечном цикле копирует прошлый ucc.log с датой в имени, запускает сервер на первом ядре (taskset -c 0), после выхода добивает процесс, дописывает время падения в kf_crash_times.log и через 3 секунды запускает сервер снова:

#! /bin/bash
while true
do
cd /home/game/KILLINGFLOOR/System/; cp ucc.log /home/game/KILLINGFLOOR/ucc.log; cd /home/game/KILLINGFLOOR/; mv ucc.log ucc-$(date +%d%m%y%H%M).log
cd /home/game/KILLINGFLOOR/System/; taskset -c 0 ./ucc-bin server KF-westlondon.rom?game=KFMod.KFGameType?VACSecured=True?MaxPlayers=20?ini=KillingFLoor.ini +net_public_adr x.xxx.xx.xx -nohomedir
kill -9 $(ps ax | grep KF-westlondon | grep -v grep | awk '{print $1}')
date >> /home/game/KILLINGFLOOR/kf_crash_times.log
echo !!! Waiting 3 seconds to restart...
sleep 3
done

Из терминала это работало, а из rc.local при загрузке нет. siriushard советовал прописать путь к скрипту в rc.local отдельной строкой, без приписок вроде taskset, перед exit 0:

/home/game/KILLINGFLOOR/System/kf1.sh
exit 0

Он же советовал не использовать заглавные буквы в путях. Автор темы о результате не написал.

Готовое решение: LinuxGSM

Всё перечисленное (установка через SteamCMD, запуск и остановка, обновления, мониторинг с уведомлениями, бэкапы, консоль, сжатие карт) умеет скрипт kfserver Дэниела Гиббса, который вырос в проект LinuxGSM. На форуме в 2014 году выкладывали перевод его документации. Если не хочется поддерживать свои скрипты, начните с него. Сравнение вариантов — в статье Варианты сервера, если SteamCMD не работает.