nice cat watch screen

Binary Maelstrom

Dockerizing Arma3 servers

Hey guys !

As you might know, I’m a sysOps, but I’m also a gamer IRL. So why not talking about game servers administration? I’m a huge fan of hardcore survival games (like DayZ) and also realistics FPS. One of my favorites is Arma3 from Bohemia Studio. Arma3 is basically an engine/a sandbox to build mission(s) with and the modding community is very active on it. Wasteland, Battle Royale, Life are among the most famous mods using this engine.

Cool thing is Arma3 server-side components are freely (like in free beer, not free speech) available and runnable. You just need a Steam account, but no need to purchase the game. Moreover, Arma3 is GNU/Linux compatible! So let’s talk about Arma3 server setup on Linux. Hmmm, no ! Let’s talk about Arma 3 dockerized server running on Linux! Yeah!!

To introduce Arma3 server setup, I will sum up my feeling about documentations and tutorials available about this topic: it’s a mess !! I mean, there is a pretty good official documentation but everything is scattered, which is, from my point of view, difficult to understand. So I’ll try to be clear with my explanations…

I will presume you are familiar with Dockerfile, and if not, I suggest you to read this and this!

First thing first, my docker container will use a volume to store its data, because:

  1. It’s a lot of data
  2. Arma3 server needs to be restarted regularly (don’t ask me why, ask Bohemia instead ;))

All right, now :

  1. I use GNU/Linux Debian Jessie,
  2. I will need some dependencies and expose some network ports.
  3. I have to create a bootstrap script to launch the server.

Let’s inspect the Dockerfile:

FROM debian:jessie
MAINTAINER bmljb2xhc0Bha2lyYS5mcgo= 

RUN apt-get update && apt-get -y upgrade
RUN apt-get install -y lib32gcc1 lib32stdc++6 wget
RUN useradd -u 2000 -m -d /home/steam/ -s /bin/bash steam

USER steam

VOLUME ["/home/steam/"]
ADD start.sh /start.sh
ADD server.cfg /tmp/server.cfg

EXPOSE 2302/udp
EXPOSE 2303/udp
EXPOSE 2304/udp

CMD ["/bin/bash", "/start.sh"]

Some explanations:

  1. I set the user id in order to have the same uid (permissions) in both container and host. With an up-to-date release of docker, you can use the remap-id feature which accomplishs the same thing.
  2. USER steam is for security reason, we don’t start our server as root, never! I mean: NEVER!!!! Seriously guys, I saw plenty of tutorials saying to run server instances as root, this could be dangerous.
  3. We add the configuration file for the server (server.cfg) and start.sh which configure the steam directory and launch the server (I will explain more about this one below).

Now, let’s take a look at start.sh.

This script will:

  1. Create directories in /home/steam
  2. Setup the Steam installation script for Arma3 and run it.
  3. Get the default server.cfg or get a custom one from $ARMA3_SERVER_CFG environment variable.
  4. Generate passwords for the server if $SERVER_UPDATE_PASSWORD is defined. If not, use the default ones.
  5. In a final step, we look for $MOD_SCRIPT which is a script aims to do additional configuration (useful when derivating this Dockerfile to run a new mod). Otherwise, simply starts the server with standart parameters.

Putting things together, this look like:

#!/bin/bash

STEAM_VOLUME="/home/steam"
STEAMCMD="$STEAM_VOLUME/steamcmd"
ARMA3_INST="$STEAMCMD/arma3_inst.txt"
WGET_BIN=$(command -v wget)
TAR_BIN=$(command -v tar)

if [ ! -d "$STEAMCMD" ]; then
    mkdir $STEAMCMD
fi

cat << EOF > $STEAMCMD/arma3_inst.txt 
// installing arma3
@ShutdownOnFailedCommand 1 //set to 0 if updating multiple servers at once
@NoPromptForPassword 1
login $STEAM_LOGIN $STEAM_PASSWORD
force_install_dir ./arma3/
app_update 233780 validate
quit
EOF

$WGET_BIN -O /tmp/steamcmd_linux.tar.gz https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz
$TAR_BIN --overwrite -xvzf /tmp/steamcmd_linux.tar.gz -C $STEAMCMD

if [ ! -z ${ARMA3_UPDATE_DATA+x} ] || [ ! -f $STEAMCMD/arma3/server.cfg ]; then
    $STEAMCMD/steamcmd.sh  +runscript $ARMA3_INST
    mkdir -p $HOME/".local/share/Arma 3"
    mkdir -p $HOME/".local/share/Arma 3 - Other Profiles"
fi

if [ -z ${ARMA3_SERVER_CFG+x} ]; then
    echo "Using the default server.cfg..."
    cp /tmp/server.cfg $STEAMCMD/arma3/server.cfg
else
    echo "Using custom server.cfg..."
    $WGET_BIN -O $STEAMCMD/arma3/server.cfg $ARMA3_SERVER_CFG
    local STATUS=$?
    if [ $STATUS -ne 0 ]; then
        echo "Unable to fetch server.cfg from remote, falling back to default server.cfg..."
        cp /tmp/server.cfg $STEAMCMD/arma3/server.cfg
    fi
fi

if [ ! -z ${SERVER_UPDATE_PASSWORD+x} ]; then
    ADMIN_PASSWORD=$(cat /dev/urandom| tr -dc 'a-zA-Z0-9!#' | fold -w 15 | head -1)
    SERVER_COMMAND_PASSWORD=$(cat /dev/urandom| tr -dc 'a-zA-Z0-9!#' | fold -w 15 | head -1)
    sed -i "s/passwordAdmin.*/passwordAdmin = \"$ADMIN_PASSWORD\";/g" $STEAMCMD/arma3/server.cfg
    sed -i "s/serverCommandPassword.*/serverCommandPassword = \"$SERVER_COMMAND_PASSWORD\";/g" $STEAMCMD/arma3/server.cfg
else
    ADMIN_PASSWORD=$(grep passwordAdmin $STEAMCMD/arma3/server.cfg | cut -f2 -d'"')
    SERVER_COMMAND_PASSWORD=$(grep serverCommandPassword $STEAMCMD/arma3/server.cfg | cut -f2 -d'"')
fi

echo "admin password: $ADMIN_PASSWORD"
echo "server command password: $SERVER_COMMAND_PASSWORD"

#######################################################
# This is the mod specific part. Anyone can overwrite
# This file to configure a specific mod in top of this 
# Arma3 Docker image. 
# You just need to define $MOD_SCRIPT when running and 
# add it to the image build.

if [ ! -z ${MOD_SCRIPT+x} ] && [ -f $MOD_SCRIPT ]; then
    echo "Launching $MOD_SCRIPT to setup mod for this instance"
    /bin/bash $MOD_SCRIPT
#######################################################
else
    cd $STEAMCMD/arma3/ && ./arma3server -name=public -config=server.cfg
fi

You now have a basic container working with Arma3. At this point, you just need to set the Missions class with the missions you wanna play.

$MOD_SCRIPT can be used to pass additional commands to configure, for instance, Life mods using this Dockerfile as a base. Okay, this is cool, but how I used it to do so ? Well, my friend, I will write about it soon to setup a container running Arma3 AltisLife.

To conclude, you can go see my github repository to access the content and have additional explanations on how to run the container.

Be creative, post comments and Dockerize!

Adios!

comments powered by Disqus