Difference between revisions of "Linux dedicated server"

From Team Fortress Wiki
Jump to: navigation, search
m (Updated forenote for modern operating systems.)
(Create a shell script to run the server: use exec in the shell script)
 
(74 intermediate revisions by 38 users not shown)
Line 1: Line 1:
{{ambox | type = notice | image = Ambox_notice.png | contents = '''This guide''' assumes you know how to use the '''terminal/command line in Linux'''.}}
+
{{ambox  
 +
| type = notice  
 +
| image = Tux_Normal_Style.png|300px
 +
| contents = This guide assumes that the reader has a ''basic understanding'' of using the Linux command line terminal.
 +
}}
 +
{{Cleanup|This page is very long with some very messy formatting, some changes to be made could be finding a way to collapse large sections of the text in <nowiki><code></nowiki> tags (without the use of a table, preferably) and splitting the current text up into more headers.}}
  
This is a setup guide that allows you to install a basic ''[[Team Fortress 2]]'' '''Linux dedicated server'''. In the below example the [[server]] is installed into the user's home directory in a directory called 'hlserver'.
+
This is a setup guide that walks you through the installation process of a basic ''Team Fortress 2 dedicated server'' on '''GNU/Linux (x86 or amd64)''' or a '''FreeBSD (x86 or amd64)''' system with Linux compatibility patches running in its kernel. In the example below, the [[Servers|server]] is installed into the user's home directory in a directory called <code>hlserver</code>.
  
Basic installation and configuration for a '''Linux dedicated server''' is the same for all distributions, but small details, such as package names, directories, etc. may differ from distribution to distribution. It is recommended that you check your distribution's repositories for the required packages before continuing. A link to a chef recipe based on this guide is also available in the "See also" section.  
+
Basic installation and configuration of a dedicated server is almost the same on most Linux distributions, but small details, such as package names and directories may differ from distribution to distribution. It is recommended that you check your package manager's repositories for the required packages before continuing.
  
== Reading this article ==
+
Note: information about [[Windows dedicated server|running a server on Windows]] is often applicable on Linux, for example, files like <code>server.cfg</code> and <code>motd_default.txt</code> are identical between platforms. Check that page for additional details and suggestions. Information on that page and this one may also be useful on other Unix-like platforms.
This article has been written according to standard Linux documentation syntax, meaning the following:
 
  
* A command prefixed by <code>#</code> (a hash) is meant to be run as '''root'''. Most distributions have a separate root account; for other distributions such as Ubuntu, Linux Mint, Crunchbang, etc., the '''sudo''' prefix to a command will ensure the command is run as root, or you can use the '''su''' command to make all following command be run as '''root'''.
+
==Reading this article==
* A command prefixed by <code>$</code> (a dollarsign) is meant to be run as a '''user'''.
+
This article has been written according to standard Linux terminal documentation syntax, meaning the following:
* <code>./</code> means "current working directory".
 
  
== Requirements ==
+
* A command prefixed by <code>#</code> (a hashtag) is meant to be run as '''root'''. Most distributions have a separate root account; for other distributions such as Ubuntu, Linux Mint and Crunchbang, prepending <code>sudo</code> to a command will ensure that the command is run as root. An alternative would be to use the <code>su</code> command to make all following commands run as '''root''', although this is not recommended.
A number of requirements exist in order to run a ''Team Fortress 2'' server on the Linux platform, namely:
+
* A command prefixed by <code>$</code> (a dollar sign) is meant to be run as a '''regular user''' without root permissions.
 +
* <code>./</code> means ''current working directory'', the directory in which commands entered into the terminal will be executed.
 +
 
 +
==Docker==
 +
