Gaming

Subsections of Gaming

Auto Update Steamcmd Servers

Idee

Mit Steamcmd können verschiedene Spieleserver heruntergeladen werden.
Die lokal installierte Version hat eine buildid, die mit der öffentlich verfügbaren Version verglichen wird.
Unterscheiden sich die beiden IDs, werden die Dateien mittels Docker und des Steamcmd Images aktualisiert.
Läuft der Container des Servers noch, wird dieser gestoppt und im anschluss neugestartet.

Genauere Infos zum Verhalten wird noch weiter unten beleuchtet.

Skript

Grundsätzlich ist dieses Skript für Docker basierte Server gedacht. Es kann auch andere Systeme updaten, allerdings sind Prüfungen und Funktionen für Docker eingebaut. Einfach unter /usr/local/sbin/update_steam_game.sh ablegen.

#!/bin/bash

set -e

: "${APP_ID:=}"
: "${APP_DIR:=}"
: "${APP_UID:=1000}"
: "${APP_GID:=1000}"
: "${APP_DIR_INIT:=0}"
: "${CONTAINER_NAME:=}"
: "${UPDATE_SCRIPT:=}"


[[ ! -d "${APP_DIR}" && "${APP_DIR_INIT}" != "1" ]] && echo "APP_DIR [${APP_DIR}] does not exist" && exit 1

# get state of game
TEMP_FILE=$(mktemp)
URL="https://api.steamcmd.net/v1/info/${APP_ID}"
curl -X GET "${URL}" -o ${TEMP_FILE} > /dev/null 2>&1


local_buildid=$(grep -oP 'buildid.+"\K[0-9]+' ${APP_DIR}/appmanifest_${APP_ID}.acf 2>/dev/null|| echo 0)
remote_buildid=$(jq -r  '.data.[].depots.branches.public.buildid' "${TEMP_FILE}")
rm "${TEMP_FILE}"

if [[ "${local_buildid}" == "${remote_buildid}" ]]; then
    echo "no update needed - buildid local[${local_buildid}] remote[${remote_buildid}]"
    exit 0
fi

# stop container if existing and not stopped
state=$(docker ps -a -f name="^${CONTAINER_NAME}$" --format json | jq -r '.State')

if [[ ${state} == "" ]];then
    echo "Container [${CONTAINER_NAME}] does not exist (check ENV CONTAINER_NAME variable)"
elif [[ ! ${state} =~ exited ]];then
    echo "stopping container [${CONTAINER_NAME}]"
    docker stop "${CONTAINER_NAME}"
    stopped=1
fi

# update by script / default cmd
if [[ -x "${UPDATE_SCRIPT}" ]];then
    echo "UPDATE BY SCRIPT [${UPDATE_SCRIPT}]"
    ${UPDATE_SCRIPT}
else
    # create directory and fix permissions
    if [[ ! -d "${APP_DIR}" ]];then
        mkdir -p "${APP_DIR}"
    fi
    ts=$(date +'%s')

    chown -R 1000:1000 "${APP_DIR}"
    cmd="docker run --network host --rm -it --name=${CONTAINER_NAME:-steam_$ts}_updater -v ${APP_DIR}:/home/steam/Steam/steamapps:rw cm2network/steamcmd /home/steam/steamcmd/steamcmd.sh +login anonymous +app_update ${APP_ID} validate +quit"
    echo "UPDATE BY COMMAND [${cmd}]"
    $cmd
    chown -R ${APP_UID}:${APP_GID} "${APP_DIR}"
fi

[[ ${stopped} -eq 1 ]] && echo "starting docker container [${CONTAINER_NAME}]" && docker start "${CONTAINER_NAME}"

Berechtigung fixen:

chmod 700 /usr/local/sbin/update_steam_game.sh

Benutzung

Zu Beginn des Skripts werden folgende Variablen gesetzt:

