Use case · Game server

TF2 dedicated server on bare metal: SteamCMD, token, srcds_run, firewall

A TF2 dedicated server on Linux is SteamCMD app 232250, fetched with login anonymous and started as srcds_run -game tf with a map and a player count, listening on port 27015. Below: the 32-bit libraries, a Steam login token for app 440 kept out of your shell history, server.cfg and mapcycle, the firewall, and a systemd unit that updates the game before each start. It assumes a whole x86 game server machine with root.

See the machines

Hardware: what srcds asks for

Not much. The Valve Developer Community (VDC) has no TF2-specific sizing; its generic Source Dedicated Server page puts the floor at 512 MB of memory, says 1 GB carries more than 60 player slots, and advises 4 GB or more on current operating systems. The Official TF2 Wiki's Linux guide adds about 8 GB of free disk. Treat these as minimums, not a plan.

ResourceSourceConsequence
CPU architectureTF2 Wiki: the guide covers GNU/Linux on x86 or x86_64, with 32-bit compatibility libraries on 64-bit systemsAn x86-64 machine with the lib32 packages
MemoryVDC SRCDS page: 512 MB minimum, 1 GB for 60+ slots, 4 GB+ advised on newer systemsSpare memory goes to a second instance
DiskTF2 Wiki: about 8 GB freeCheck the drive size of the build you pick
NetworkVDC: upload is what a server spends; 27015 must accept unsolicited inbound trafficA public IPv4 with nothing translating it

Player count is a launch setting, not a hardware one. VDC's maxplayers page lists 101 for Team Fortress 2, but 33 on 32-bit unless the server starts with -unrestricted_maxplayers, and its command-line page calls that flag unsupported and not recommended because of stability problems at the top. The unit below uses 24, the figure in the TF2 Wiki's example.

The machine to put it on

Take an x86 blade or rack server from the game server range, near where your players are. It is the whole machine (all cores, all memory, root) with no hypervisor under srcds. Each comes with an unmetered port and one IPv4 address; the port is 1 Gbps on 10 of our 18 configurable lines and 500 Mbps on the other 8, and nothing counts the traffic.

  • Cities: Bucharest, New York, Amsterdam, San Francisco and Miami, all on AS19624, our own network. Each city has a test address on the locations page; ping it from where your players are.
  • Console: rack servers and blades each carry an out-of-band controller (iLO on HPE machines, iDRAC on Dell, a BMC on Supermicro) with a browser console, power control and virtual media, published in the dashboard when a console login has been added.
  • Lead time: about 30 minutes from order approval to a live machine when it is already racked; a build to order takes 4-24 hours.
  • OS: Ubuntu installs in one click; the commands below assume it. More on the Linux servers page.

Leave the ARM machines out of this. That is our inference, not a Valve statement: the TF2 Wiki describes the server on x86 and x86_64 only and VDC documents 32-bit x86 libraries, so arm64 is outside anything either source covers. The X-Gene cartridge also boots only Ubuntu 16.04 or 18.04.

Install: libraries, user, firewall, SteamCMD

Everything runs as an unprivileged steam account: VDC's SteamCMD page warns against running it as root. The firewall is up before any game port exists. Put the address you will run RCON from in place of 203.0.113.10.

# root: 32-bit libraries, service user, firewall (IPv6 first)
sudo apt-get update
sudo apt-get install -y lib32gcc-s1 lib32stdc++6 curl
sudo useradd -m -s /bin/bash steam
sudo sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw
sudo ufw allow OpenSSH
sudo ufw --force enable
sudo ufw allow 27015/udp
sudo ufw allow from 203.0.113.10 to any port 27015 proto tcp

# steam user: SteamCMD, then app 232250 with an anonymous login
sudo -u steam bash -c 'mkdir -p /home/steam/Steam && cd /home/steam/Steam && curl -sqL "https://client-update.steamstatic.com/installer/steamcmd_linux.tar.gz" | tar zxf -'
sudo -u steam bash -c 'cd /home/steam/Steam && ./steamcmd.sh +force_install_dir /home/steam/tf2 +login anonymous +app_update 232250 validate +quit'
sudo -u steam bash -c 'mkdir -p /home/steam/.steam/sdk32 && ln -sf /home/steam/Steam/linux32/steamclient.so /home/steam/.steam/sdk32/steamclient.so'
  • lib32gcc-s1 is the dependency VDC gives for SteamCMD on 64-bit Debian and Ubuntu, and lib32stdc++6 its fix for a missing 32-bit libstdc++. The TF2 Wiki lists more 32-bit packages and notes that recent releases no longer ship some of them (libtinfo5:i386, libncurses5:i386); add a package only when srcds names the library it is missing.
  • 232250 is "Team Fortress 2 Dedicated Server" on VDC's Dedicated Servers List, Linux section, marked for anonymous login.
  • VDC says to put force_install_dir before the login, as here.
  • The last line is VDC's fix for the "unable to locate a running instance of Steam" message; the TF2 Wiki gives the same advice for a missing steamclient.so.

