2hours.gg/

Game servers by the hour. Pay only when you play.

How to run a Windows-only game server on Linux

Some Steam games only ship a Windows dedicated server. There is no Linux binary in the depot, so the usual advice is "run it on a Windows box." You do not have to. With Wine you can run the Windows server on a normal Linux machine, and it will connect to Steam and accept real players. This is the exact recipe that worked for us, using Alien Swarm: Reactive Drop (a free Source co-op game) as the example. The same approach should carry to other Windows-only Source dedicated servers.

First, check there really is no Linux server

Do not assume. Ask Steam directly before you reach for Wine. Point steamcmd at the app and read its platform list:

steamcmd +login anonymous +app_info_print <appid> +quit \
  | grep -iE "oslist|name"

If the dedicated-server app is "oslist windows" only, there is no native Linux build to fall back to. You can also try to force a Linux install; when there is genuinely no Linux depot it fails fast:

steamcmd +@sSteamCmdForcePlatformType linux \
  +login anonymous +app_update <appid> validate +quit
# ERROR! Failed to install app '<appid>' (Missing configuration)

That error, and no ELF files landing, confirms it. Now Wine is the path. Install the server AND app 1007 (the Steamworks Common Redistributables) into the same folder, with the windows platform type. App 1007 ships the Steam DLLs the server needs, and you will see why in Step 2:

steamcmd +@sSteamCmdForcePlatformType windows +login anonymous \
  +force_install_dir /path/to/server \
  +app_update <appid> validate \
  +app_update 1007 validate \
  +quit

Why the naive Wine attempt fails

Running the server straight from Wine hits two walls in a row:

  • No console: the server expects a real terminal. Piping from /dev/null gives CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents and it never starts.
  • Unable to load Steam library: even once it boots, it prints "Unable to load Steam support library" and never registers with Steam, so no one can find or join it.

Both are fixable. Here is the full recipe.

Step 1: give it a real terminal (PTY)

A headless box has no terminal, and the Windows console server refuses to run without one. Wrap the launch in script, which allocates a pseudo-terminal, and use Xvfb for a fake display:

Xvfb :99 -screen 0 1024x768x24 &
export DISPLAY=:99 WINEPREFIX=/wine
script -qfc "wine srcds_console.exe -console -condebug \
  -game <gamedir> +map <map> -port 27015" /tmp/server.log

That alone gets the server to load a map and bind its game port. But it still cannot talk to Steam.

Step 2: two Steam DLLs, two different sources

The Source engine needs BOTH steamclient.dll and steam.dll next to the server exe, and here is the trap that cost us a full extra debugging round: they come from DIFFERENT places, and app 1007 only gives you ONE of them.

  • steamclient.dll: comes from app 1007 (Steamworks Common Redistributables), which you installed in Step 1. Canonical, version-matched, Valve-maintained.
  • steam.dll: is NOT in app 1007. It is part of the Steam CLIENT, and the only clean way to get it is to run the Windows steamcmd.exe once under Wine, which self-updates and lays down steam.dll (plus steamclient.dll) in its own folder.

So bootstrap steam.dll with steamcmd.exe under Wine, then copy both DLLs next to the server exe:

# steam.dll: run Windows steamcmd once under Wine (needs Xvfb for a display)
cd "$WINEPREFIX/drive_c/steamcmd"
curl -fsSLO https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip
unzip -o steamcmd.zip
DISPLAY=:99 wine steamcmd.exe +quit    # lays down steam.dll + steamclient.dll

# place both next to the server exe
cd /path/to/server
cp "$WINEPREFIX/drive_c/steamcmd/steam.dll" .
[ -f steamclient.dll ] || cp "$WINEPREFIX/drive_c/steamcmd/steamclient.dll" .

Step 3: why steam.dll is the piece that matters

This is the part almost nobody writes down. The error says "Unable to load Steam support library," and the support library it means is not steamclient.dll, it is steam.dll. The Source engine looks for steam.dll next to its own executable to bootstrap the whole Steam chain. With only steamclient.dll present (which is all app 1007 gives you) it still fails; the moment steam.dll is beside the .exe, the log turns over from failure to success:

Connection to Steam servers successful.
VAC secure mode is activated.

VAC will not activate unless the server is a properly logged-in gameserver, so that line is your proof it registered. Most Source servers log in anonymously here and need no Game Server Login Token (GSLT). Only a few games (like CS2) require one.

The trap: A2S goes silent but the server is fine

Here is the gotcha that cost us the most time, and the reason we nearly gave up. Under Wine the server does NOT answer A2S_INFO, the UDP query that tools use to read a server's name, map, and player count. Query it and every port times out, even from the same machine. If you use A2S as your health check, the server looks completely dead.

It is not dead. A2S being silent under Wine does not stop real players from joining. The in-game server browser lists servers from Steam's master list (which the server pushes to on its own), and a direct connect uses the game protocol, not A2S. So the true test is a client connecting, not a query answering. When we finally tried it, a real player connected and played on the first attempt:

Client "player" connected (10.0.0.5:27005).
1/ 8 on map <mapname>

The practical lesson: for a Wine-hosted server, do not health-check with A2S. Check something that actually reflects liveness, such as the "VAC secure mode is activated" line in the log, the player-count line, or a plain check that the game UDP port is bound.

Does this work for every Windows game?

Be honest about the scope. We proved this on a Source-engine server, and the same recipe (PTY, a steamcmd-built runtime, steam.dll next to the exe) should work for other Windows-only Source dedicated servers. Games on other engines integrate Steam differently, so treat them as separate experiments. Two things to expect either way: boots are slower than native Linux (Wine plus the steamcmd step plus the Steam login), and the A2S-silent behaviour above will likely apply to all of them.

Or skip all of this

This is the kind of yak-shave that eats an afternoon. If you just want the server, we run the Linux fleet and the Wine plumbing for you, by the hour, with a public IP from the first minute. See what we host on 2hours.gg.

See also

← Back to all guides