Variable Verwendung
APP_ID ID des Spiels, Palworld z.B. hat die ID 2394010
APP_DIR Pfad zu steamapps (Installation), im Dockercontainer wäre dies der Pfad zu /home/steam/Steam/steamapps
APP_DIR_INIT Existiert der Ordner noch nicht, wird dieser angelegt und das Spiel erstmalig heruntergeladen
CONTAINER_NAME Name des Server-Containers der geprüft und ggf. neugestartet werden soll
UPDATE_SCRIPT Pfad zu einem eigenen Update Skript, welches Anstelle des docker run Befehls mit Standard Steamcmd Parametern ausgeführt wird (z.B. wenn Login nötig ist, oder anderer Branch)
OPTIONALE VARIABLEN
APP_UID Nach dem Update wird der Owner von APP_DIR auf diese ID gesetzt
APP_GID Nach dem Update wird die Owner Group von APP_DIR auf diese GID gesetzt

Beispiel:

Auto Update für Palworld, kann so auch als Cronjob / Systemd Timer laufen…

APP_ID="2394010" APP_DIR_INIT="1" APP_DIR="/srv/docker/containers/steam/palworld.testing2/" CONTAINER_NAME="steam_palworld_test" /usr/local/sbin/update_steam_game.sh

CSGO Training Server mit Docker und Auto-Update

Vorwort

Das Spiel ist Programm, viele spielten es schon mit 1.6, oder gar früheren Versionen.
Hier kurz und bündig die Installation eines Training-Servers basierend auf Docker.

Installation

Hinweis

Es können beliebig viele CSGO-Server gestartet werden, einfach einen weiteren Service in der docker-compose.yml und weitere env-Datei hinzufügen! Der Auto-Updater erkennt selbständig weitere Instanzen.

# File: docker-compose.yml

version: "3"
services:
  # Dokumentation: https://github.com/timche/docker-csgo-updater
  csgo_updater:
    container_name: "csgo_updater"
    # timches Updater Image
    image: "timche/csgo-updater"
    restart: "unless-stopped"
    # kann auch isoliert laufen, network_mode ist aber einfacher
    network_mode: "host"
    volumes:
    # notwendig um via Socket Docker Befehle (wie einen Neustart) zu senden
    - "/var/run/docker.sock:/var/run/docker.sock"
    environment:
      # Container mit dem folgenden Image werden berücksichtigt
      UPDATER_CONTAINER_IMAGE: "timche/csgo"
      # Interval (Sekunden) in denen Container gescannt werden
      UPDATER_POLL_INTERVAL: 60

  csgo_practice:
    container_name: "csgo_practice"
    # fertiges Image mit Training-Plugin
    image: "timche/csgo:pug-practice"
    restart: "unless-stopped"
    network_mode: "host"
    volumes:
    - "/srv/docker/containers/csgo_practice/:/home/csgo/server:rw"
    env_file:
    - practice.env

In der practive.env kommen alle Umgebungsvariablen hinein, die der Container berüsichtigt.
Weitere Informationen und Anleitungen für die REPLACE_-Keys findet man im Projekt https://github.com/timche/docker-csgo/blob/main/README.md

# File: practice.env

CSGO_GSLT=REPLACE_SPIELSERVER_ACCOUNT_KEY
CSGO_WS_API_KEY=REPLACE_MEIN_WEB_API_KEY
CSGO_MAP=de_mirage
CSGO_MAX_PLAYERS=16
CSGO_HOSTNAME=My Train server
CSGO_RCON_PW=mein_rcon_pw
CSGO_PW=mein_server_password
CSGO_TICKRATE=64
CSGO_GAME_TYPE=0
CSGO_TV_ENABLE=true
CSGO_TV_NAME=My Train TV
CSGO_TV_DELAY=45
CSGO_TV_PORT=27020
CSGO_DISABLE_BOTS=true

Auto-Update

Der CSGO-Updater Container prüft im Stdout-Log des Spieleservers, ob diese vom Steam-Server zu einem restart gebeten werden (MasterRequestRestart).
Wird die Zeile erkannt, löst der Updater einen Restart aus (sofern der Server leer ist) und die CSGO-Server-Container laden die aktuelle Spieleversion herunter.