The login token and app 440

Valve's name for it is GSLT, short for Game Server Login Token. With one, the server logs in to a persistent Steam game server account rather than an anonymous one. VDC's TF2 cvar list describes sv_setsteamaccount as setting that token, and its Source Dedicated Server page treats it as a startup parameter: a log entry with result 18 or 106 means regenerate the token or make a new one and put it there.

How strict is TF2 about it? Valve's own pages state no TF2 rule. The Linux guide on the Official TF2 Wiki is firmer: without a valid token, it says, the server is not listed in the browser. Our reading, which neither Valve nor the TF2 Wiki states, is that a server without one still takes players who connect by address. A public server should have a token either way.

  1. Sign in at steamcommunity.com/dev/managegameservers. Valve's conditions: the account owns the game, holds a qualifying registered phone, and is neither limited nor community banned or locked. VDC records the game as free since June 2011; our reading is that adding it to your library meets the ownership rule.
  2. Create the token for app ID 440. That is the game itself on Steam (VDC's Team Fortress 2 page); 232250 is only the server download.
  3. Create the token file empty and private first: sudo install -d -m 700 /etc/tf2, then sudo install -m 600 /dev/null /etc/tf2/gslt.env. Open it with sudo nano /etc/tf2/gslt.env and add the single GSLT= line shown in the next block.

Valve's page carries the rest of the token's rules: it is yours alone and must not be handed to third parties, a token the server never uses for a long time expires and can be regenerated there, and resetting your Steam password regenerates every token you hold.

server.cfg, the map rotation and RCON

The game folder is tf, so configuration lives in /home/steam/tf2/tf/cfg/. VDC's CFG page says server.cfg runs when the dedicated server starts and again on every map change. Create it locked before you type a password into it: sudo install -m 600 -o steam -g steam /dev/null /home/steam/tf2/tf/cfg/server.cfg, then edit it with sudo -u steam nano /home/steam/tf2/tf/cfg/server.cfg.

# /etc/tf2/gslt.env   (root:root, mode 600)
GSLT=token-from-the-steam-game-server-page

# /home/steam/tf2/tf/cfg/server.cfg   (steam:steam, mode 600)
hostname "Payload and CTF | 24 slots"
rcon_password "a-long-random-string"
sv_password ""
sv_lan 0
sv_rcon_maxfailures 5
mapcyclefile "mapcycle_live.txt"

# /home/steam/tf2/tf/cfg/mapcycle_live.txt
ctf_2fort
pl_badwater
cp_dustbowl
cp_granary
  • hostname: what the server browser lists. VDC caps it at 64 characters and wants quotes around anything with spaces.
  • rcon_password: the remote console password. It stays in this file only; on a launch line it would show to every local user in ps and land in shell history.
  • sv_password: empty means anyone can join; put a word in it and players need that password to connect.
  • sv_lan 0: VDC describes a LAN server as having no heartbeat and no authentication. An internet server needs 0.
  • sv_rcon_maxfailures: how many failed RCON logins earn a ban; VDC lists a default of 10 and a range of 1-20.
  • mapcyclefile: the rotation file. VDC's SteamCMD page warns that validate resets a customised mapcycle.txt to the server default but leaves files that are not part of the install alone, so the rotation goes in a file of your own name. One map per line, the .bsp name without its extension.

Running it under systemd

VDC's generic launch is srcds_run with -game, +map and +maxplayers; the TF2 Wiki's example adds the token. This unit lets systemd own restarts and updates.

# /etc/systemd/system/tf2.service
[Unit]
Description=Team Fortress 2 dedicated server
Wants=network-online.target
After=network-online.target

[Service]
User=steam
WorkingDirectory=/home/steam/tf2
EnvironmentFile=/etc/tf2/gslt.env
TimeoutStartSec=1800
ExecStartPre=-/home/steam/Steam/steamcmd.sh +force_install_dir /home/steam/tf2 +login anonymous +app_update 232250 +quit
ExecStart=/home/steam/tf2/srcds_run -game tf -console -norestart -nohltv -port 27015 +map ctf_2fort +maxplayers 24 +sv_setsteamaccount ${GSLT}
Restart=always
RestartSec=15

[Install]
WantedBy=multi-user.target
  • -norestart turns off srcds_run's own restart loop. Restart=always hands that job to systemd, which starts the server again whenever the process ends, crashed or not.
  • The - in front of ExecStartPre lets the server start on the files it has when the update exits with an error. An update that hangs is different: it can delay the start by as much as TimeoutStartSec=1800 allows, 30 minutes. The ceiling is raised because the default start timeout also covers ExecStartPre.
  • -nohltv disables SourceTV and closes its port (27020 UDP), per VDC. Remove it if you want SourceTV, and open that port.
  • The token reaches srcds through ${GSLT}, read by systemd from the root-only file. It is still on the srcds command line, so any local user can read it with ps. On a machine with no other logins, that is the trade.

Load it: sudo systemctl daemon-reload, then sudo systemctl enable --now tf2; the console scrolls in journalctl -u tf2 -f. VDC notes that a server does not answer queries until a map has loaded.

Ports and the firewall

PortProtoUse, per VDCHere
27015UDPGame traffic and pings; set with -portOpen to all
27015TCPRCON; follows -portYour admin address only
27020UDPSourceTV; +tv_portClosed (-nohltv)
27005UDPClient port; -clientportNo inbound rule (our reading)
26900UDPSteam port, outgoing; -sportNo rule; ufw allows outgoing by default (our reading)

Per VDC's page on the RCON protocol, the remote console listens on TCP 27015 by default and moves with -port, which is why TCP is fenced to one address. Another TF2 instance on this box needs its own install folder (force_install_dir /home/steam/tf2-b), its own server.cfg inside it, its own token, its own unit and its own port, -port 27016: open 27016 UDP to players and 27016 TCP to your address.

Updates, backups, failure modes

Updates arrive on restart: ExecStartPre runs app_update 232250 each time, so sudo systemctl restart tf2 is the procedure. VDC recommends validate only for the first install and when something is broken, because it overwrites changed files.

Copy what SteamCMD cannot download again to another machine yourself: the tf/cfg folder, any .bsp you added to tf/maps, tf/custom and tf/addons if you use them, /etc/systemd/system/tf2.service and /etc/tf2/gslt.env. Two of those hold secrets, so keep the copy private.

  • Segmentation fault at start: the TF2 Wiki says this usually means missing 32-bit libraries.
  • Not in the server browser: check the token first (result 18 or 106 in the log means regenerate it) and that sv_lan is 0.
  • Never add -insecure to a public server; VDC: it starts srcds without Valve Anti-Cheat.

The same SteamCMD and srcds pattern runs other Source games; the Left 4 Dead 2 walkthrough is one.

Questions

What app ID does SteamCMD use for the TF2 server?

232250. VDC's Dedicated Servers List names it the Team Fortress 2 Dedicated Server, available to anonymous login on Linux. 440, the game's Steam app ID, is what the login token is made for.

Is a Game Server Login Token required?

Valve sets no TF2-specific rule; the TF2 Wiki's Linux guide makes a valid token the condition for a browser listing. Our reading, which neither Valve nor the TF2 Wiki states, is that a tokenless server still accepts direct connections by address. Create it for app 440 and pass it with +sv_setsteamaccount.

How many players can one server hold?

VDC lists 101 for Team Fortress 2 and 33 on 32-bit unless -unrestricted_maxplayers is used, an option it calls unsupported and not recommended. Set the count with +maxplayers on the launch line; VDC says it cannot be changed while the server runs.

How do I make the server private?

Set sv_password in server.cfg; VDC's cvar list describes it as the server password for entry. Players then need that password to join. Keep server.cfg at mode 600, since it also holds the RCON password.

Can I run two servers on one machine?

Yes, as two separate installs: each with its own folder, server.cfg, systemd unit, token and port, such as 27015 and 27016. Open each port's UDP to players and its TCP, which carries RCON, only to your own address.

Run TF2 on its own machine

Whole x86 servers with root, an unmetered port and five cities to choose from.

See the machines

Related on Server Room

Other use cases