ゲームサーバーを1時間ごとに。遊ぶときだけ支払い。

Windows 専用のゲームサーバーを Linux で動かす方法

Steam のゲームの中には Windows 用の専用サーバーしか用意されていないものがあります。depot に Linux バイナリがないので、いつものアドバイスは「Windows マシンで動かせ」です。その必要はありません。Wine を使えば、Windows サーバーを普通の Linux マシンで動かすことができ、Steam に接続して実際のプレイヤーを受け入れます。これは、例として Alien Swarm: Reactive Drop(無料の co-op Source ゲーム)を使って私たちが実際にうまくいったレシピそのものです。同じアプローチは Windows 専用の他の Source 専用サーバーでも通用するはずです。

まず、本当に Linux サーバーが存在しないかを確認する

決めつけないでください。Wine に頼る前に Steam に直接尋ねましょう。steamcmd をそのアプリに向けて、プラットフォームの一覧を読みます:

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

サーバーの専用サーバーアプリが「oslist windows」だけなら、頼れるネイティブ Linux ビルドはありません。Linux インストールを強制してみることもできます。本当に Linux depot がないときは、その場で失敗します:

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

このエラーと、ELF ファイルが 1 つもダウンロードされないことが、それを裏付けます。ここからは Wine が道です。サーバーと app 1007(Steamworks Common Redistributables)を同じフォルダに、プラットフォームタイプ windows でインストールします。app 1007 はサーバーが必要とする Steam の DLL をもたらします。その理由はステップ 2 でわかります:

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

Wine での素朴な試みが失敗する理由

サーバーを Wine から直接動かすと、続けざまに 2 つの壁にぶつかります:

  • コンソールがない: サーバーは本物の端末を期待します。/dev/null からリダイレクトすると CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents が出て、起動しません。
  • Steam ライブラリを読み込めませんでした: 起動したあとでも「Unable to load Steam support library」と表示され、Steam に登録されないので、誰も見つけられず入れません。

どちらにも直し方があります。ここに完全なレシピを示します。

ステップ 1: 本物の端末(PTY)を与える

ヘッドレスのマシンには端末がなく、Windows のコンソールサーバーは端末なしでは動くのを拒否します。起動をスクリプトで包んで疑似端末を割り当て、偽のディスプレイ用に Xvfb を使います:

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

これだけでサーバーはマップを読み込んでゲームポートをバインドします。ですが、まだ Steam と話すことができません。

ステップ 2: 2 つの Steam DLL、2 つの異なる入手元

Source エンジンは steamclient.dll と steam.dll の両方をサーバーの exe の隣に必要とします。そしてここに、デバッグを丸 1 周分よけいに費やす羽目になった罠があります: それらは異なる場所から来ていて、app 1007 はそのうち片方しか渡してくれません。

  • steamclient.dll: はステップ 1 でインストールした app 1007(Steamworks Common Redistributables)から来ます。正規で、互換性のあるバージョンで、Valve がメンテナンスしています。
  • steam.dll: は app 1007 に含まれていません。これは Steam クライアントの一部で、それをきれいに入手する唯一の方法は、Windows 版の steamcmd.exe を Wine の下で一度実行することです。すると自動更新され、steam.dll(と steamclient.dll)を自身のフォルダに置きます。

そこで steamcmd.exe を Wine の下で実行して steam.dll をブートストラップし、そのあと 2 つの DLL をサーバーの 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" .

ステップ 3: なぜ steam.dll が肝心の部品なのか

これはほとんど誰も書き留めていない部分です。エラーには「Unable to load Steam support library」と出ますが、そこで言及されているサポートライブラリは steamclient.dll ではなく steam.dll です。Source エンジンは Steam のチェーン全体をブートストラップするために、実行ファイルの隣に steam.dll を探します。steamclient.dll だけがある状態(app 1007 が渡してくれるのはそれだけ)ではまだ失敗します。steam.dll が .exe の隣に置かれた瞬間、ログは失敗から成功へと変わります:

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

VAC はサーバーが正しくログインしたゲームサーバーでない限り有効になりません。なので、この行はサーバーが登録されたことの証拠です。ほとんどの Source サーバーはここで匿名でログインし、Game Server Login Token(GSLT)は必要ありません。一部のゲーム(CS2 など)だけが必要とします。

罠: A2S が沈黙するがサーバーは正常

ここで私たちが最も時間を取られ、あやうく諦めかけた理由となる部分です。Wine の下ではサーバーは A2S_INFO に応答しません。これはツールがサーバーの名前、マップ、プレイヤー数を読むために使う UDP クエリです。問い合わせると、どのポートも、同じマシンからでもタイムアウトします。A2S をヘルスチェックに使っていると、サーバーは完全に死んでいるように見えます。

死んではいません。Wine の下で A2S が沈黙しても、実際のプレイヤーが入るのを妨げることはありません。ゲーム内のサーバーブラウザは Steam のマスターリスト(サーバー自身が送信します)からサーバーを一覧表示し、ダイレクト接続は A2S ではなくゲームのプロトコルを使います。だから本当のテストはクエリが応答することではなく、クライアントが接続することです。実際に試してみたところ、本物のプレイヤーが一発で接続してプレイできました:

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

実践的な教訓: Wine でホストしたサーバーでは、A2S でヘルスチェックをしないこと。ログの「VAC secure mode is activated」の行、プレイヤー数の行、あるいはゲームの UDP ポートがバインドされているかどうかの単純な確認など、実際に生きているかどうかを反映するものをチェックしましょう。

これはすべての Windows ゲームで通用する?

スコープには正直になりましょう。私たちはこれを Source エンジンのサーバーで実証しましたが、同じレシピ(PTY、steamcmd でビルドしたランタイム、exe の隣の steam.dll)は Windows 専用の他の Source 専用サーバーでも通用するはずです。他のエンジンのゲームは Steam の統合の仕方が異なるので、別々の実験として扱ってください。どのみち予想すべきことが 2 つあります。ブートはネイティブ Linux より遅くなること(Wine に steamcmd のステップと Steam ログインが加わるため)、そして上記の A2S 沈黙の挙動はおそらくすべてに当てはまること。

あるいは全部すっ飛ばす

これは午後をまるごと食いつぶすたぐいの面倒ごとです。サーバーさえあればいいなら、Linux フリートと Wine まわりの配管は私たちが引き受けます。時間単位で、最初の 1 分からパブリック IP 付きです。私たちが2hours.gg でホストしているものをご覧ください。

関連情報

← すべてのガイドに戻る