Palworld Server mit Docker

Diese Anleitung beschreibt die Erstellung eines Palworld Servers mit Einstellungen und Backup in einem isolierten Docker-Container.

Vorbereitung

Es wird Docker und rsync benötigt.

pacman -Syu docker rsync
apt update
apt install docker.io rsync

Server downloaden

Hinweis

Die Installation des Servers findet im Ordner /srv/docker/containers/steam/palworld/ statt, dieser muss an mehreren Stellen angepasst werden, falls ein anderer Ort gewünscht ist!

mkdir -p /srv/docker/containers/steam/palworld/
chown 1000:1000 /srv/docker/containers/steam/palworld/
docker run --network host --rm -it --name=steamcmd -v /srv/docker/containers/steam/palworld/:/home/steam/Steam/steamapps:rw cm2network/steamcmd /home/steam/steamcmd/steamcmd.sh +login anonymous +app_update 2394010 validate +quit

Server vorbereiten

Einfach eine docker-compose.yml anlegen

Hinweis

Die IP-Adresse (1.2.3.4) durch die öffentliche IP ersetzen und ggf. Port, falls ein anderer gewünscht ist.

version: "3"
services:
  palworld-server:
    container_name: 'steam_palworld'
    hostname: 'palworld-server'
    image: 'cm2network/steamcmd'
    ports:
    - 8211:8211/udp
    - 27015:27015/tcp
    volumes:
      - /srv/docker/containers/steam/palworld/:/home/steam/Steam/steamapps:rw
    entrypoint:
      - "/home/steam/Steam/steamapps/common/PalServer/PalServer.sh"
      # FALLS der Server gelistet werden soll, sonst Zeile löschen
      - "EpicApp=PalServer"
      # HIER öffentliche IP einsetzen
      - "-publicip=1.2.3.4"
      # FALLS ein anderer Port genutzt wird, anpassen
      - "-publicport=8211"
    environment:
      PGID: 1000
      PUID: 1000
    restart: unless-stopped
    networks:
      default:
        ipv4_address: 172.22.25.2
networks:
  default:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.22.25.0/24
    driver_opts:
      com.docker.network.bridge.name: br_steam

Nun muss die Server-Config selbst kopiert werden:

mkdir -p /srv/docker/containers/steam/palworld/common/PalServer/Pal/Saved/Config/
chown -R 1000:1000 /srv/docker/containers/steam/palworld
cp /srv/docker/containers/steam/palworld/common/PalServer/DefaultPalWorldSettings.ini /srv/docker/containers/steam/palworld/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini

Danach kann die Konfiguration angepasst werden. Informationen zu den Parametern findet man zu genüge im Internet…

Start des Servers

docker-compose up -d

Grundsätzlich loggt der Server kaum etwas und man findet nur Hinweise auf den Kontakt des Steam-Netzwerks, ansonsten bleibt es recht ruhig:

2024-02-01T10:22:44.694623116Z - Existing per-process limit (soft=xxxxx, hard=xxxxx) is enough for us (need only xxxxx)
2024-02-01T10:22:44.694638425Z Increasing per-process limit of core file size to infinity.
2024-02-01T10:22:44.694641135Z - Existing per-process limit (soft=xxxxx, hard=xxxxx) is enough for us (need only xxxxx)
2024-02-01T10:22:44.775042934Z CAppInfoCacheReadFromDiskThread took 0 milliseconds to initialize
2024-02-01T10:22:44.787811558Z Setting breakpad minidump AppID = 2394010
2024-02-01T10:22:44.788494153Z [S_API FAIL] Tried to access Steam interface SteamUser021 before SteamAPI_Init succeeded.
2024-02-01T10:22:44.788499153Z [S_API FAIL] Tried to access Steam interface SteamFriends017 before SteamAPI_Init succeeded.
2024-02-01T10:22:45.224352804Z [S_API FAIL] Tried to access Steam interface STEAMAPPS_INTERFACE_VERSION008 before SteamAPI_Init succeeded.
2024-02-01T10:22:45.279131338Z [S_API FAIL] Tried to access Steam interface SteamNetworkingUtils004 before SteamAPI_Init succeeded.

