Project Zomboid Server in Docker Compose (BETA)
Usually I don't like to expose infrastructure information but this time I make an exception. Some parts of the code might be changed for privacy reasons though.
Before focusing on IT-Security related content I wanted to create a Project Zomboid Gaming Server during xmas holiday season.
The code is free to use.
Docker compose setup
I started using the steamcmd:root image from cm2network: https://hub.docker.com/r/cm2network/steamcmd/
The docker image itself only provides steamcmd which then can be used to host different kind of Steam dedicated servers.
I opted for the root version of the image for developing purposes such as installing Linux packages during runtime.
# docker-compose.yml
services:
steamcmd:
image: cm2network/steamcmd:root
container_name: steamcmd
tty: true
ports:
- "0.0.0.0:16261:16261/udp"
- "0.0.0.0:16262:16262/udp"
volumes:
- /mount/steamcmd_login_volume:/home/steam
- /mount/steamcmd_volume:/home/steam/steamcmd
Beside defining the steamcmd:root image I also had to open both ports udp/16261 and udp/16262 used by the game client.
The volumes themselves are (persistent) bind mounts.
Installation
The initial installation procedure can be found on the PZWIKI page. I followed the installation procedure for steamcmd using the steam user:
cat >$HOME/update_zomboid.txt <<'EOL'
// update_zomboid.txt
//
@ShutdownOnFailedCommand 1 //set to 0 if updating multiple servers at once
@NoPromptForPassword 1
force_install_dir /opt/pzserver/
//for servers which don't need a login
login anonymous
app_update 380870 validate
quit
EOL
steamcmd +runscript $HOME/update_zomboid.txt
Source: https://pzwiki.net/wiki/Dedicated_Server#Linux
Auto Update
The script below uses three functions to keep the Project Zomboid Server up2date from outside of the steamcmd docker container. The script is stored under " /etc/cron.hourly".
"checkupdate()" is used to get the installed build version number as well as the latest build number from https://api.steamcmd.net. In case the Project Zomboid Server is up2date a log entry gets created and the script exits.
"updater()" gets activated once there is a new build avaibable. It first kills the game server before executing the update. Afterwards the server gets started again in background. Consider using a better way to close the server than just terminating the Linux process. I am just lazy :)
"check_availability()" then check if the processes are running and report the status accordingly to the logs.
Replace <SERVERNAME> with the servername set during the initial setup.
#!/bin/bash
checkupdate() {
# get current build id
CURRENTBUILD=$(docker exec steamcmd grep -i 'buildid' /home/steam/Steam/logs/content_log.txt | tail -n 1 | sed -n 's/^.*BuildID\s\([0-9]\+\).*$/\1/p')
# get latest build id from steamcmd API
LATESTBUILD=$(curl -s https://api.steamcmd.net/v1/info/380870 | jq '.["data"]["380870"]["depots"]["branches"]["public"]["buildid"]' | cut -d "\"" -f 2)
if [ $CURRENTBUILD == $LATESTBUILD ]; then
logger -p Info -t ZomboidUpdater INFO: "PZserver up2date. Exiting.."
exit
else
:
fi
}
updater() {
#0 install ps just in case the container got rebooted
docker exec steamcmd apt update
docker exec steamcmd apt install procps -y
#1 kill pzserver
for i in $(docker exec steamcmd ps -aux | grep '<SERVERNAME>' | awk '{print $2}'); do docker exec steamcmd kill $i; done
#2 update pzserver
docker exec -u steam steamcmd /home/steam/steamcmd/steamcmd.sh +runscript /home/steam/Steam/servers/projectzomboid/update_zomboid.txt
#3 start pzserver
docker exec -u steam steamcmd nohup /home/steam/Steam/servers/projectzomboid/start-server.sh -servername <SERVERNAME> &
}
check_availability() {
# check if pzserver proccesses are running and assign it to the PSTAT variable
PSTAT=$(docker exec steamcmd ps -aux | grep '<SERVERNAME>' | wc -l)
# if the NTSTAT variable equals "2" then both of the pzsever ports are open and everything runs as expected
if [ $PSTAT == 2 ]; then
logger -p Info -t ZomboidUpdater SUCCESS: "Processes are UP. PZserver seems to run"
else
logger -p Error -t ZomboidUpdater FAILED: "Processes are DOWN. PZserver does not seem to run"
fi
}
checkupdate
updater
check_availability