If your server is running [https://www.docker.com/ Docker], you can simply use:
 +
<pre>
 +
docker run -d --net=host --name=tf2-dedicated -e SRCDS_TOKEN={YOURTOKEN} -it cm2network/tf2
 +
</pre>
 +
SRCDS_TOKEN is required to be listed; https://steamcommunity.com/dev/managegameservers
 +
 
 +
The container will automatically update the game on startup, so if there is a game update just restart the container.
 +
 
 +
The config is located here: ''/home/steam/tf2-dedicated/tf/cfg''
 +
 
 +
If you want to launch another instance you can increment the environment variables, using -e (--env):
 +
<pre>
 +
docker run -d --net=host -e SRCDS_PORT=27016 -e SRCDS_TV_PORT=27021 -e SRCDS_TOKEN={YOURTOKEN} -it --name=tf2-dedicated2 cm2network/tf2
 +
</pre>
 +
SRCDS_TOKEN is required to be listed; https://steamcommunity.com/dev/managegameservers
 +
 
 +
You can find the associated Docker Hub page here:
 +
[https://hub.docker.com/r/cm2network/tf2/ https://hub.docker.com/r/cm2network/tf2/]
 +
 
 +
==Step by step==
 +
===Requirements===
 +
A number of requirements exist in order to run a ''Team Fortress 2 dedicated server'' on the '''GNU/Linux''' platform, namely:
  
 
* Write-access to the current working directory
 
* Write-access to the current working directory
* <code>glibc >= 2.3.6</code>
+
* A version of <code>glibc</code> equal to or newer than 2.3.6.
* Approximately 4.49GB hard-drive space (for a barebones server with no custom maps, sounds, etc.)
+
* Approximately 8GB of free hard-drive space (for a barebones server with no custom maps, sounds, etc).
* If you are installing on FreeBSD (which is not Linux at all), you must enable Linux compatibility in the kernel and install a base system via the ports collection.  Instructions to get you started are located [https://www.ian-justman.com/wiki/index.php?title=HowTos:SRCDS_under_FreeBSD here]. WARNING: This guide is outdated. Consider consulting the [https://www.freebsd.org/doc/handbook/linuxemu-lbc-install.html FreeBSD Handbook] or other more recent sources of information.
+
* If you are following this tutorial on a FreeBSD system, then most of the commands shown here are still applicable, but you must enable Linux compatibility in the kernel and install a base system via the ports collection.  Instructions to get you started are located [https://www.ian-justman.com/wiki/index.php?title=HowTos:SRCDS_under_FreeBSD here]. '''WARNING''': This guide is outdated. Consider consulting the [https://www.freebsd.org/doc/handbook/linuxemu-lbc-install.html FreeBSD Handbook] or other more recent sources of information.
* In the case of a '''64-bit''' distribution, the package '''lib32gcc1''' or '''ia32-libs''' is required to be installed:
+
* In the case of a '''64-bit''' distribution, the package named '''lib32gcc1''' or '''ia32-libs''' is required to be installed:
:On 64-bit CentOS run:
+
:On 64-bit CentOS or Fedora run:
 
:
 
:
 
:<code># yum install ncompress libgcc.x86_64 libgcc.i686 glibc.i686 zlib.i686 ncurses-libs.i686</code>
 
:<code># yum install ncompress libgcc.x86_64 libgcc.i686 glibc.i686 zlib.i686 ncurses-libs.i686</code>
 
:
 
:
:On 64-bit Debian/Ubuntu/Linux Mint run: 
+
:On Fedora, also do:
 +
:<code># dnf install libstdc++.i686 ncurses-compat-libs.i686 libcurl.i686</code>
 
:
 
:
:<code>$ sudo apt-get install lib32z1 lib32ncurses5 lib32bz2-1.0 lib32gcc1</code>
+
:On 64-bit Debian/Ubuntu/Linux Mint run:
 
:
 
:
:For x86_64 Arch Linux run (you need to have multilib repositories enabled):
+
:<code>$ sudo dpkg --add-architecture i386</code>
 +
:<code>$ sudo apt-get update</code>
 +
:<code>$ sudo apt-get install lib32z1 libncurses5:i386 libbz2-1.0:i386 lib32gcc-s1 lib32stdc++6 libtinfo5:i386 libcurl3-gnutls:i386 libsdl2-2.0-0:i386 </code>
 
:
 
:
:<code># pacman -Syy lib32-gcc-libs</code>
+
:For x86_64 Arch Linux run:
 +
:
 +
:<code># pacman -Syy lib32-gcc-libs lib32-libcurl-gnutls</code>
 +
:
 +
:(you need to have multilib repositories enabled)
 +
:
 +
: For terminal support on x64 Arch Linux, install <code>lib32-ncurses5-compat-libs</code> from the Arch user repository.
  
==Download and install the SteamCMD Tool==
+
You may also need to install other packages in their 32-bit forms (eg libcurl4-gnutls).
 +
 
 +
===Download and install the SteamCMD Tool===
  
 
'''It is recommended you create a separate user (such as "gameserver") to install and run game servers.'''
 
'''It is recommended you create a separate user (such as "gameserver") to install and run game servers.'''
  
*Download [http://media.steampowered.com/installer/steamcmd_linux.tar.gz steamcmd_linux.tar.gz]
+
*Create a user named "gameserver"
wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz
+
<code># useradd --create-home gameserver</code>
*Use tar to uncompress it to a directory, for example './hlserver' :
+
*As the "gameserver" user, create a directory in which SteamCMD will be installed, eg '~/hlserver':
tar zxf steamcmd_linux.tar.gz
+
<code>$ mkdir ~/hlserver</code>
 +
*Change the current working directory to ''hlserver'':
 +
<code>$ cd ~/hlserver</code>
 +
*Download steamcmd_linux.tar.gz :
 +
<code>$ wget https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz</code>
 +
*Use the tar command to uncompress the archive into the working directory:
 +
<code>tar zxf steamcmd_linux.tar.gz</code>
 +
 
 +
* On Fedora, you also need to do:
 +
<pre>
 +
$ mkdir -p ~/.steam/sdk32
 +
$ ln -s ~/hlserver/linux32/steamclient.so ~/.steam/sdk32/
 +
# ln -s /usr/lib/libcurl.so.4 /usr/lib/libcurl-gnutls.so.4
 +
</pre>
 +
 
 +
===Download the Server===
 +
*Use this command to download the latest server:
 +
 
 +
<pre>
 +
./steamcmd.sh +force_install_dir ./tf2 +login anonymous +app_update 232250 +quit
 +
</pre>
 +
 
 +
*If you want to opt-in to the pre-release version of the TF2 dedicated server, add the following line:
 +
-beta prerelease
 +
 
 +
*You can update the server in the future by executing this command again.
 +
 
 +
*<b>If you receive the error "Error! App '232250' state is 0x202 after update job."</b>
 +
:» You do not have enough available disk space.
 +
*<b>If you get the error saying <code>/something/linux32/steamcmd - No such file or directory</code></b>
 +
:» You did not install the requirements listed above.
  
==Create a steamcmd script==
+
===Creating/Updating server configuration files===
*Create a file called tf2_ds.txt in the folder where you install the tool, i.e. './hlserver'
 
*Edit the file with this text:
 
login anonymous
 
force_install_dir ./tf2
 
app_update 232250
 
quit
 
  
If you want to opt in to the prerelease version of the TF2 dedicated server, add this line before the app_update line:
+
*Change the current working directory to <code>~/hlserver/tf2/tf/cfg</code>:
beta prerelease
+
<code>$ cd ~/hlserver/tf2/tf/cfg</code>
 +
*Create a file named ''server.cfg'':
 +
<code>$ nano server.cfg</code>
 +
*Add the following content into your ''server.cfg'' (see [[Windows dedicated server]] for more information):
  
==Create an updating shell script==
+
<pre>
Create a file called update.sh in the folder where you installed the tool, i.e. './hlserver' and add the following text into that file:
+
hostname "Your_Server's_Name"
 +
rcon_password "Your_Rcon_Password"
 +
sv_contact "admin@yourdomain.com"
 +
mp_timelimit "30"
 +
</pre>
  
 +
* Edit the files motd.txt, maplist.txt (?), and mapcycle.txt, all found in the '~/hlserver/tf2/tf' folder.
 +
 +
===Create a shell script to run the server===
 +
*Create a file tf2.sh in './hlserver/tf2' with the following contents, replacing <code>[STEAMTOKEN]</code> with your token:
 
  #!/bin/sh
 
  #!/bin/sh
  ./steamcmd.sh +runscript tf2_ds.txt
+
  cd /home/gameserver/hlserver/tf2 || exit 1
 +
exec ./srcds_run -console -game tf +sv_pure 1 +randommap +maxplayers 24 +sv_setsteamaccount [STEAMTOKEN]
 +
 
 +
*+sv_setsteamaccount is required to be listed; https://steamcommunity.com/dev/managegameservers!
 +
*Make the file executable:
 +
<code> # chmod u+x tf2.sh </code>
 +
*Run <code>./tf2.sh</code> to launch the server:
 +
<code>$ ./tf2.sh</code>
 +
 
 +
===Ports===
 +
* Ports used by TF2 & those that need to be opened on your server to allow connection from users outside your local network.  See below section on setting up port forwarding.
 +
** UDP 27015 - Main connection port (MUST). This is the port and protocol used by the server browser, allows clients to connect.
 +
** TCP 27015 - This port is used for RCON such as with SourceBans (if needed).
 +
** UDP 27020 - SourceTV (if enabled). You can disable this port by adding "-nohltv" to the start up command.
 +
** UDP 27005 (Optional) - This is an outgoing connection used by clients. Typically you would not need to open this port in your firewall because this is for OUTBOUND connections.
 +
* if you are using AWS EC2, open at least the main inbound port UDP 27015 src 0.0.0.0/0, and add as other ports as needed.
 +
* To see ports used by TF2 and user connecting: <code>$ netstat -a |egrep 270 </code>
 +
 
 +
====UFW====
 +
If UFW is installed you can use the following commands:
 +
<pre>
 +
ufw allow 27015
 +
ufw allow 27020/udp
 +
</pre>
 +
 
 +
====IPTables====
 +
 
 +
Firstly, run <code>sudo -i</code> to get a root prompt. Then, enter this (all one line). To leave the root prompt and return to the standard user, just type <code>exit</code> like normal.
 +
<pre>
 +
iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27016 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27017 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27018 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27019 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27016 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27017 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27018 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27019 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT
 +
</pre>
 +
 
 +
Or, equivalently:
 +
 
 +
<pre>
 +
for port in 27005 {27015..27020}; do for proto in udp tcp; do iptables -A INPUT -i venet0 -p $proto -m $proto --dport $port -m state --state NEW,ESTABLISHED -j ACCEPT; done done
 +
</pre>
 +
 
 +
=====CentOS 6.4 (minimal install)=====
 +
 
 +
on CentOS 6.4 the default IPTables rules has a reject line as the last entry. This will cause all traffic to be rejected if you append (as the above commands recommend). To fix this I recommend first running the server to determine what ports it uses:
 +
 
 +
<pre>
 +
netstat -lnptu
 +
</pre>
 +
 
 +
This should output something like this:
 +
<pre>
 +
(Not all processes could be identified, non-owned process info
 +
will not be shown, you would have to be root to see it all.)
 +
Active Internet connections (only servers)
 +
Proto Recv-Q Send-Q Local Address              Foreign Address            State      PID/Program name
 +
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                  LISTEN      -
 +
tcp        0      0 127.0.0.1:25                0.0.0.0:*                  LISTEN      -
 +
tcp        0      0 0.0.0.0:27015              0.0.0.0:*                  LISTEN      1393/./srcds_linux
 +
tcp        0      0 :::22                      :::*                        LISTEN      -
 +
tcp        0      0 ::1:25                      :::*                        LISTEN      -
 +
udp        0      0 0.0.0.0:27020              0.0.0.0:*                              1393/./srcds_linux
 +
udp        0      0 0.0.0.0:26901              0.0.0.0:*                              1393/./srcds_linux
 +
udp        0      0 0.0.0.0:68                  0.0.0.0:*                              -
 +
udp        0      0 0.0.0.0:27005              0.0.0.0:*                              1393/./srcds_linux
 +
udp        0      0 0.0.0.0:27015              0.0.0.0:*                              1393/./srcds_linux
 +
</pre>
 +
 
 +
The ports listed with the ./srcds_linux name are being used by your server. In this instance port 27015 is using TCP, and ports 26901, 27005, 27015, and 27020 are using UDP. These ports need to be added to the iptables rules so that the firewall will not block access to incoming traffic.
 +
 
 +
To add them, first you should find out what is currently in your iptables config. You must do all these commands as root. The most secure method of doing this is prepending <code>sudo</code> to each command.
 +
 
 +
<pre>
 +
# iptables -nL --line-numbers
 +
</pre>
 +
 
 +
Which should output something like this:
 +
<pre>
 +
Chain INPUT (policy ACCEPT)
 +
num  target    prot opt source              destination
 +
1    ACCEPT    all  --  0.0.0.0/0            0.0.0.0/0          state RELATED,ESTABLISHED
 +
2    ACCEPT    icmp --  0.0.0.0/0            0.0.0.0/0
 +
3    ACCEPT    all  --  0.0.0.0/0            0.0.0.0/0
 +
4    ACCEPT    tcp  --  0.0.0.0/0            0.0.0.0/0          state NEW tcp dpt:22
 +
5    REJECT    all  --  0.0.0.0/0            0.0.0.0/0          reject-with icmp-host-prohibited
 +
 
 +
Chain FORWARD (policy ACCEPT)
 +
num  target    prot opt source              destination
 +
1    REJECT    all  --  0.0.0.0/0            0.0.0.0/0          reject-with icmp-host-prohibited
 +
 
 +
Chain OUTPUT (policy ACCEPT)
 +
num  target    prot opt source              destination
 +
</pre>
 +
 
 +
Notice that line 5 says "REJECT all..." This means your server will reject everything. If you choose to append new rules to the iptables, you will still have no success with the server as the rules are followed in the order they appear in iptables. The commands you would like to run (again as root or sudo) are:
 +
 
 +
<pre>
 +
# iptables -I INPUT 5 -p tcp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT
 +
# iptables -I INPUT 6 -p udp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT
 +
# iptables -I INPUT 7 -p udp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT
 +
# iptables -I INPUT 8 -p udp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT
 +
# iptables -I INPUT 9 -p udp --dport 26901 -m state --state NEW,ESTABLISHED -j ACCEPT
 +
# service iptables save
 +
# service iptables restart
 +
</pre>
 +
 
 +
This will add the new rules above the reject line. If you look at the commands, they have a section that says "-I INPUT 5,6,7,8,9." This is telling what to make the rule number for this entry. Each time you add a new rule, you move the reject line down one, so you increment the rule number.  You can choose to just keep adding the commands all as "-I INPUT 5". and everything will still work, but I like to keep my iptables nice and orderly. call me OCD. If you wanted, you could delete the REJECT LINE (sudo iptables -D INPUT 5) and re-add it later, but you have to get the syntax correct so it is easier to insert them above. The save will keep your iptables for reboot, and you must restart the service so the new rules are recognized.  Your iptables should now look like this:
 +
 
 +
<pre>
 +
Chain INPUT (policy ACCEPT)
 +
num  target    prot opt source              destination
 +
1    ACCEPT    all  --  0.0.0.0/0            0.0.0.0/0          state RELATED,ESTABLISHED
 +
2    ACCEPT    icmp --  0.0.0.0/0            0.0.0.0/0
 +
3    ACCEPT    all  --  0.0.0.0/0            0.0.0.0/0
 +
4    ACCEPT    tcp  --  0.0.0.0/0            0.0.0.0/0          state NEW tcp dpt:22
 +
5    ACCEPT    tcp  --  0.0.0.0/0            0.0.0.0/0          tcp dpt:27015 state NEW,ESTABLISHED
 +
6    ACCEPT    udp  --  0.0.0.0/0            0.0.0.0/0          udp dpt:27015 state NEW,ESTABLISHED
 +
7    ACCEPT    udp  --  0.0.0.0/0            0.0.0.0/0          udp dpt:27005 state NEW,ESTABLISHED
 +
8    ACCEPT    udp  --  0.0.0.0/0            0.0.0.0/0          udp dpt:27020 state NEW,ESTABLISHED
 +
9    ACCEPT    udp  --  0.0.0.0/0            0.0.0.0/0          udp dpt:26901 state NEW,ESTABLISHED
 +
10  REJECT    all  --  0.0.0.0/0            0.0.0.0/0          reject-with icmp-host-prohibited
 +
 
 +
Chain FORWARD (policy ACCEPT)
 +
num  target    prot opt source              destination
 +
1    REJECT    all  --  0.0.0.0/0            0.0.0.0/0          reject-with icmp-host-prohibited
  
==Start the download/update==
+
Chain OUTPUT (policy ACCEPT)
*Run ./update.sh to start the download, may take several hours as dedicated server content is currently 5GB
+
num target    prot opt source              destination
*If however you get a permission denied error, execute this:
+
</pre>
  chmod +x update.sh
+
This should fix your firewall issues.
*Or if you see an error like "Fatal Error: Failed to load libsteam.so" , execute this :
 
chmod -R 777 /directory/to/steam/
 
*You may need to run the file *multiple* times until the message "Success! App '232250' fully installed." displays.
 
  
==Create/Update server files==
+
===Utils===
*Create a file called server.cfg in '~/hlserver/tf2/tf/cfg'
+
====screen====
*Edit the file with these details
+
Many server operators choose to run the server under [http://www.gnu.org/software/screen/ <code>screen</code>] or similar packages (such as <code>tmux</code>), as it allows you to switch between the console and the shell at will, as well as end your SSH session without killing the server. It can be installed via your distribution's package manager. The server can then be run with:
hostname "Your_Servers_Name"
 
rcon_password "Your_Rcon_Password"
 
sv_contact "admin@yourdomain.com"
 
mp_timelimit "30"
 
* Edit the files motd.txt, maplist.txt and mapcycle.txt all found in the '~/hlserver/tf2/tf' folder
 
  
==Create a shell script to run the server==
+
:<code>$ screen -m -S {{botignore|tf2}} ./srcds_run ''parameters''</code>
*Create a file in './hlserver/' called tf.sh
+
 
*Edit the file with this text:
+
Command string example:
#!/bin/sh
+
 
tf2/srcds_run -console -game tf -nohltv +sv_pure 1 +map ctf_2fort +maxplayers 24
+
:<code>$ screen -m -S tf2.MapNameHere -t MapNameHere /home/Username/hlserver/srcds_run -game tf +map MapFileNameHere -maxplayers 32 -autoupdate -steam_dir /home/Username/hlserver/ -steamcmd_script /home/Username/hlserver/tf2_ds.txt +sv_shutdown_timeout_minutes 5 -port 27015 +exec server.cfg +mapcyclefile mapcycle.txt</code>
*Run the file tf.sh to start your server
+
 
*Note: You could create an alias in your ~/.bashrc (or ~/.bash_aliases) file for this command as well.
+
where ''parameters'' is your normal <code>srcds_run</code> parameters. You can use {{key|Ctrl}}+{{key|A}}+{{key|D}} to minimize the console, and <code>screen -r tf2</code> to bring it back up. {{key|Ctrl}}+{{key|D}} will terminate the session (make sure you use the killserver console command first) and {{key|Ctrl}}+{{key|A}}, followed by {{key|Esc}} will allow you to scroll through it using {{key|Up}} and {{key|Down}}. See the [http://www.gnu.org/software/screen/manual/screen.html manual] for more commands and parameters.
=== Other command line options ===
+
 
 +
====Other command line options====
  
 
Some other common command-line options for TF2 are:
 
Some other common command-line options for TF2 are:
  
* <code>+ip 1.2.3.4</code> - Bind to a specific IP. By default, listens on all network interfaces
+
* <code>+ip 0.0.0.0</code> - Bind to a specific IP. By default, listens on all network interfaces
 
* <code>-port 27015</code> - Bind to a different port (27015 is the default)
 
* <code>-port 27015</code> - Bind to a different port (27015 is the default)
 
* <code>-secured</code> - VAC secured
 
* <code>-secured</code> - VAC secured
Line 100: Line 287:
 
* <code>+sv_shutdown_timeout_minutes 360</code> - When autoupdating, automatically restart after this many minutes.  Defaults to 360 (6 hours).
 
* <code>+sv_shutdown_timeout_minutes 360</code> - When autoupdating, automatically restart after this many minutes.  Defaults to 360 (6 hours).
  
=== screen ===
+
===Reboot Persistence===
Many server operators choose to run the server under [http://www.gnu.org/software/screen/ <code>screen</code>], as it allows you to switch between the console and the shell at will, as well as end your SSH session without killing the server. It can be installed via your distribution's package manager. The server can then be run with:
 
  
$ screen -m -S {{botignore|tf2}} ./srcds_run ''parameters''
+
In the event of unexpected power outages, it might be useful to automatically restart your server.
 
 
Command string example:
 
 
$ screen -m -S tf2.MapNameHere -t MapNameHere /home/Username/hlserver/srcds_run -game tf +map MapFileNameHere -maxplayers 32 -autoupdate -steam_dir /home/Username/hlserver/ -steamcmd_script /home/Username/hlserver/tf2_ds.txt +sv_shutdown_timeout_minutes 5 -port 27015 +exec server.cfg +mapcyclefile mapcycle.txt
 
  
where ''parameters'' is your normal <code>srcds_run</code> parameters. You can use {{key|Ctrl}}+{{key|A}}+{{key|D}} to minimize the console, and <code>screen -r tf2</code> to bring it back up. {{key|Ctrl}}+{{key|D}} will terminate the session (make sure you use the killserver console command first) and {{key|Ctrl}}+{{key|A}}, followed by {{key|Esc}} will allow you to scroll through it using {{key|Up}} and {{key|Down}}. See the [http://www.gnu.org/software/screen/manual/screen.html manual] for more commands and parameters.
+
====Using systemd====
  
=== Automated startup at server boot ===
+
For systems that use '''systemd''' instead of '''init scripts''' you need to make a '''systemd service'''
In the event of unexpected power outages, it might be useful to automatically restart your server.
+
Make a file in the /etc/systemd/system/ directory, named tf2server.service and put the following text into it:
===== Systemd service and timer =====
 
For systems that have '''systemd''' instead of init scripts you need to make a '''systemd service'''
 
Make a file at /etc/systemd/system/ called tf2server.service and put the following text into it:
 
 
<pre>
 
<pre>
 
[Unit]
 
[Unit]
 
Description=Team Fortress 2 server
 
Description=Team Fortress 2 server
RefuseManualStart=no
 
RefuseManualStop=yes
 
  
 
[Service]
 
[Service]
Type=oneshot
+
Type=simple
 +
User=gameserver
 
ExecStart=/bin/sh /home/tf2server/hlserver/tf2.sh
 
ExecStart=/bin/sh /home/tf2server/hlserver/tf2.sh
  
Line 129: Line 307:
 
WantedBy=multi-user.target
 
WantedBy=multi-user.target
 
</pre>
 
</pre>
 +
 
This should run the shell script at /home/tf2server/hlserver/tf2 at server boot. You can change '''/home/tf2server/hlserver/tf2.sh''' in the '''ExecStart=/bin/sh /home/tf2server/hlserver/tf2.sh'''
 
This should run the shell script at /home/tf2server/hlserver/tf2 at server boot. You can change '''/home/tf2server/hlserver/tf2.sh''' in the '''ExecStart=/bin/sh /home/tf2server/hlserver/tf2.sh'''
 
line of the tf2server.service to the path your shell script for running the server is. Now only thing left to do is tell systemd to refresh the the *.service files and add the file to the startup:
 
line of the tf2server.service to the path your shell script for running the server is. Now only thing left to do is tell systemd to refresh the the *.service files and add the file to the startup:
  
# systemctl deamon-reload
+
:<code># systemctl daemon-reload</code>
 +
 
 +
:<code># systemctl enable tf2server.service</code>
 +
 
 +
After this, the server should start automatically after the system starts.
  
# systemctl enable tf2server.service
+
====Using init====
  
And you should have the server run at startup.
+
NOTE: Most modern systems should be able to use systemd (see above) rather than a '''system init''' script. Use these instructions only if you are unable/unwilling to use systemd.
  
===== Debian init script =====
 
 
The following example Debian LSB init script can be used to automatically restart the server. Note that  <code>screen</code> is used. This script should be named tf2-server and can be put in the folder /etc/init.d. After doing that, run:
 
The following example Debian LSB init script can be used to automatically restart the server. Note that  <code>screen</code> is used. This script should be named tf2-server and can be put in the folder /etc/init.d. After doing that, run:
  
$ update-rc.d tf2-server defaults
+
:<code>$ update-rc.d tf2-server defaults</code>
  
 
This should ensure a proper startup of the server after each reboot.
 
This should ensure a proper startup of the server after each reboot.
Line 215: Line 397:
 
     ;;
 
     ;;
 
     restart)
 
     restart)
stop
+
        stop
 
         start
 
         start
 
     ;;
 
     ;;
Line 232: Line 414:
 
</pre>
 
</pre>
  
===== Upstart script =====
+
====Using Upstart====
Alternatively, if you'd rather use an upstart script, paste the following into /etc/init/tf2-server.conf
+
 
 +
As above, a systemd script is preferable. But if you'd rather use an upstart script, paste the following into /etc/init/tf2-server.conf
  
 
<pre>
 
<pre>
Line 257: Line 440:
  
 
post-stop script
 
post-stop script
     fuser -k /home/tf2-server/hlserver/tf2/srcds_run  
+
     fuser -k /home/tf2-server/hlserver/tf2/srcds_run
 
     while [ -n "$(pidof srcds_linux)" ]; do
 
     while [ -n "$(pidof srcds_linux)" ]; do
 
         sleep 1
 
         sleep 1
Line 264: Line 447:
 
</pre>
 
</pre>
  
== iptables rules ==
+
==Plugins==
Firstly, run <code>sudo -i</code> to get a root prompt. Then, enter this (all one line). To leave the root prompt and return to the standard user, just type <code>exit</code> like normal.
 
<pre>
 
iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27016 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27017 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27018 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27019 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27016 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27017 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27018 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27019 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT
 
</pre>
 
  
 +
Source mod can be installed for administration features like kick, ban, vote, map change. It is a requirement for most other plugins.
 +
* [https://wiki.alliedmods.net/Metamod:Source Metamod:Source] - Requirement for SourceMod
 +
* [https://wiki.alliedmods.net/SourceMod SourceMod] - Administration environment
 +
* [https://www.sourcemod.net/newstats.php?mod_id=558&addon_id=0 Most installed plugins]
  
===CentOS 6.4 (minimal install)===
+
==Troubleshooting==
on CentOS 6.4 the default iptables rules has a reject line as the last entry. This will cause all traffic to be rejected if you append (as the above commands recommend). To fix this I recommend first running the server to determine what ports it uses:
 
  
<pre>
+
* '''[S_API FAIL] SteamAPI_Init() failed; SteamAPI_IsSteamRunning() failed.'''
netstat -lnptu
+
** Safe to ignore. This is just the Steam code looking for, but not finding the Steam client.
</pre>
 
  
This should output something like this:
+
* '''dlopen failed trying to load: /home/ubuntu/.steam/sdk32/steamclient.so'''
<pre>
+
** TF2 server could not locate 32-bit binary. To fix this, run: <code>$ ln -s ~/hlserver/tf2/bin ~/.steam/sdk32</code>. Doing just <code>$ ln</code> will give you an error on most distributions.
(Not all processes could be identified, non-owned process info
 
will not be shown, you would have to be root to see it all.)
 
Active Internet connections (only servers)
 
Proto Recv-Q Send-Q Local Address              Foreign Address            State      PID/Program name 
 
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                  LISTEN      -                 
 
tcp        0      0 127.0.0.1:25                0.0.0.0:*                  LISTEN      -                 
 
tcp        0      0 0.0.0.0:27015              0.0.0.0:*                  LISTEN      1393/./srcds_linux 
 
tcp        0      0 :::22                      :::*                       LISTEN      -                 
 
tcp        0      0 ::1:25                      :::*                       LISTEN      -                  
 
udp        0      0 0.0.0.0:27020              0.0.0.0:*                              1393/./srcds_linux 
 
udp        0      0 0.0.0.0:26901              0.0.0.0:*                              1393/./srcds_linux 
 
udp        0      0 0.0.0.0:68                  0.0.0.0:*                              -                 
 
udp        0      0 0.0.0.0:27005              0.0.0.0:*                              1393/./srcds_linux 
 
udp        0      0 0.0.0.0:27015              0.0.0.0:*                              1393/./srcds_linux
 
</pre>
 
  
The ports listed with the ./srcds_linux name are being used by your server. In this instance port 27015 is using TCP, and ports 26901, 27005, 27015, and 27020 are using UDP. These ports need to be added to the iptables  rules so that the firewall will not block access to incoming traffic.
+
* '''Could not load: replay_srv.so'''
 +
** Search your package manager for packages named {{code|libtinfo5:i386}}, {{code|libncurses5:i386}}, and {{code|libcurl3-gnutls:i386}}, and install them using <code>sudo apt-get install</code>
 +
** If you're on a Red Hat based distro such as fedora, cent, rocky, alma, make sure you also install ncurses5-compat-libs using <code>sudo yum install ncurses-compat-libs.x86_64 ncurses-compat-libs.i686</code>. This fix also applies to anyone using Amazon Linux hosting through EC2.
  
To add them, first you should find out what is currently in your iptables config. You must do all these commands as root. The best practice is to add your account to the sudoers file so that you are somewhat restricted and access will time out. The choice is yours, su  and login, or sudo
+
* '''Segmentation fault (core dumped)'''
 +
**This means your dedicated server has crashed. To help resolve the issue, add <code>-debug</code> to the tf2/srcds_run file. Doing this will generate a file named ''debug.log'', which contains detailed information about the crash.
  
<pre>
+
* '''My server doesn’t show up in the LAN tab of my client’s server browser OR I cannot access my loadout when playing on this server.'''
sudo iptables -nL --line-numbers
+
** Are you still able to connect using <code>[[vdc:List of TF2 console commands and variables#C|connect <ip-address>]]</code> in the [[Console|Developer Console]]?
</pre>
+
** During startup, does your server report the following:
 +
*** Unable to load Steam support library.
 +
*** This server will operate in LAN mode only.
 +
** When you connect with your client, does the server say the following?
 +
*** NULL ISteamGameServer in ConnectClient. Steam authentication may fail.
 +
*** Cannot verify load for invalid steam ID […]
 +
** If so, then both of these problems have the same solution: Make sure you have a <code>steam_appid.txt</code> file containing the number <code>232250</code> in your directory. See ''[[#Create a shell script to run the server|Running the server]]'' section above.
  
Which should output something like this:
+
* '''My server doesn’t auto-update on startup.'''
 +
** When starting up, does your server say the following? If so, then you need point <code>srcds_run</code> to the location of your SteamCMD binary, using the <code>-steam_dir</code> argument and to your steamcmd update script using the <code>-steamcmd_script</code> argument. See ''[[#Other command line options|Other command line options]]'', above.
 
<pre>
 
<pre>
Chain INPUT (policy ACCEPT)
+
  ERROR: -autoupdate requires -steam_dir and -steamcmd_script.
num  target    prot opt source              destination       
+
  WARNING: Failed to locate steam binary.
1    ACCEPT    all -- 0.0.0.0/0            0.0.0.0/0          state RELATED,ESTABLISHED
+
  WARNING: Could not locate steam binary:, ignoring.
2    ACCEPT    icmp --  0.0.0.0/0            0.0.0.0/0         
 
3    ACCEPT    all --  0.0.0.0/0            0.0.0.0/0         
 
4    ACCEPT    tcp --  0.0.0.0/0            0.0.0.0/0          state NEW tcp dpt:22
 
5    REJECT    all  --  0.0.0.0/0            0.0.0.0/0          reject-with icmp-host-prohibited
 
 
 
Chain FORWARD (policy ACCEPT)
 
num  target    prot opt source              destination       
 
1    REJECT    all  --  0.0.0.0/0            0.0.0.0/0          reject-with icmp-host-prohibited
 
 
 
Chain OUTPUT (policy ACCEPT)
 
num  target    prot opt source              destination 
 
 
</pre>
 
</pre>
  
Notice that line 5 says "REJECT all..." This means your server will reject everything. If you choose to append new rules to the iptables, you will still have no success with the server as the rules are followed in the order they appear in iptables. The commands you would like to run (again as root or sudo) are:
+
* '''My server is stuck at 0/0 during updates'''
 
+
** When an update is running, does the console output the following? If so, remove the "validate" instruction from the update command.
 
<pre>
 
<pre>
sudo iptables -I INPUT 5 -p tcp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT
+
force_install_dir /home/your/server/directory
sudo iptables -I INPUT 6 -p udp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT
+
app_update 232250 validate
sudo iptables -I INPUT 7 -p udp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT
+
Initial App state (0x4) installed
sudo iptables -I INPUT 8 -p udp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT
+
App state (0x4) installed, progress: 0.00 (0 / 0)
sudo iptables -I INPUT 9 -p udp --dport 26901 -m state --state NEW,ESTABLISHED -j ACCEPT
+
Success! App '232250' already up to date.
sudo service iptables save
 
sudo service iptables restart
 
 
</pre>
 
</pre>
  
This will add the new rules above the reject line. If you look at the commands, they have a section that says "-I INPUT 5,6,7,8,9." This is telling what to make the rule number for this entry. Each time you add a new rule, you move the reject line down one, so you increment the rule number.  You can choose to just keep adding the commands all as "-I INPUT 5". and everything will still work, but I like to keep my iptables nice and orderly. call me OCD. If you wanted, you could delete the REJECT LINE (sudo iptables -D INPUT 5) and re-add it later, but you have to get the syntax correct so it is easier to insert them above. The save will keep your iptables for reboot, and you must restart the service so the new rules are recognized. Your iptables should now look like this:
+
* '''My server doesn't work with rcon and/or refuses to broadcast UDP logs'''
 +
** Do you have IPv6 or multiple network interfaces? If so, the server will have an existential crisis when trying to perform these, and you'll need to reassure it by giving it IPs to listen on:
 +
** To do this, include <code>+ip 0.0.0.0</code> on the command-line arguments and add <code>rcon_address 0.0.0.0</code> to your server.cfg
 +
** ''Note: <code>rcon_address</code> is not exclusively used by rcon, UDP logging will fail without it.''
  
 +
* '''steamclient.so error - 64bit'''
 
<pre>
 
<pre>
Chain INPUT (policy ACCEPT)
+
  dlopen failed trying to load:
num target    prot opt source              destination       
+
  ~/.steam/sdk32/steamclient.so
1    ACCEPT    all  -- 0.0.0.0/0            0.0.0.0/0          state RELATED,ESTABLISHED
+
  with error:
2    ACCEPT    icmp --  0.0.0.0/0            0.0.0.0/0         
+
  ~/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory
3    ACCEPT    all  --  0.0.0.0/0            0.0.0.0/0         
 
4    ACCEPT    tcp --  0.0.0.0/0            0.0.0.0/0          state NEW tcp dpt:22
 
5    ACCEPT    tcp  --  0.0.0.0/0            0.0.0.0/0          tcp dpt:27015 state NEW,ESTABLISHED
 
6    ACCEPT    udp  --  0.0.0.0/0            0.0.0.0/0          udp dpt:27015 state NEW,ESTABLISHED
 
7    ACCEPT    udp  -- 0.0.0.0/0            0.0.0.0/0          udp dpt:27005 state NEW,ESTABLISHED
 
8    ACCEPT    udp  --  0.0.0.0/0            0.0.0.0/0          udp dpt:27020 state NEW,ESTABLISHED
 
9    ACCEPT    udp  --  0.0.0.0/0            0.0.0.0/0          udp dpt:26901 state NEW,ESTABLISHED
 
10  REJECT    all  --  0.0.0.0/0            0.0.0.0/0          reject-with icmp-host-prohibited
 
 
 
Chain FORWARD (policy ACCEPT)
 
num  target    prot opt source              destination       
 
1    REJECT    all  --  0.0.0.0/0            0.0.0.0/0          reject-with icmp-host-prohibited
 
 
 
Chain OUTPUT (policy ACCEPT)
 
num  target    prot opt source              destination
 
 
</pre>
 
</pre>
This should fix your firewall issues.
+
:* Safe to ignore. This is just the Steam code looking for, but not finding the Steam client. If you want to fix it use: <code>cp ~/hlserver/linux32/steamclient.so ~/.steam/sdk32/</code>
  
 +
* '''Could not load replay_srv.so'''
 +
** Install packages named <code>mailutils</code>, <code>lib32gcc1</code>, <code>libstdc++6</code>, <code>libstdc++6:i386</code>, and <code>libcurl4-gnutls-dev:i386</code> using apt, apititute or yum.
  
 +
* '''Server fails to start with ./srcds_run line 324 18491 Segmentation fault $HL_CMD'''
 +
** Run the following 2 commands:
 +
** <code>yum install libcurl.i686</code>
 +
** <code>ln -s /usr/lib/libcurl.so.4 /usr/lib/libcurl-gnutls.so.4</code>
  
== Troubleshooting ==
+
* ''' Assertion error when logging in via SteamCMD or SteamCMD says to check the connection.'''
; My server doesn’t show up in the LAN tab of my client’s server browser.
+
** If this error occurs on Arch Linux, you may need to run the following command. This may work on other distributions of Linux.
; I cannot access my loadout when playing on this server.
+
:<code>sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf</code>
: Are you still able to connect using <code>[https://developer.valvesoftware.com/wiki/List_of_TF2_console_commands_and_variables#C connect <ip-address>]</code> in the [https://developer.valvesoftware.com/wiki/Console Developer Console]?
+
:* After running the command, restart the machine to ensure that the changes are applied. This error occurs when the resolv.conf isn't configured.
: During startup, does your server report the following?
 
* Unable to load Steam support library.*
 
* This server will operate in LAN mode only.*
 
: When you connect with your client, does the server say the following?
 
NULL ISteamGameServer in ConnectClient. Steam authentication may fail.
 
 
Cannot verify load for invalid steam ID […]
 
: If so, then both of these problems have the same solution: Make sure you have a <code>steam_appid.txt</code> file containing the number <code>440</code> in your <code>orange box</code> folder. See ''[[#Running the server|Running the server]]'', above.
 
 
 
; My server doesn’t auto-update on startup.
 
: When starting up, does your server say the following?
 
ERROR: -autoupdate requires -steam_dir and -steamcmd_script.
 
WARNING: Failed to locate steam binary.
 
WARNING: Could not locate steam binary:, ignoring.
 
: If so, then you need point <code>srcds_run</code> to the location of your SteamCMD binary, using the <code>-steam_dir</code> argument and to your steamcmd update script using the <code>-steamcmd_script</code> argument. See ''[[#Other command line options|Other command line options]]'', above.
 
 
 
; My server is stuck at 0/0 during updates
 
: When an update is running, does the console output the following?
 
force_install_dir /home/your/server/directory
 
app_update 232250 validate
 
Initial App state (0x4) installed
 
App state (0x4) installed, progress: 0.00 (0 / 0)
 
Success! App '232250' already up to date.
 
: If so, remove the "validate" instruction from the update command.
 
 
 
  
; My server doesn't work with rcon and/or refuses to broadcast UDP logs
+
* '''SteamCMD still says to check the connection.'''
: Do you have IPv6 or multiple network interfaces? If so, the server will have an existential crisis when trying to perform these, and you'll need to reassure it by giving it IPs to listen on:
+
** Another method of solving this issue is modfying the hosts file. Only do this method if the solution above doesn't work. This solution may work on other distributions of Linux. However, this solution has only been tested on Arch Linux.
: To do this, include <code>+ip 0.0.0.0</code> on the command-line arguments and add <code>rcon_address 0.0.0.0</code> to your server.cfg
+
** For Arch system users may need to run the following:
: ''Note: <code>rcon_address</code> is not exclusively used by rcon, UDP logging will fail without it.''
+
:* <code>ping media.steampowered.com</code>
 +
:* <code>nano /etc/hosts</code>
 +
:* add to the hosts file: <code><IP shown in ping> media.steampowered.com</code>
  
 
== See also ==
 
== See also ==
 
* [[Windows dedicated server]]
 
* [[Windows dedicated server]]
 
* [[Dedicated server configuration]]
 
* [[Dedicated server configuration]]
* [https://github.com/autotune/chef-repo/tree/master/cookbooks/tf2server Chef Recipe] 
 
  
[[Category: Servers]]
+
[[Category:Servers]]

Latest revision as of 22:08, 19 November 2024

This is a setup guide that walks you through the installation process of a basic Team Fortress 2 dedicated server on GNU/Linux (x86 or amd64) or a FreeBSD (x86 or amd64) system with Linux compatibility patches running in its kernel. In the example below, the server is installed into the user's home directory in a directory called hlserver.

Basic installation and configuration of a dedicated server is almost the same on most Linux distributions, but small details, such as package names and directories may differ from distribution to distribution. It is recommended that you check your package manager's repositories for the required packages before continuing.

Note: information about running a server on Windows is often applicable on Linux, for example, files like server.cfg and motd_default.txt are identical between platforms. Check that page for additional details and suggestions. Information on that page and this one may also be useful on other Unix-like platforms.

Reading this article

This article has been written according to standard Linux terminal documentation syntax, meaning the following:

  • A command prefixed by # (a hashtag) is meant to be run as root. Most distributions have a separate root account; for other distributions such as Ubuntu, Linux Mint and Crunchbang, prepending sudo to a command will ensure that the command is run as root. An alternative would be to use the su command to make all following commands run as root, although this is not recommended.
  • A command prefixed by $ (a dollar sign) is meant to be run as a regular user without root permissions.
  • ./ means current working directory, the directory in which commands entered into the terminal will be executed.

Docker

If your server is running Docker, you can simply use:

docker run -d --net=host --name=tf2-dedicated -e SRCDS_TOKEN={YOURTOKEN} -it cm2network/tf2

SRCDS_TOKEN is required to be listed; https://steamcommunity.com/dev/managegameservers

The container will automatically update the game on startup, so if there is a game update just restart the container.

The config is located here: /home/steam/tf2-dedicated/tf/cfg

If you want to launch another instance you can increment the environment variables, using -e (--env):

docker run -d --net=host -e SRCDS_PORT=27016 -e SRCDS_TV_PORT=27021 -e SRCDS_TOKEN={YOURTOKEN} -it --name=tf2-dedicated2 cm2network/tf2

SRCDS_TOKEN is required to be listed; https://steamcommunity.com/dev/managegameservers

You can find the associated Docker Hub page here: https://hub.docker.com/r/cm2network/tf2/

Step by step

Requirements

A number of requirements exist in order to run a Team Fortress 2 dedicated server on the GNU/Linux platform, namely:

  • Write-access to the current working directory
  • A version of glibc equal to or newer than 2.3.6.
  • Approximately 8GB of free hard-drive space (for a barebones server with no custom maps, sounds, etc).
  • If you are following this tutorial on a FreeBSD system, then most of the commands shown here are still applicable, but you must enable Linux compatibility in the kernel and install a base system via the ports collection. Instructions to get you started are located here. WARNING: This guide is outdated. Consider consulting the FreeBSD Handbook or other more recent sources of information.
  • In the case of a 64-bit distribution, the package named lib32gcc1 or ia32-libs is required to be installed:
On 64-bit CentOS or Fedora run:
# yum install ncompress libgcc.x86_64 libgcc.i686 glibc.i686 zlib.i686 ncurses-libs.i686
On Fedora, also do:
# dnf install libstdc++.i686 ncurses-compat-libs.i686 libcurl.i686
On 64-bit Debian/Ubuntu/Linux Mint run:
$ sudo dpkg --add-architecture i386
$ sudo apt-get update
$ sudo apt-get install lib32z1 libncurses5:i386 libbz2-1.0:i386 lib32gcc-s1 lib32stdc++6 libtinfo5:i386 libcurl3-gnutls:i386 libsdl2-2.0-0:i386
For x86_64 Arch Linux run:
# pacman -Syy lib32-gcc-libs lib32-libcurl-gnutls
(you need to have multilib repositories enabled)
For terminal support on x64 Arch Linux, install lib32-ncurses5-compat-libs from the Arch user repository.

You may also need to install other packages in their 32-bit forms (eg libcurl4-gnutls).

Download and install the SteamCMD Tool

It is recommended you create a separate user (such as "gameserver") to install and run game servers.

  • Create a user named "gameserver"

# useradd --create-home gameserver

  • As the "gameserver" user, create a directory in which SteamCMD will be installed, eg '~/hlserver':

$ mkdir ~/hlserver

  • Change the current working directory to hlserver:

$ cd ~/hlserver

  • Download steamcmd_linux.tar.gz :

$ wget https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz

  • Use the tar command to uncompress the archive into the working directory:

tar zxf steamcmd_linux.tar.gz

  • On Fedora, you also need to do:
$ mkdir -p ~/.steam/sdk32
$ ln -s ~/hlserver/linux32/steamclient.so ~/.steam/sdk32/
# ln -s /usr/lib/libcurl.so.4 /usr/lib/libcurl-gnutls.so.4

Download the Server

  • Use this command to download the latest server:
./steamcmd.sh +force_install_dir ./tf2 +login anonymous +app_update 232250 +quit
  • If you want to opt-in to the pre-release version of the TF2 dedicated server, add the following line:

-beta prerelease

  • You can update the server in the future by executing this command again.
  • If you receive the error "Error! App '232250' state is 0x202 after update job."
» You do not have enough available disk space.
  • If you get the error saying /something/linux32/steamcmd - No such file or directory
» You did not install the requirements listed above.

Creating/Updating server configuration files

  • Change the current working directory to ~/hlserver/tf2/tf/cfg:

$ cd ~/hlserver/tf2/tf/cfg

  • Create a file named server.cfg:

$ nano server.cfg

hostname "Your_Server's_Name"
rcon_password "Your_Rcon_Password"
sv_contact "admin@yourdomain.com"
mp_timelimit "30"
  • Edit the files motd.txt, maplist.txt (?), and mapcycle.txt, all found in the '~/hlserver/tf2/tf' folder.

Create a shell script to run the server

  • Create a file tf2.sh in './hlserver/tf2' with the following contents, replacing [STEAMTOKEN] with your token:
#!/bin/sh
cd /home/gameserver/hlserver/tf2 || exit 1
exec ./srcds_run -console -game tf +sv_pure 1 +randommap +maxplayers 24 +sv_setsteamaccount [STEAMTOKEN]

# chmod u+x tf2.sh

  • Run ./tf2.sh to launch the server:

$ ./tf2.sh

Ports

  • Ports used by TF2 & those that need to be opened on your server to allow connection from users outside your local network. See below section on setting up port forwarding.
    • UDP 27015 - Main connection port (MUST). This is the port and protocol used by the server browser, allows clients to connect.
    • TCP 27015 - This port is used for RCON such as with SourceBans (if needed).
    • UDP 27020 - SourceTV (if enabled). You can disable this port by adding "-nohltv" to the start up command.
    • UDP 27005 (Optional) - This is an outgoing connection used by clients. Typically you would not need to open this port in your firewall because this is for OUTBOUND connections.
  • if you are using AWS EC2, open at least the main inbound port UDP 27015 src 0.0.0.0/0, and add as other ports as needed.
  • To see ports used by TF2 and user connecting: $ netstat -a |egrep 270

UFW

If UFW is installed you can use the following commands:

ufw allow 27015
ufw allow 27020/udp

IPTables

Firstly, run sudo -i to get a root prompt. Then, enter this (all one line). To leave the root prompt and return to the standard user, just type exit like normal.

iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27016 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27017 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27018 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27019 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p tcp -m tcp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27016 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27017 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27018 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27019 -m state --state NEW,ESTABLISHED -j ACCEPT && iptables -A INPUT -i venet0 -p udp -m udp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT

Or, equivalently:

for port in 27005 {27015..27020}; do for proto in udp tcp; do iptables -A INPUT -i venet0 -p $proto -m $proto --dport $port -m state --state NEW,ESTABLISHED -j ACCEPT; done done
CentOS 6.4 (minimal install)

on CentOS 6.4 the default IPTables rules has a reject line as the last entry. This will cause all traffic to be rejected if you append (as the above commands recommend). To fix this I recommend first running the server to determine what ports it uses:

netstat -lnptu

This should output something like this:

(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address               Foreign Address             State       PID/Program name
tcp        0      0 0.0.0.0:22                  0.0.0.0:*                   LISTEN      -
tcp        0      0 127.0.0.1:25                0.0.0.0:*                   LISTEN      -
tcp        0      0 0.0.0.0:27015               0.0.0.0:*                   LISTEN      1393/./srcds_linux
tcp        0      0 :::22                       :::*                        LISTEN      -
tcp        0      0 ::1:25                      :::*                        LISTEN      -
udp        0      0 0.0.0.0:27020               0.0.0.0:*                               1393/./srcds_linux
udp        0      0 0.0.0.0:26901               0.0.0.0:*                               1393/./srcds_linux
udp        0      0 0.0.0.0:68                  0.0.0.0:*                               -
udp        0      0 0.0.0.0:27005               0.0.0.0:*                               1393/./srcds_linux
udp        0      0 0.0.0.0:27015               0.0.0.0:*                               1393/./srcds_linux

The ports listed with the ./srcds_linux name are being used by your server. In this instance port 27015 is using TCP, and ports 26901, 27005, 27015, and 27020 are using UDP. These ports need to be added to the iptables rules so that the firewall will not block access to incoming traffic.

To add them, first you should find out what is currently in your iptables config. You must do all these commands as root. The most secure method of doing this is prepending sudo to each command.

# iptables -nL --line-numbers

Which should output something like this:

Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
2    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
5    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
1    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

Notice that line 5 says "REJECT all..." This means your server will reject everything. If you choose to append new rules to the iptables, you will still have no success with the server as the rules are followed in the order they appear in iptables. The commands you would like to run (again as root or sudo) are:

# iptables -I INPUT 5 -p tcp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -I INPUT 6 -p udp --dport 27015 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -I INPUT 7 -p udp --dport 27005 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -I INPUT 8 -p udp --dport 27020 -m state --state NEW,ESTABLISHED -j ACCEPT
# iptables -I INPUT 9 -p udp --dport 26901 -m state --state NEW,ESTABLISHED -j ACCEPT
# service iptables save
# service iptables restart

This will add the new rules above the reject line. If you look at the commands, they have a section that says "-I INPUT 5,6,7,8,9." This is telling what to make the rule number for this entry. Each time you add a new rule, you move the reject line down one, so you increment the rule number. You can choose to just keep adding the commands all as "-I INPUT 5". and everything will still work, but I like to keep my iptables nice and orderly. call me OCD. If you wanted, you could delete the REJECT LINE (sudo iptables -D INPUT 5) and re-add it later, but you have to get the syntax correct so it is easier to insert them above. The save will keep your iptables for reboot, and you must restart the service so the new rules are recognized. Your iptables should now look like this:

Chain INPUT (policy ACCEPT)
num  target     prot opt source               destination
1    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           state RELATED,ESTABLISHED
2    ACCEPT     icmp --  0.0.0.0/0            0.0.0.0/0
3    ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0
4    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           state NEW tcp dpt:22
5    ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0           tcp dpt:27015 state NEW,ESTABLISHED
6    ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0           udp dpt:27015 state NEW,ESTABLISHED
7    ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0           udp dpt:27005 state NEW,ESTABLISHED
8    ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0           udp dpt:27020 state NEW,ESTABLISHED
9    ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0           udp dpt:26901 state NEW,ESTABLISHED
10   REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT)
num  target     prot opt source               destination
1    REJECT     all  --  0.0.0.0/0            0.0.0.0/0           reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT)
num  target     prot opt source               destination

This should fix your firewall issues.

Utils

screen

Many server operators choose to run the server under screen or similar packages (such as tmux), as it allows you to switch between the console and the shell at will, as well as end your SSH session without killing the server. It can be installed via your distribution's package manager. The server can then be run with:

$ screen -m -S tf2 ./srcds_run parameters

Command string example:

$ screen -m -S tf2.MapNameHere -t MapNameHere /home/Username/hlserver/srcds_run -game tf +map MapFileNameHere -maxplayers 32 -autoupdate -steam_dir /home/Username/hlserver/ -steamcmd_script /home/Username/hlserver/tf2_ds.txt +sv_shutdown_timeout_minutes 5 -port 27015 +exec server.cfg +mapcyclefile mapcycle.txt

where parameters is your normal srcds_run parameters. You can use Ctrl+A+D to minimize the console, and screen -r tf2 to bring it back up. Ctrl+D will terminate the session (make sure you use the killserver console command first) and Ctrl+A, followed by Esc will allow you to scroll through it using and . See the manual for more commands and parameters.

Other command line options

Some other common command-line options for TF2 are:

  • +ip 0.0.0.0 - Bind to a specific IP. By default, listens on all network interfaces
  • -port 27015 - Bind to a different port (27015 is the default)
  • -secured - VAC secured
  • -timeout 0 - Faster server restart on crash
  • -strictportbind - If a server is already running on the specified port, stop the server from running
  • +randommap - Use instead of +map to select a map at random
  • +servercfgfile - Which tf/cfg/ file to execute on map change, defaults to server.cfg
  • +mapcyclefile - Which tf/cfg/ file contains this server's mapcycle, defaults to mapcycle.txt. Will also look in tf/
  • -replay - Executes replay.cfg and adds an additional slot for the replay bot, but removes it from the player count.
  • -autoupdate - Attempts to auto-update the server when an update comes out. You MUST use -steam_dir and -steamcmd_script
  • -steam_dir ~/hlserver/ - Location of steamcmd. Required by -autoupdate
  • -steamcmd_script ~/hlserver/tf2_ds.txt - SteamCMD script to update this server. Required by -autoupdate
  • +sv_shutdown_timeout_minutes 360 - When autoupdating, automatically restart after this many minutes. Defaults to 360 (6 hours).

Reboot Persistence

In the event of unexpected power outages, it might be useful to automatically restart your server.

Using systemd

For systems that use systemd instead of init scripts you need to make a systemd service Make a file in the /etc/systemd/system/ directory, named tf2server.service and put the following text into it:

[Unit]
Description=Team Fortress 2 server

[Service]
Type=simple
User=gameserver
ExecStart=/bin/sh /home/tf2server/hlserver/tf2.sh

[Install]
WantedBy=multi-user.target

This should run the shell script at /home/tf2server/hlserver/tf2 at server boot. You can change /home/tf2server/hlserver/tf2.sh in the ExecStart=/bin/sh /home/tf2server/hlserver/tf2.sh line of the tf2server.service to the path your shell script for running the server is. Now only thing left to do is tell systemd to refresh the the *.service files and add the file to the startup:

# systemctl daemon-reload
# systemctl enable tf2server.service

After this, the server should start automatically after the system starts.

Using init

NOTE: Most modern systems should be able to use systemd (see above) rather than a system init script. Use these instructions only if you are unable/unwilling to use systemd.

The following example Debian LSB init script can be used to automatically restart the server. Note that screen is used. This script should be named tf2-server and can be put in the folder /etc/init.d. After doing that, run:

$ update-rc.d tf2-server defaults

This should ensure a proper startup of the server after each reboot.

#!/bin/sh

### BEGIN INIT INFO
# Provides:          tf2server
# Required-Start:    $remote_fs
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Team Fortress 2 server
# Description:       Starts a Team Fortress 2 server
### END INIT INFO

NAME="Team Fortress 2"
USER="tf2server"
SCREENREF="tf2"
BINARYPATH="/home/tf2server/hlserver/tf2"
BINARYNAME="srcds_run"
PIDFILE="tf2server.pid"

OPTS="-game tf +sv_pure 1 +maxplayers 32 +ip 0.0.0.0 +map mvm_decoy -autoupdate -steam_dir /home/tf2server/hlserver/ -steamcmd_script /home/tf2server/hlserver/tf2_ds.txt +sv_shutdown_timeout_minutes 5"

cd "$BINARYPATH"

running() {
    if [ -n "`pgrep -f $BINARYNAME`" ]; then
        return 0
    else
        return 1
    fi
}

start() {
    if ! running; then
        echo -n "Starting the $NAME server... "
        start-stop-daemon --start --chuid $USER --user $USER --chdir $BINARYPATH --exec "/usr/bin/screen" -- -dmS $SCREENREF $BINARYPATH/$BINARYNAME $OPTS
        pgrep -f $BINARYNAME > $PIDFILE
        if [ -s $PIDFILE ]; then
            echo "Done"
        else
            echo "Failed"
            rm $PIDFILE
        fi
    else
        echo "The $NAME server is already started."
    fi
}

stop() {
    if running; then
        echo -n "Stopping the $NAME server... "
        kill `cat $PIDFILE`
        while running; do
            sleep 1
        done
        rm $PIDFILE
        echo "Done"
    else
        echo "The $NAME server is already stopped."
    fi
}

case "$1" in
    start)
        start
    ;;
    stop)
        stop
    ;;
    restart)
        stop
        start
    ;;
    status)
        if running; then
            echo "The $NAME server is started."
        else
            echo "The $NAME server is stopped."
        fi
    ;;
    *)
        echo "Usage: $0 (start|stop|restart|status)"
        exit 1
esac
exit 0

Using Upstart

As above, a systemd script is preferable. But if you'd rather use an upstart script, paste the following into /etc/init/tf2-server.conf

description     "TF2 Server"
author          "TF2 Wiki"

start on runlevel [2345]
stop on starting rc RUNLEVEL=[016]

pre-start script
    cd /home/tf2-server/hlserver
    su -c "screen -dmS tf2 ./srcds_run -game tf +sv_pure 1 +maxplayers 32 +ip 0.0.0.0 +map mvm_decoy -autoupdate -steam_dir /home/tf2-server/hlserver/ -steamcmd_script /home/tf2-server/hlserver/tf2_ds.txt +sv_shutdown_timeout_minutes 5" tf2server
    while [ -z "$(pidof srcds_linux)" ]; do
        sleep 1
    done
end script

script
    while [ -n "$(pidof srcds_linux)" ]; do
        sleep 1
    done
end script

post-stop script
    fuser -k /home/tf2-server/hlserver/tf2/srcds_run
    while [ -n "$(pidof srcds_linux)" ]; do
        sleep 1
    done
end script

Plugins

Source mod can be installed for administration features like kick, ban, vote, map change. It is a requirement for most other plugins.

Troubleshooting

  • [S_API FAIL] SteamAPI_Init() failed; SteamAPI_IsSteamRunning() failed.
    • Safe to ignore. This is just the Steam code looking for, but not finding the Steam client.
  • dlopen failed trying to load: /home/ubuntu/.steam/sdk32/steamclient.so
    • TF2 server could not locate 32-bit binary. To fix this, run: $ ln -s ~/hlserver/tf2/bin ~/.steam/sdk32. Doing just $ ln will give you an error on most distributions.
  • Could not load: replay_srv.so
    • Search your package manager for packages named libtinfo5:i386, libncurses5:i386, and libcurl3-gnutls:i386, and install them using sudo apt-get install
    • If you're on a Red Hat based distro such as fedora, cent, rocky, alma, make sure you also install ncurses5-compat-libs using sudo yum install ncurses-compat-libs.x86_64 ncurses-compat-libs.i686. This fix also applies to anyone using Amazon Linux hosting through EC2.
  • Segmentation fault (core dumped)
    • This means your dedicated server has crashed. To help resolve the issue, add -debug to the tf2/srcds_run file. Doing this will generate a file named debug.log, which contains detailed information about the crash.
  • My server doesn’t show up in the LAN tab of my client’s server browser OR I cannot access my loadout when playing on this server.
    • Are you still able to connect using connect <ip-address> in the Developer Console?
    • During startup, does your server report the following:
      • Unable to load Steam support library.
      • This server will operate in LAN mode only.
    • When you connect with your client, does the server say the following?
      • NULL ISteamGameServer in ConnectClient. Steam authentication may fail.
      • Cannot verify load for invalid steam ID […]
    • If so, then both of these problems have the same solution: Make sure you have a steam_appid.txt file containing the number 232250 in your directory. See Running the server section above.
  • My server doesn’t auto-update on startup.
    • When starting up, does your server say the following? If so, then you need point srcds_run to the location of your SteamCMD binary, using the -steam_dir argument and to your steamcmd update script using the -steamcmd_script argument. See Other command line options, above.
 ERROR: -autoupdate requires -steam_dir and -steamcmd_script.
 WARNING: Failed to locate steam binary.
 WARNING: Could not locate steam binary:, ignoring.
  • My server is stuck at 0/0 during updates
    • When an update is running, does the console output the following? If so, remove the "validate" instruction from the update command.
 force_install_dir /home/your/server/directory
 app_update 232250 validate
 Initial App state (0x4) installed
 App state (0x4) installed, progress: 0.00 (0 / 0)
 Success! App '232250' already up to date.
  • My server doesn't work with rcon and/or refuses to broadcast UDP logs
    • Do you have IPv6 or multiple network interfaces? If so, the server will have an existential crisis when trying to perform these, and you'll need to reassure it by giving it IPs to listen on:
    • To do this, include +ip 0.0.0.0 on the command-line arguments and add rcon_address 0.0.0.0 to your server.cfg
    • Note: rcon_address is not exclusively used by rcon, UDP logging will fail without it.
  • steamclient.so error - 64bit
 dlopen failed trying to load:
 ~/.steam/sdk32/steamclient.so
 with error:
 ~/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory
  • Safe to ignore. This is just the Steam code looking for, but not finding the Steam client. If you want to fix it use: cp ~/hlserver/linux32/steamclient.so ~/.steam/sdk32/
  • Could not load replay_srv.so
    • Install packages named mailutils, lib32gcc1, libstdc++6, libstdc++6:i386, and libcurl4-gnutls-dev:i386 using apt, apititute or yum.
  • Server fails to start with ./srcds_run line 324 18491 Segmentation fault $HL_CMD
    • Run the following 2 commands:
    • yum install libcurl.i686
    • ln -s /usr/lib/libcurl.so.4 /usr/lib/libcurl-gnutls.so.4
  • Assertion error when logging in via SteamCMD or SteamCMD says to check the connection.
    • If this error occurs on Arch Linux, you may need to run the following command. This may work on other distributions of Linux.
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
  • After running the command, restart the machine to ensure that the changes are applied. This error occurs when the resolv.conf isn't configured.
  • SteamCMD still says to check the connection.
    • Another method of solving this issue is modfying the hosts file. Only do this method if the solution above doesn't work. This solution may work on other distributions of Linux. However, this solution has only been tested on Arch Linux.
    • For Arch system users may need to run the following:
  • ping media.steampowered.com
  • nano /etc/hosts
  • add to the hosts file: <IP shown in ping> media.steampowered.com

See also