Backup

Hinweis

Das Skript wird alle 10 Minuten ausgeführt und löscht alte Backups nach 7 Tagen.

Ein einfaches Skript unter /usr/local/bin/backup_palworld.sh anlegen.

#/bin/bash

# 7 Tage Backups behalten
BACKUP_ROTATE_HOURS="$(( 7 * 24 ))"
BACKUP_DIR="/srv/backup/palworld/"

DATE=$(date +'%Y-%m-%d-%H-%M-%S')
PATH_DST="${BACKUP_DIR}/${DATE}/"
PATH_SRC="/srv/docker/containers/steam/palworld/common/PalServer/Pal/Saved/"

mkdir -p ${BACKUP_DIR}

# kopieren des Backups
rsync -aH "${PATH_SRC}" "${PATH_DST}"
# Zeitstempel auf NOW()
touch "${PATH_DST}"

backup_timeout_minutes="$(( $BACKUP_ROTATE_HOURS * 60 ))"

# alte Backups finden die älter als Rotation sind und löschen
find "${BACKUP_DIR}" -maxdepth 1 -mmin +${backup_timeout_minutes} -exec rm -rv {} \;

Das Skript mmuss noch ausführbar gemacht werden und kann dann im Crontab hinterlegt werden:

chmod 700 /usr/local/bin/backup_palworld.sh

crontab -e

# alle 10 Minuten Backup ausführen
*/10 * * * * /usr/local/bin/backup_palworld.sh

Vintage Story Server mit Docker

Vorwort

Vintage Story ist Survival-Sandbox-Game, welches gemeinsames Spielen mit Freunden mittels Server ermöglicht;

https://vintagestory.at/

Vorbereitung

Für den Bau ist Docker und Git notwendig! Falls nicht bereits installiert:

pacman -Syu docker git
apt update
apt install git docker.io

Docker Image bauen

Hinweis

Aus rechtlichen Gründen (ich habe im Chat beim Entwickler gefragt) darf ich keine fertigen Images auf Docker Hub oder anderen Registries anbieten. Deshalb habe ich ein kleines Projekt zum bauen des Images angelegt.

Einfach das Projekt herunterladen, oder auschecken:

# Projekt auschecken
git clone https://github.com/dr3st/docker-vintage-story.git
cd docker-vintage-story

# Image bauen
VS_VERSION=1.16.4 ./build.sh

Sollte es Schwierigkeiten beim bauen geben, weil zum Beispiel die Firewall etwas unterbindet, kann der Build-Befehl angepasst werden.
Alle Parameter hinter build.sh werden an “docker build” übergeben.

VS_VERSION=1.14.9 ./build.sh [--network host]

Danach steht das Image vintagestory:1.16.4 zur Verfügung.

Beim Bauen wird das aktuelle Spiel vom Hersteller heruntergeladen und in das Image integriert, siehe Dockerfile: https://github.com/dr3st/docker-vintage-story/blob/main/Dockerfile

Server einrichten

Die möglichen Parameter des Docker Images sind der README zu entnehmen: https://github.com/dr3st/docker-vintage-story/blob/main/README.md#parameters

# File: docker-compose.yml

version: '3.1'
services:
  vintage_story:
    image: "vintagestory:1.16.4"
    container_name: vintage_story
    restart: unless-stopped
    network_mode: host
    environment:
      PUID: 1000
      PGID: 1000
    volumes:
    - "/srv/docker/containers/vintage_story:/data:rw"

Im Anschluss wird der Vintage Story Server seine Daten im Hostverzeichnis /srv/docker/containers/vintage_story abspeichern, sodass weitere Konfigurationen innerhalb dieses Verzeichnisses möglich sind.