This guide shows how a Killing Floor 2 server can be setup in an LXC container.


Refer to Installing Killing Floor 2 Dedicated Server in Linux for motivation why you might want to do this.

A recap on container security: Anything that runs as root inside the container (guest) also has root access to the host machine, since they run on the same Linux kernel instance. You must make very sure that the container application can never get unauthorized privileged access. This is in contrast to virtualization, where the guest runs a separate operating system kernel and can never take over the host in the general case.


Get yourself a minimal Linux installation running in a container somehow. It must be 64-bit and recent enough to have Wine 1.9 packaged. I'm using a Debian 8 guest (container) running on a Debian 8 host system using LXC managed by libvirt. If you have a similar host system you may want to have a look at my guide on getting LXC to work with libvirt in Debian Jessie.


Create the container with a minimal Debian installation:

# lxc-create -t debian -n kf2server

Write down the root password. Start it up:

# lxc-start -n kf2server

Get the console fixed according to my previous article. Shut down the container.

Write a domain definition like this one, which I also described in my previous article about LXC. Make sure to edit the name and paths according to your installation.

Import the definition into libvirt:

# virsh --connect lxc:/// define kf2server.xml

Start the new domain and connect to its console:

# virsh --connect lxc:/// start kf2server
# virsh --connect lxc:/// console kf2server

System wide container configuration

In this part the system wide configuration of the container is done. As I would like to be able to destroy/recreate the server at will I created a script to semi-automate this part. It is shown below.

# Start the container with libvirt and run this in the console to configure the
# system.

set -e

# jessie/contrib for winetricks
cat > /etc/apt/sources.list <<EOF
deb jessie main contrib

# Optionally use apt-cacher-ng, if you have one
cat > /etc/apt/apt.conf.d/02proxy <<EOF
Acquire::http::proxy "http://aptcache:3142";

# wget is used to download the WineHQ release key over HTTPS next
apt-get update
apt-get install -y wget </dev/null

# Unstable wine repo for Wine 1.9
cat > /etc/apt/sources.list.d/wine.list <<EOF
deb jessie main
apt-key add Release.key

# Enable 32-bit multiarch
dpkg --add-architecture i386
apt-get update

# xserver-common for MS VC runtime installer
apt-get install -y xserver-common </dev/null
apt-get install -y wine-staging wine-staging-amd64 winehq-staging </dev/null
# winetricks just for its dependencies. We will actually use the latest version from git.
# expect for unbuffer
# sudo for unprivileged control of the server systemd service
apt-get install -y winetricks expect sudo </dev/null

# Optionally install your favorite tools for managing the server's config files
apt-get install -y git vim less </dev/null

# Get the latest winetricks, since the repository version doesn't support wine 1.8
pushd /usr/local/bin/
chmod +x winetricks

# Create the non-privilegied user account. Nobody likes /bin/sh (default shell)
useradd --system --create-home --shell /bin/bash kf2server

# Allow the unprivileged user to start/stop the server
cat >> /etc/sudoers <<EOF
kf2server ALL=NOPASSWD:/bin/systemctl status kf2server.service
kf2server ALL=NOPASSWD:/bin/systemctl start kf2server.service
kf2server ALL=NOPASSWD:/bin/systemctl stop kf2server.service

visudo --check

View raw file

First, WineHQ's binary repo is installed. Next, APT is configured to use a local cache as a proxy. If you set up and tear down a lot of similar containers, you might want to set up your own cache using apt-cacher-ng or similar. It can save you a lot of time in skipped package downloads in the long run.

Next, Wine 1.9 and friends are installed using APT. winetricks from Debian is only installed to pull in all its dependencies, but the script itself will not actually be used. Instead, the git tip version of winetricks is installed next, since the packaged version in Debian does not support Wine 1.9.

A non-privileged account is then created that will run Steam and the actual Killing Floor 2 server. It is allowed to control the systemd service kf2server, which does not exist yet.

At this point you can download my custom service unit for the KF2 server and drop it into /etc/systemd/system/kf2server.service. Refer to my article on installing Killing Floor 2 Dedicated Server in Linux for more information on how it works and how you might need to customize it.

Finally, you may manually enable the service so that it starts automatically on the next boot:

# systemctl enable kf2server.service

User configuration

In this part we will configure Wine and install Steam as the unprivileged user. As part of the installation we will install Microsoft Visual C Runtime 2010 using winetricks. This is a graphical installation program, like it or not, so we need a way to display X windows somehow. I chose to use SSH with X Forwarding to display the windows on my desktop computer tunneled through SSH.

While still logged into the console as root, su to the unprivileged user:

# su - kf2server

Put your public SSH key in /home/kf2server/.ssh/authorized_keys. Log out and close the console. Using a desktop Linux machine, SSH to the container as the unprivileged user with X Forwarding enabled:

$ ssh -X kf2server@kf2server

Run winetricks vcrun2010 to install Visual C Runtime. Answer no to the offers of installing Mono and Gecko, unless you want them for some other purpose. A graphical installation wizard should then show. Follow the instructions.

Finally, to install Steam and Killing Floor 2 Dedicated Server, run the following script. It should be self-explanatory.

# Run this as the unprivilegied user in the container. Press "next, next,
# finish" and "OK" in the windows as applicable.

set -e

# Download and unpack SteamCMD
mkdir .wine/drive_c/steamcmd
mv steamcmd.exe .wine/drive_c/steamcmd/

# Install and/or update KF2 dedicated server
wine "C:/steamcmd/steamcmd.exe" +login anonymous +force_install_dir kf2server +app_update 232130 +quit

# Start the server manually for testing. Exit with Ctrl+C twice.
wine "C:/steamcmd/kf2server/Binaries/Win64/KFServer.exe" kf-burningparis

View raw file

Future work

You may want to install unattended-upgrades to keep the system packages up-to-date.

Furthermore, the KF2 server is not automatically updated. When a new version is released you need to manually SSH into the server, stop the server and re-run steamcmd.exe with the +app_update option. You will notice when this happens because your server will disappear from the server browser.