ARKのゲームサーバーをAzureに構築する

こんにちわ。

最近、ARKというゲームを始めてみました。
内容は、恐竜が跋扈する無人島でサバイバル生活を行う、といったものです。

- [ARK: Survival Evolved - SPIKE CHUNSOFT](https://www.spike-chunsoft.co.jp/ark)

このゲームはオンラインマルチプレイに対応していますが、友人などの限られたメンバーで遊びたい場合は、プライベートなゲームサーバーを構築する必要があります。

今回は、このゲームサーバーをMicrosoft Azure上に構築したので、とりあえず遊べるようになるまでの備忘録です。


# リソースの生成
ゲームサーバーの構築に必要な各種リソースを生成します。

- [パブリックIP](#パブリックipの生成)
- [仮想ネットワーク](#仮想ネットワークの生成)
- [ネットワークセキュリティグループ](#ネットワークセキュリティグループの生成)
- [仮想マシン](#仮想マシンの生成)

リソースグループは、ゲームサーバー用に新規作成したほうが管理は楽になります。

下記以外の項目はお好みで設定してください。


## パブリックIPの生成
- [パブリックIPアドレスの作成 - Microsoft Azure](https://portal.azure.com/#create/Microsoft.PublicIPAddress-ARM)

ゲームサーバーを外部へ公開する際のエンドポイントとなるリソースです。
ここにグローバルIPアドレスが割り当てられます。

**基本**

- IPバージョン: IPv4
- SKU: Basic
- IPアドレスの割り当て: 静的
- アイドルタイムアウト: 5分
- 場所: 東日本

ここでDNS名を設定した場合、外部からアクセスする際にIPアドレスの代わりにDNS名を使用できます。


## 仮想ネットワークの生成
- [仮想ネットワークの作成 - Microsoft Azure](https://portal.azure.com/#create/Microsoft.VirtualNetwork)

Azure内のリソースを相互接続する仮想ネットワークです。
今回は仮想マシン(に従属するネットワークインターフェイス)とパブリックIPしか接続しません。

**基本**

- 地域: 東日本

**IPアドレス**

- IPアドレス空間: 192.168.0.0/24
- サブネット名: default
- サブネットアドレス範囲: 192.168.0.0/24

**セキュリティ**

- DDoS保護: Basic
- ファイアウォール: 無効


## ネットワークセキュリティグループの生成
- [ネットワークセキュリティグループの作成 - Microsoft Azure](https://portal.azure.com/#create/Microsoft.NetworkSecurityGroup)

送受信ポート制御などを司るリソースです。
ポート開放はOSからではなく基本このリソースから操作します。

**基本**

- 地域: 東日本


## 仮想マシンの生成
- [仮想マシンの作成 - Microsoft Azure](https://portal.azure.com/#create/Microsoft.VirtualMachine)

ARKのゲームサーバーは最低起動要件が思いのほかハードル高いので、ハードウェアサイズは`B2s v3(2vCPU, 8GB RAM)`にしてあります。
しかし24時間稼動の1ヶ月で10000円も掛かるので、色々と試してみて下げれそうなら下げて良いかもしれません。

OSはUbuntu Server 18.04にしてます。
2020/06/11現在、東日本DCでは20.04を選択できませんでした。
まだですかMicrosoftさん...

今回は手間やお財布事情で冗長関連の設定は切ってますが、有効化しても問題ありません。

**基本**

- 地域: 東日本
- 可用性オプション: 無し
- イメージ: Ubuntu Server 18.04 LTS
- Azure スポットインスタンス: いいえ
- サイズ: Standard B2s v3
- パブリック受信ポート: 選択したポートを許可
- 受信ポートを選択: SSH

**ディスク**

- OSディスクの種類: Premium SSD
- 暗号化の種類: プラットフォームマネージドキーを使用した保存時の暗号化
- マネージドディスクを使用する: はい

**ネットワーク**

- 仮想ネットワーク: ([仮想ネットワーク](#仮想ネットワークの作成) で作成したリソース)
- パブリックIP: ([パブリックIP](#パブリックipの作成) で作成したリソース)
- NICネットワークセキュリティグループ: 詳細
- ネットワークセキュリティグループの構成: ([ネットワークセキュリティグループ](#ネットワークセキュリティグループの作成) で作成したリソース)
- パブリック受信ポート: 選択したポートを許可
- 受信ポートを選択: SSH
- 高速ネットワーク: オフ
- この仮想マシンを既存の負荷分散ソリューションの後ろに配置しますか: いいえ

**管理**

- ブート診断: オフ
- OS のゲスト診断: オフ 
- システム割り当てマネージドID: オフ 
- 自動シャットダウンを有効にする: オフ 
- バックアップの有効化: オフ

**詳細**

- VM の生成: Gen2


# リソースの設定
全リソースのデプロイが完了したら、各リソースごとに構成設定を行います。

- [ネットワークセキュリティグループ](#ネットワークセキュリティグループの設定)
- [ネットワークインターフェイス](#ネットワークインターフェイスの設定)

## ネットワークセキュリティグループの設定
**受信セキュリティ規則**
いわゆるポート開放です。
以下のルールを追加します。

|名前|ソース|ソースポート範囲|宛先|宛先ポート範囲|プロトコル|アクション|優先度|
|:--|:--|:--|:--|:--|:--|:--|:--|
|SSH|Any|*|Any|22|TCP|許可|100|
|Ark_Socket|Any|*|Any|7777,7778|Any|許可|200|
|Ark_Browse|Any|*|Any|27015|Any|許可|210|
|Ark_Rcon|Any|*|Any|27020|Any|許可|220|

**ネットワークインターフェイス**

- 関連付け: ([仮想マシンの生成](#仮想マシンの生成) 時に自動生成されたネットワークインターフェイスのリソース)

**サブネット**

- 関連付け: ([仮想ネットワークの生成](#仮想ネットワークの生成) 時に作成したサブネット)


## ネットワークインターフェイスの設定
**IP構成**

- IP転送: 無効
- サブネット: ([仮想ネットワークの生成](#仮想ネットワークの生成) 時に作成したサブネット)

**ipconfig1**

- パブリックIPアドレス: 関連付け
- IPアドレス: ([パブリックIPの生成](#パブリックipの生成) で生成したリソース)
- プライベートアドレス割り当て: 静的
- IPアドレス: 192.168.0.4

**ネットワークセキュリティグループ**
- ネットワークセキュリティグループ: ([ネットワークセキュリティグループの生成](#ネットワークセキュリティグループの生成) で生成したリソース)


# システムの設定
[リソースの設定](#リソースの設定) が完了したら、いよいよリモートログインします。

**インストール済のパッケージを更新**
最初はお約束です。

```shell:Shell
sudo apt update
sudo apt upgrade
sudo apt autoremove
sudo apt autoclean
```

**ファイルオープン数の上限引き上げ**
ARKのゲームサーバーは同時に大量のファイルを開くため、デフォルト値では上限に達してしまい、パフォーマンスに影響が出る可能性がある、との事です。

以下の3項目を設定します。

```shell:Shell
sudo ulimit -n 1000000
```

```config:/etc/sysctl.conf
fs.file-max=100000
```

```config:/etc/security/limits.conf
* soft nofile 1000000
* hard nofile 1000000
```


# スクリプトの作成
ゲームサーバーをインストールする前に、よく行う処理をスクリプトにまとめておきます。

- `ark_install_server.sh` ... ゲームサーバーのインストール/アップデート
- `ark_install_mod.sh` ... Modのインストール/アップデート
- `ark_start_server.sh` ... ゲームサーバーを起動
- `ark_backup_server.sh` ... コンフィグ/ゲームデータをバックアップ
- `ark_restore_server.sh` ... コンフィグ/ゲームデータをレストア

まずはシェルスクリプトファイルを作成します。

```shell:Shell
cd ~/
sudo touch ark_install_server.sh ark_install_mod.sh ark_backup_server.sh ark_restore_server.sh ark_start_server.sh
sudo chmod 755 ark_install_server.sh ark_install_mod.sh ark_backup_server.sh ark_restore_server.sh ark_start_server.sh
```

それぞれのスクリプト内容は、以下となります。

`__MySession__`や`__MyPassword__`や`xxxxxxxx,...`(Modを導入する場合)などは、その時によって適宜変更してください。

```shell:~/ark_install_server.sh
steamcmd +login anonymous +force_install_dir ~/ark_server +app_update 376030 +quit
```

```shell:~/ark_install_mod.sh
rm -rf ~/ARK
rm -rf ~/.steam/SteamApps/workshop/content/346110

arkmanager installmod ${1}

rm -f ~/ark_server/ShooterGame/Content/Mods/${1}.mod
rm -rf ~/ark_server/ShooterGame/Content/Mods/${1}

cp -f ~/ARK/ShooterGame/Content/Mods/${1}.mod ~/ark_server/ShooterGame/Content/Mods
cp -rf ~/ARK/ShooterGame/Content/Mods/${1} ~/ark_server/ShooterGame/Content/Mods

rm -rf ~/ARK
rm -rf ~/.steam/SteamApps/workshop/content/346110
```

```shell:~/ark_start_server.sh
~/ark_server/ShooterGame/Binaries/Linux/ShooterGameServer\
 ${1}\
?listen\
?SessionName=__MySession__\
?ServerPassword=__MyPassword__\
?ServerAdminPassword=__MyPassword__\
?RCONEnabled=True\
?RCONPort=27020\
# ?ShowFloatingDamageText=True\
# ?AllowHitMarkers=True\
# ?NonPermanentDiseases=True\
?GameModIds=xxxxxxxx,yyyyyyyy,zzzzzzzz\
 -server\
 -log\
 -culture=ja
```

```shell:~/ark_backup_server.sh
rm -rf ~/ark_backup/*

cp -rf ~/ark_server/ShooterGame/Saved/SavedArks ~/ark_backup
cp -rf ~/ark_server/ShooterGame/Saved/Config/LinuxServer ~/ark_backup
```

```shell:~/ark_restore_server.sh
rm -rf ~/ark_server/ShooterGame/Saved/SavedArks
rm -rf ~/ark_server/ShooterGame/Saved/Config/LinuxServer

mkdir -p ~/ark_server/ShooterGame/Saved/Config

cp -rf ~/ark_backup/SavedArks ~/ark_server/ShooterGame/Saved
cp -rf ~/ark_backup/LinuxServer ~/ark_server/ShooterGame/Saved/Config
```


# インストール
ゲームサーバーの運用に必要なアプリケーションをインストールします。

- [Steamコマンドラインツール](#steamコマンドラインツール)
- [ゲームサーバー](#ゲームサーバー)
- [Mod展開ツール](#mod展開ツール)


# Steamコマンドラインツール
- [SteamCMD - Valve Developer Community](https://developer.valvesoftware.com/wiki/SteamCMD)

Steamには、各種操作をCLIで操作できる **SteamCMD** というコマンドラインツールが用意されています。
Ubuntuの場合、公式のパッケージリポジトリで公開されているので、それをインストールします。

```shell:Shell
sudo apt install steamcmd
```


## ゲームサーバー
まずはインストールとバックアップに使用するディレクトリを作成します。

```shell:Shell
mkdir ~/ark_server
mkdir ~/ark_backup
```

ゲームサーバー本体のインストールは、先ほど作成したインストールスクリプトを使用します。
これにより、バイナリが`~/ark_server`へデプロイされます。

```shell:Shell
./ark_install_server.sh
```

デプロイが完了したら、ゲーム設定ファイルを作成します。
設定ファイルは初回起動時に自動生成されるのですが、この時点ではまだ存在しないので、先に作成します。

```shell:Shell
sudo mkdir -p ~/ark_server/ShooterGame/Saved/Config/LinuxServer
sudo touch ~/ark_server/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini
sudo touch ~/ark_server/ShooterGame/Saved/Config/LinuxServer/Game.ini
```

なお、設定ファイルはよく編集すると思うので、ホームディレクトリにシンボリックリンクを作成しておくと便利です。

```shell:Shell
sudo ln -s ~/ark_server/ShooterGame/Saved/Config/LinuxServer/GameUserSettings.ini ~/GameUserSettings.ini
sudo ln -s ~/ark_server/ShooterGame/Saved/Config/LinuxServer/Game.ini ~/Game.ini
```

設定ファイルの内容は [ゲームの設定](#ゲームの設定) にて後述します。


## Mod展開ツール
- [FezVrasta/ark-server-tools - GitHub](https://github.com/FezVrasta/ark-server-tools)

Mod導入は躓きポイントです。

よくある解説記事では "Modは起動オプションに`-automanagedmods`もしくはGame.iniに`[ModInstaller]`を追加すると自動でダウンロードとインストールをしてくれる" という記載がありますが...

**少なくともLinux版では動きませんでした。**

これらのオプションを設定すると、サーバーアプリケーションが起動中にクラッシュします。
そのためModを入れる場合は、手動でダウンロードと展開を行い適切なディレクトリへデプロイする必要があります。
そしてModのダウンロードと展開を行うためのツールが **ARK-Server-Tools** となります。

なお、このツールはゲームサーバーのオーケストレーターとして機能するため、このツールを使用してもゲームサーバーはインストールは出来るのですが、今後の対応などを考えるとなるべく使用したくない思いもあり、今回このツールはModのダウンロードと展開だけに使用します。

インストールスクリプトを`curl`でダウンロードし、そのまま実行します。
`-s MyUser`オプションは、自身がいまログインしてるユーザー名に置き換えます。

```shell:Shell
curl -sL http://git.io/vtf5N | sudo bash -s MyUser
```


# ゲームの設定
- [Server Configuration - ARK Wiki](https://ark.gamepedia.com/Server_Configuration/ja)

ARK Wikiのコンフィグ内容を確認しながら、設定ファイルに項目を記述します。

- [GameUserSettings.ini](#gameusersettingsini)
- [Game.ini](#gameini)

## GameUserSettings.ini
サーバーやゲーム内の全体に関する設定を記述するファイルです。

`RCONServerGameLogBuffer` ~ `ItemStackSizeMultiplier`にかけては、特に変更する必要のない項目ですが、削除してもまた復活してしまうので、デフォルト値を記述しています。

以下の項目は、前述の [スクリプトの作成](#スクリプトの作成) で作成した`ark_start_server.sh`と内容を合わせる必要があります。

- `ServerPassword=__MyPassword__`
- `ServerAdminPassword=__MyPassword__`
- `RCONEnabled=True`
- `RCONPort=27020`
- `SessionName=__MySession__`
- `ActiveMods=xxxxxxxx,yyyyyyyy,zzzzzzzz`
- `ShowFloatingDamageText` (任意)
- `AllowHitMarkers` (任意)
- `NonPermanentDiseases` (任意)

その他の項目は、ARK Wikiのコンフィグ一覧を確認しながら好みで追加や削除を行います。

<details><summary>設定内容(参考)</summary><div>

```ini:GameUserSettings.ini
[ServerSettings]
RCONServerGameLogBuffer=600.0
OxygenSwimSpeedStatMultiplier=1.0
StructurePreventResourceRadiusMultiplier=1.0
RaidDinoCharacterFoodDrainMultiplier=1.0
ListenServerTetherDistanceMultiplier=1.0
TheMaxStructuresInRange=10500.0
TribeNameChangeCooldown=15.0
PlatformSaddleBuildAreaBoundsMultiplier=1.0
StructurePickupTimeAfterPlacement=30.0
StructurePickupHoldDuration=0.5
AllowIntegratedSPlusStructures=True
PvEDinoDecayPeriodMultiplier=1.0
KickIdlePlayersPeriod=3600.0
PerPlatformMaxStructuresMultiplier=1.0
AutoSavePeriodMinutes=15.0
ItemStackSizeMultiplier=1.0
ServerPassword=__MyPassword__
ServerAdminPassword=__MyPassword__
RCONEnabled=True
RCONPort=27020
# ShowFloatingDamageText=True
# AllowHitMarkers=True
# NonPermanentDiseases=True
# ServerPVE=True
# ServerCrosshair=True
# ShowMapPlayerLocation=True
# AllowThirdPersonPlayer=True
# AllowHideDamageSourceFromLogs=True
# NoTributeDownloads=True
# AllowCaveBuildingPvE=True
# AllowFlyerCarryPvE=True
# DifficultyOffset=3.0
# HarvestAmountMultiplier=3.0
# PlayerCharacterWaterDrainMultiplier=0.2
# StructureResistanceMultiplier=0.5
# DayTimeSpeedScale=0.75
# NightTimeSpeedScale=1.25
# TamingSpeedMultiplier=20.0
# DinoCountMultiplier=2.0
# MaxTamedDinos=5000.0
ActiveMods=xxxxxxxx,yyyyyyyy,zzzzzzzz

[SessionSettings]
SessionName=__MySession__

[/Script/Engine.GameSession]
MaxPlayers=70
```
</div></details>


## Game.ini
ゲーム内の詳細なバランス調整を記述するファイルです。
こちらは、とくに他と設定内容を合わせる必要は無いので、ARK Wikiを見ながら完全に好みで設定します。

<details><summary>設定内容(参考)</summary><div>

```ini:Game.ini
[/script/shootergame.shootergamemode]
# bUseSingleplayerSettings=True
# bDisableFriendlyFire=True
# bAllowUnlimitedRespecs=True
# bUseCorpseLocator=True
# GlobalCorpseDecompositionTimeMultiplier=5.0
# UseCorpseLifeSpanMultiplier=5.0
# MatingIntervalMultiplier=0.05
# EggHatchSpeedMultiplier=10.0
# BabyMatureSpeedMultiplier=15.0
# BabyCuddleIntervalMultiplier=0.01
```
</div></details>


# Modのインストール
Modを入れる場合は、最初に作成したスクリプトを使用します。
このスクリプトを使用すると、先ほどインストールした [ARK-Server-Tools](#mod展開ツール) を使用しModのダウンロードと展開を行い、それをゲームサーバーのインストールディレクトリへデプロイしてくれます。

引数の`xxxxxxxx`は、Steam WorkshopのMod IDです。

```shell:Shell
sudo ./ark_install_mod.sh xxxxxxxx
```


# サーバーの起動/停止
**サーバーの起動**
最初に作成したスクリプトで行います。
引数のMapNameは、以下のマップ名のいずれかを入力します。

- `TheIsland`
- `TheCenter`
- `Extinction`
- `Ragnarok`
- `ScorchedEarth_P`
- `Aberration_P`

```shell:Shell
sudo ./ark_start_server.sh MapName
```

起動すると、以下のエラーログのようなものが表示される場合がありますが、そのまま放置で問題ありません。
5~10分ほどでログインできるようになります。

```
[S_API FAIL] SteamAPI_Init() failed; SteamAPI_IsSteamRunning() failed.
Setting breakpad minidump AppID = 346110
```

**サーバーの停止**
ゲームにログインした状態でTabキーを押し、管理者コンソールに以下のコマンドを入力します。

```shell:InGameConsole
EnableCheats __MyPassword__
AdminCheats DoExit
```

SSHでCtrl+Cを押してサーバーを強制終了させると、最悪の場合アイテムロストが発生する可能性があるとの事なので、オススメしません。


# ゲームデータのバックアップ/レストア
ゲームデータと設定ファイルのバックアップとレストアは、最初に作成したスクリプトで行えます。
バックアップ先は`~/ark_backup`となります。

**バックアップ**

```shell:Shell
sudo ./ark_backup_server.sh
```

**レストア**

```shell:Shell
sudo ./ark_restore_server.sh
```


# RCONについて
RCONとは、本来はゲームにログインしないと叩けない管理者コンソールを外部から叩くためのプロトコルです。
専用のターミナルアプリケーションを使用して操作できます。

ARKのゲームサーバーもRCONに対応しており、ポートは`27020`を使用します。

ターミナルは **mcrcon** を使用します。
元々はMineCraft用だったらしいのですが、RCONを使用する他のゲームにも流用可能とのことです。

- [Tiiffi/mcrcon - GitHub](https://github.com/Tiiffi/mcrcon)

Windowsの場合、以下のようなバッチファイルを作成しターミナルを起動することで、対話的なコマンド操作が可能になります。

```shell:ark_control.cmd
@echo off
setlocal

set address=__MyAddress__
set port=27020

echo Address: %address%
echo Port: %port%

set /p password="Password: "

mcrcon.exe -H %address% -P %port% -p %password% -t
```

サーバーを停止する際など、いちいちゲームにログインせずともRCON経由で安全に操作できます。

```shell:RCON
DoExit
```

# おわりに
手元にハードウェアが無くても、だれでも簡単にゲームサーバーを構築できるようになりました。
素晴らしいですね。