Root-Server Tutorial

ROOT-SERVER TUTORIAL

Dockerized CS:GO Game Server

Learn how to run a CS:GO game server as a Docker container.
Author

Author:

Lukas Böttcher

Publish date:

05/11/2021

Submit your tutorial

Get 60€ netcup vouchers for every published tutorial.

Introduction

In this tutorial you will learn how to run game servers in a Docker environment, specifically a Counter Strike: Global Offensive server that can automatically update itself.

Requirements

  • A server, ideally hosted by netcup :), with at least 40GB of free space and two vCPUs. At least an RS 1000 is recommended for hosting multiple game servers.
  • A Debian-based operating system on the server (Ubuntu or Debian are recommended).
  • A working Docker installation (see Docker installation tutorial) on the server.
  • Root access to your server via SSH (ideally pubkey-based).
  • A Steam account (you do not have to own Counter Strike: Global Offensive on that account).

Step 1 - Verify Docker is running correctly

Connect to your server via SSH. If you have not set up SSH access yet, follow the instructions in the corresponding tutorial before continuing with this tutorial.

After connecting to your server, verify that your Docker installation is working correctly by running

docker run hello-world

This should show you some text:

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

If you don't see this specific message or an error, Docker is not running correctly. In this case, please follow the instructions in the Docker installation tutorial again (see the official documentation).

Also make sure that your user is in the Docker group.

Otherwise continue with Step 2, everything is set up.

Step 2 - Create configuration files for the server

First create a folder that will hold all files needed for the container.

mkdir ~/csgo-container
cd ~/csgo-container

Step 2.1 - Get the necessary keys to run your CS:GO server

In order to connect to your server over the internet, you need to acquire a game server login token, short GSLT, here. Technically this is optional, but since there are very few reasons for hosting a LAN-only game server on a server, this is strongly recommended.

If you want to play on workshop maps you also need to get the API key for your Steam account here.

Be careful not to share these with anyone since misuse can result in termination of your Steam account. It is often advisable to create a new empty Steam account just for your server. But that goes beyond the scope of this tutorial.

Step 2.2 - Create configuration files for CS:GO

Since we want to create a CS:GO dedicated server, we first need to create some config files specifically for the source dedicated server - things like start options, game settings and passwords.

We do this by placing all required files in the folder we created and by copying them later to the container in Step 2.3.

First we need to create a runscript that allows the server to automatically update. Simply create a file named runscript_csgo that contains the following:

login anonymous
force_install_dir /data/csgo_ds
app_update 740
quit

Then we create a simple script that can start the server. For this to work, create a file named start-csgo.sh with the following content:

##!/usr/bin/bash
steamcmd/steamcmd.sh +login anonymous +force_install_dir /data/csgo_ds +app_update 740 +quit
sed -i -e 's#\./steam\.sh #\./steamcmd\.sh #g' csgo_ds/srcds_run # edit autoupdate for server version
csgo_ds/srcds_run -game csgo -console -usercon -port 27015 \
        -net_port_try 1 -maxplayers_override 10 -tickrate 128 \
        -nobreakpad -game csgo -console \
        -usercon -secure -authkey "<API KEY HERE>" \
        -autoupdate -steam_dir /data/steamcmd \
        -steamcmd_script /data/steamcmd/runscript_csgo

As you can see, a lot of configuration happens when the server starts. Feel free to adapt these settings as you wish. Also add your API key after the authkey argument.

Next we create two files for the game settings. First create autoexec.cfg with the following content:

sv_setsteamaccount "<ENTER GSLT HERE>"  // change this to your GSLT key
game_type 0
game_mode 1
sv_pure 1
// host_workshop_collection <WORKSHOP COL ID>
// workshop_start_map <WORKSHOP START MAP>
map de_dust2                            // set default map here if not using a workshop map
log on
sv_allow_votes 0
sv_logbans 1
sv_logecho 1
sv_logfile 1
sv_log_onefile 1
sv_hibernate_when_empty 1
sv_hibernate_ms 5
sv_maxrate "0"
sv_minrate "128000"
sv_minupdaterate "128"
sv_mincmdrate "128"
sv_pure 1
sv_pure_kick_clients 1
hostname "My CSGO Server"               // change this to your servers name (optional)
rcon_password ""                        // change this if you want to enter commands from the cs:go client (optional)
sv_password ""                          // change this to protect the server with a password (optional)
sv_cheats 0
sv_lan 0
exec banned_user.cfg
exec banned_ip.cfg

The autoexec.cfg file is executed when the server first starts, here you can define your preferred password and hostname. You can also set things like the workshop collection if you have some maps from the Steam workshop you want to play on. But most importantly, you have to add your GSLT key that you generated for your server here. Insert the GSLT key after sv_setsteamaccount in the first line. You can connect to your server over the internet if this key is present.

For all game modes and game types see this table from the Valve Developer Wiki - CS:GO Game Modes

game_type game_mode
0 1 2 3
Classic 0 Casual Competitive Wingman Weapons Expert
Gun Game 1 Arms Race Demolition Deathmatch
Training 2 Training
Custom 3 Custom
Cooperative 4 Guardian Co-op Strike
Skirmish 5 War Games
Free For All 6 Danger Zone

Now create config.cfg with the following content:

mp_autoteambalance 0
mp_limitteams 0
mp_autokick 0
writeid
writeip

These settings are executed every time a new map loads. As you can see, "Autokick" and "Team balancing" have been disabled. Feel free to change these to whatever you want to use.

Step 2.3 - Create a dockerfile for your game server

A dockerfile describes all the inner workings of the container you want to create. Starting with the FROM instruction which tells Docker what our container will be based on. In our case we will be using Ubuntu Focal.

Now create the dockerfile itself. Simply create a file named Dockerfile in the folder we created and add the following:

FROM ubuntu:focal

ENV DEBIAN_FRONTEND=noninteractive
ENV USER csgo
ENV HOME /data
ENV SERVER $HOME/csgo_ds

This sets some variables we will use later on.

Step 2.3.1 - Installing necessary packages in the container

Running a CS:GO dedicated server requires some packages. We will instruct the container to download the packages when it is first created. Just append the following instructions that install some required libraries and configure the English locales inside the container.

RUN apt update && \
    apt install curl lib32gcc1 locales -y

RUN locale-gen en_US.UTF-8 \
    && update-locale LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 \
    && dpkg-reconfigure --frontend=noninteractive locales \
    && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

Step 2.3.2 - Add a group and a user for the CS:GO server process

Running things as root is bad. But since we are running everything in a container this is actually not that big of a deal. The main reason for creating an unprivileged user is the fact that we don't want all files created in the container to be owned by root, which is annoying when extracting files from the container.

We can create a user and group for running the dedicated server by adding these lines to our dockerfile:

RUN addgroup --gid 1000 csgo \
    && adduser --system --shell /bin/false --uid 1000 --ingroup csgo --home /data csgo && \
    chown csgo:csgo -R /data

WORKDIR /data

USER $USER

Step 2.3.3 - Copy the config files into the container and install steamcmd

All config files for the CS:GO server now need to be copied into the container with the following instructions:

COPY --chown=1000:1000 runscript_csgo /data/steamcmd/runscript_csgo
COPY --chown=1000:1000 start-csgo.sh /data/start-csgo.sh
COPY --chown=1000:1000 *.cfg /data/csgo_ds/csgo/cfg/

RUN curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar -xzC /data/steamcmd

The last line simply downloads the steamcmd program from Valve, which allows us to download csgo and all other Steam games into our container.

Step 2.3.4 - Add an entrypoint to our dockerfile

Since all configuration is complete, we now can open ports and run our start-csgo.sh that we created earlier. Just add these lines, which expose the default ports for csgo and run the script:

EXPOSE 27015/tcp
EXPOSE 27015/udp

CMD [ "sh", "/data/start-csgo.sh" ]

At this point our dockerfile is done and ready to be deployed.

Step 2.3.5 - Complete dockerfile

This should be the final dockerfile:

FROM ubuntu:focal

ENV DEBIAN_FRONTEND=noninteractive

ENV USER csgo
ENV HOME /data
ENV SERVER $HOME/csgo_ds

RUN apt update && \
    apt install curl lib32gcc1 locales -y

RUN locale-gen en_US.UTF-8 \
    && update-locale LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_ALL=en_US.UTF-8 \
    && dpkg-reconfigure --frontend=noninteractive locales \
    && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

RUN addgroup --gid 1000 csgo \
    && adduser --system --shell /bin/false --uid 1000 --ingroup csgo --home /data csgo && \
    chown csgo:csgo -R /data

WORKDIR /data

USER $USER

COPY --chown=1000:1000 runscript_csgo /data/steamcmd/runscript_csgo
COPY --chown=1000:1000 start-csgo.sh /data/start-csgo.sh
COPY --chown=1000:1000 *.cfg /data/csgo_ds/csgo/cfg/

RUN curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar -xzC /data/steamcmd

EXPOSE 27015/tcp
EXPOSE 27015/udp

CMD [ "sh", "/data/start-csgo.sh" ]

Step 3 - Start the container

Now all you need to do is

  • build the container
  • run the container.

To build the container simply run:

docker build . -t csgo

and run:

docker run -d --restart=unless-stopped --name csgo \
    -p 27015:27015/udp -p 27015:27015 -it -v csgo_data:/data csgo

to start the container with default ports. If you plan on running multiple containers or prefer different ports, you need to adjust the port mappings accordingly with the -p argument.

Now the container should be started and will begin downloading the CS:GO dedicated server. This can take some minutes since there are about 20GB of server files to be downloaded.

You can see the logs by running:

docker logs -f csgo

You can also easily start, restart and stop the container by running:

docker start csgo
docker restart csgo
docker stop csgo

If you want to get shell access inside the container to edit config files, you can do that by running:

docker exec -it csgo bash

Alternatively you sometimes might need access to the command line interface for the CS:GO server if you don't want to use RCON. This can be done by attaching to the container by running:

## this is essentially the same as opening your console in the CS:GO client
docker attach csgo

To leave this console, press CTRL-P + Q.

Another useful thing are backups, which are not really needed in this example, since most of the server state is configured in the config files, but still can be useful. To copy files from the container to your computer, you can run:

docker cp csgo:/data/csgo_ds/csgo/cfg/<files to copy> .

Conclusion

You should have a running CS:GO dedicated server that keeps itself up to date. All data is stored in the csgo_data Docker volume, which persists the data even if you remove the container.

Now anyone who owns the CS:GO game can join your server by connecting via the community server browser in game or with this URL, where example.com is your server's domain or IP address and sv_password is the password you set up in step 2.2 in the autoexec.cfg:

steam://connect/<example.com>/<sv_password>

All steps are essentially the same for other source games from Valve, such as Garry's Mod or CSS, feel free to try out those games as well.

License

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Contributor's Certificate of Origin

By making a contribution to this project, I certify that:

  1. The contribution was created in whole or in part by me and I have the right to submit it under the license indicated in the file; or

  2. The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same license (unless I am permitted to submit under a different license), as indicated in the file; or

  3. The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.

  4. I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the license(s) involved.

Published 05/11/2021 by Lukas Böttcher

Submit your tutorial

Get 60€ netcup vouchers for every published tutorial.