統合版Minecraftのサーバを建てる

# はじめに
Java版のサーバ設置に関してはあちらこちらに参考になる記事があるのですが、こと統合版に関してはあまり情報がなく、手探りでサーバの設定をしなくてはなりません。
そこで今後統合版のサーバを自宅サーバやレンタルVPS上に設置してみたいという方のために作業の記録を残しておきます。
私はRealmsからの乗り換えとなります。毎月1000円でメンテフリーでマルチができるのは魅力ですが、マップが拡大するにつれて処理能力の限界を感じて来たり、レンダリング距離が短く高スペックなPCがあっても生かせなかったり、カスタマイズ性にも乏しいので1年ほど遊んでいるとなんだか物足りなくなってきたので自前でサーバ設置を考え始めました。
本記事の執筆にあたり様々なネット記事を参考にしました。特にKagoya VPSさんが出しているJava版サーバ設置方法の記事とほとんど同じ方法で統合版もサーバを建てることができます。

https://www.kagoya.jp/howto/cloud/vps/vps_minecraft/

# 前提
<strike>サーバはKagoya VPSというレンタルVPSを利用します。プランは3コア/2GB RAMの月1000円ほどのものを選んでいますが、それ以上でもそれ以下でもサーバ設置に当たっては問題ありません。
Kagoya VPS上のOSはUbuntu 20.04 LTSです。</strike>

オンプレミス移行に伴い、動作確認済みの環境が変更となりました。
環境依存な処理はしていないので、基本的に異なる環境でも動作すると推測しますが、保証はできかねます。
その点ご承知おき頂いたうえで、ご参考にしていただければ幸いでございます。

- HP Z640
  - Xeon E5-2637 v3 (4C8T) x2 (8C16T)
  - RAM: DDR4-2133 8GB x4
  - インストール先: 256GB SATA SSD
  - OS: CentOS 7 → ubuntu desktop 24.04 LTS

マンションのネットワークでのサーバ構築については下記の記事を参考にしていただければ幸いです。

https://qiita.com/kabegamikamio/items/56e74d0ce1701f106af8

また各種操作を行うにあたり、ssh接続ができたりnanoやvim等のエディタが使えることを前提として話を進めて行きます。

# やりたいこと
- 公式サーバをインストールして走らせる
    - `screen`で操作できるように（後述）
- 毎日3回バックアップを取る
    - 最大5個のバージョンを残しておく
- 毎月1回アーカイブを残す
    - Minecraft Overviewerで地図を作るため
- 毎日1回再起動する
    - 再起動にあたり自動でbedrock_serverも起動したい
- ホストappを自動更新する
    - `if (公開されているversion) > (現在のversion) do update`

自動でHTMLで見れるマップを生成するスクリプトも作っています。
もしよかったらこちらも見てみてください。

https://qiita.com/kabegamikamio/items/2a1aabf2c09974d1743a

参考程度に、ディレクトリ構成図を載せておきます。

```
~/bedrock
├── backups/
│   ├── archive/
│   ├── daily/
│   └── monthly/
├── backup.sh
├── end_server.sh
├── reboot.sh
├── run.sh
|── update2.sh
└── server/
    :
    ├── version.txt
    :
```

# I. サーバを設置する
最初に必要なパッケージがいくつかあるのでインストールしておきましょう。
おそらく一つだけで大丈夫ですが、適宜`root`でインストールしておいてください。

```bash
sudo apt install ufw    # ポートを常時開放するためのパッケージ
```

次にサーバ管理を行うためのユーザ`minecraft`を作りましょう。
今後の操作は特記ない限りすべてユーザ`minecraft`から行います。

```bash
sudo adduser minecraft
su - minecraft
```

続いてMojangの公式サイトから統合版サーバをVPSにダウンロードして展開します。
下記ページにアクセスしてLinux用サーバのダウンロードリンクを取得してください。

https://www.minecraft.net/ja-jp/download/server/bedrock

作業用フォルダ`bedrock/`を作ってそこにダウンロード、さらにその下にサブフォルダ`server/`を作って展開します。
サブフォルダを作るのは、サーバのアップデートの際に便利という理由です。

```bash
cd ~
mkdir bedrock/
cd bedrock/
wget https://minecraft.azureedge.net/bin-linux/bedrock-server-(最新ver).zip
unzip bedrock-server* -d server/
```

既にワールドデータがある場合は、`scp`などの方法でサーバに保存し、`~/bedrock/server/worlds`内に配置してください。

続いてポート開放をします。VPSの場合であれば以下で終わると思いますが、自宅サーバの場合は別途ルータなどのポート開放が必要になる場合があります。

```bash
sudo ufw allow 19132    # bedrock server のIPv4デフォルトポート
                        # 変更してもOKです (server.configもいじる)
sudo ufw allow 19133    # bedrock server のIPv6デフォルトポート: IPv4と同様です
sudo ufw reload
sudo ufw status         # 19132, 19133 が開放されているか確認
```

> マンションなどにサーバを置かれている方はこちらも参考にしてください
> https://qiita.com/kabegamikamio/items/56e74d0ce1701f106af8

これでサーバの設定にひと段落ついたので試運転します。
以下のコマンドでホストを動かしましょう。

```bash
cd ~/bedrock/server/
./bedrock_server
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626368/0fde8fbb-1ecc-af0d-5439-31130d2b9487.png)

クライアント側でこのように表示されればOKです。
ただこのままでは`bedrock_server`を起動したsshが閉じてしまうと`bedrock_server`の諸操作ができなくなってしまいます。
次項でこれを改善します。

# II. `screen`でホストを走らせる
`screen`とは、仮想環境のようなもので、複数のセッションを一括管理できる利点があります。
`bedrock_server`を起動するには以下のようなコマンドを打てばいいのですが、毎回タイプするのは面倒です。

```bash
# サーバ起動の度にこれを実行するのは面倒
cd ~/bedrock/server
screen -dm -S minecraft /bin/bash -c ~/bedrock/1.17.31.01/bedrock_server
```

そこで `~/bedrock/` に`run.sh`というスクリプトを書いて配置します。

```bash:~/bedrock/run.sh
#!/bin/bash

RUN_STATUS_MC=`screen -ls | grep minecraft | grep -v S-minecraft | wc -w`

fi
if [ $RUN_STATUS_MC -eq 0 ]; then    # minecraftという名前のscreenがなければ新しく作る
        # Start the bedrock server
        echo starting new server
        cd ~/bedrock/server/
        screen -dm -S minecraft /bin/bash -c ~/bedrock/server/bedrock_server
else
        echo "Server already running.\n"    # minecraftというscreenがあるならばホストは実行中
fi
```

今後スクリプトを追加する際は同様に実行権限付与を行ってください。

```bash
chmod 755 run.sh
```

実際にこのスクリプトを走らせてみます。

```
./run.sh
```

このままだと画面には何も変化ありません。
`screen`コマンドの詳しい使い方は他の方の解説に譲るとして、`bedrock_server`に入って何か操作するときは以下のコマンドを実行します。

```
screen -r minecraft    # minecraftという名前のセッションに接続

[2021-09-27 07:30:55:803 INFO] Level Name: OurCity
[2021-09-27 07:30:55:804 ERROR] xuid or permission missing from permissions file: permissions.json

（略）

# screen上からMinecraftのゲーム内に操作を加えることもできます
title @a title hello    # プレイヤーの画面にhelloと表示できる
op Steve                # プレイヤーSteveにOperator権限を付与
stop                    # bedrock_server終了
```

`screen`は`Ctrl-A D`でセッションを一旦閉じることができます。閉じたセッションを開きなおすには`screen -r <セッション名 or ID>`と覚えておきましょう。

# III. 再起動を定期的に行う
毎日1回サーバの再起動を行い、再起動前にプレイヤーにアナウンスして再起動後は自動的に`bedrock_server`を起動するようにします。

以下はホストを停止するためのスクリプトです。
3分前からカウントダウンを始めてサーバを停止します。

```bash:~/bedrock/end_server.sh
#!/bin/bash

# Display presets
STR_1="tellraw @a {\"rawtext\":[{\"text\":\"[SERVER] Reboot in "
STR_2=" sec\"}]}\\015"
STR_3=" min\"}]}\\015"

# 3分以上をカウントする場合に備えてやや冗長な記述になってます
count_down () {
        # Counting down from 2 min to 2 min
        for i in {2..2}; do
                sleep 1m
                screen -S minecraft -p 0 -X stuff "$STR_1$i$STR_3"
        done

        # Counting down from 60 sec to 20 sec by 10 sec
        for i in 60 50 40 30 20; do
                sleep 10s
                screen -S minecraft -p 0 -X stuff "$STR_1$i$STR_2"
        done

        # Counting down from 10 sec to 0 sec
        for i in {10..0}; do
                sleep 1s
                screen -S minecraft -p 0 -X stuff "$STR_1$i$STR_2"
        done
}


# Display the announcement of shutting down
screen -S minecraft -p 0 -X stuff 'tellraw @a {"rawtext":[{"text":"[SERVER] The server will be rebooted in 3 min"}]}\015'

# count down to stop the bedrock server
count_down

# Ending message
screen -S minecraft -p 0 -X stuff 'tellraw @a {"rawtext":[{"text":"Server ended"}]}\015'

# Shutting down the host
screen -S minecraft -p 0 -X stuff 'stop\015'

echo ended
```

カウントダウンの方法はもう少しやりようがあった気もしますが、まあだいたいでいいかなと思います。

続いて下に示すのは、再起動用のスクリプトです。
再起動するのはホストだけで、サーバ(マシン)自体はrebootしません。

```bash:~/bedrock/reboot.sh
#!/bin/bash
# This is a SHELL programme to reboot the bedrock server

# Stop the bedrock server
~/bedrock/end_server.sh

# Wait until the bedrock server stops
sleep 3

# Restart the bedrock server
~/bedrock/run.sh
```

このスクリプトを自動実行するように設定をしておきます。

```
~ $ crontab -e

@reboot /home/minecraft/run.sh         # マシンが再起動した後は念の為run.shを走らせる
0 7 * * * /home/minecraft/reboot.sh    # 毎日7:00にbedrock_serverを再起動
13 7 * * * /home/minecraft/run.sh      # 万が一再起動にトラブルがあった場合に7:13にrun.shを走らせる
```

またサーバ自体の再起動も行いたいので、`root`ユーザにログインして同様にスケジュールを組みます。

```
root:~ $ crontab -e

0 7 * * * sudo shutdown -r now
```

# IV. バックアップを定期的に行う
`bedrock_server`には標準でバックアップ機能がついているのですが、バージョン管理ができないなどあまり便利とは言えないものなので、ワールドデータを圧縮してバックアップ用フォルダに保存する方法を考えます。
先述の通り、万が一の復元用のバックアップは1日3回、また地図を作成するためのデータは月1回生成します。

```
/home/minecraft
├── backups/           # 毎日バックアップ用フォルダ
│   ├── annual/        # 毎月バックアップ用フォルダ
|   ├── backup.sh      # バックアップスクリプト
├── bedrock/
│   ├── 1.17.31.01/    
│   │   ├── worlds/    # ワールドデータ
```

バックアップを行うスクリプトは以下の通りです。

```bash:backup.sh
#!/bin/bash

# バックアップdir
BACKUP_DIR=/home/minecraft/bedrock/backups

# バックアップ元
TARGET_DIR=/home/minecraft/bedrock/server/worlds/OurCity/

# 毎日のバックアップ名
DAILY_DIR=${BACKUP_DIR}/daily/`date +%Y-%m-%d_%H:%M:%S`

# 毎月のバックアップ名
MONTHLY_DIR=${BACKUP_DIR}/monthly/`date +%Y-%m`

# 毎日バックアップの保管数
NUM_GENS=3


# コマンドライン引数からバックアップモードを指定
# 0 : 毎日バックアップ
# 1 : 毎月バックアップ
BACKUP_MODE=$1

# 古いバックアップを消去する関数
delete_file () {
    CNT=0
    eval "cd $BACKUP_DIR/daily"
    for file in `ls -1t *zip`
    do
        CNT=$((CNT+1))
        if [ $CNT -le $NUM_GENS ]; then
            continue
        fi
        eval "rm ${file}"
    done
}

# zipファイルを作成する関数
make_zip () {
    zip ${1} -r ${2} -q
}


# BACKUP_MODEの判定
if [ $BACKUP_MODE -eq 0 ]; then
    make_zip $DAILY_DIR $TARGET_DIR
    delete_file
elif [ $BACKUP_MODE -eq 1 ]; then
    make_zip $MONTHLY_DIR $TARGET_DIR
fi
```

このコマンドを定期的に実行させるために`crontab`を編集します。

```
~ $ crontab -e
...
# 以下追加行
0 3 * * * /home/minecraft/backups/backup.sh 0    # 毎日AM3:00に実行
0 12 * * * /home/minecraft/backups/backup.sh 0   # 毎日PM12:00に実行
0 19 * * * /home/minecraft/backups/backup.sh 0   # 毎日PM19:00に実行
5 3 1 * * /home/minecraft/backups/backup.sh 1    # 毎月1日に実行
```

# アップデートを自動で行う
公式ではアップデートの有無の確認をするインターフェースは提供されていない(と思う、多分)ので、自分で最新のバージョン番号を取得し、現在のサーババージョンと比較することでアップデートの有無を検証します。

> スクリプト作成にあたってはMinory様の記事を参考にさせていただきました。
> https://minory.org/bedrock-server-auto-update-linux.html

現在のバージョンは `~/bedrock/server/version.txt` で管理しています。
ない場合は一旦作っておきます。

```bash:~/bedrock/server/
vi version.txt    # 初回は現在のバージョンを手打ち
```

```bash:~/bedrock/update2.sh
#!/bin/bash

# The directory holding your Bedrock server files
cd /home/minecraft/bedrock/server

# Randomizer for user agent
RandNum=$(echo $((1 + $RANDOM % 5000)))

URL=`curl -H "Accept-Encoding: identity" -H "Accept-Language: en" -L -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.33 (KHTML, like Gecko) Chrome/90.0.$RandNum.212 Safari/537.33" https://www.minecraft.net/ja-jp/download/server/bedrock/ 2>/dev/null | grep bin-linux/ | sed -e 's/.*<a href=\"\(https:.*\/bin-linux\/.*\.zip\).*/\1/'`
VERSION=`echo $URL | sed -n 's/.*bedrock-server-\([0-9.]*\).zip/\1/p'`
CUR_VERSION=`cat version.txt`
echo URL shown
echo $URL

# Verify if the DOWNLOAD and SERVER destinations exist. Create if it doesn't
if [ -z $URL ]; then
  echo invalid update link
  exit 1
elif [[ $CUR_VERSION = $VERSION ]]; then
  echo the server is the latest
  exit 1
else
  # write the newest version to version.txt
  echo $VERSION | cat > version.txt

  # Process kill
  echo stopping server
  screen -S minecraft -p 0 -X stuff 'stop\015'  # stop server

  # Backup files
  echo replicating world data
  cp -r ./worlds/OurCity ../temp

  echo replicating server.properties
  cp ./server.properties ../temp/server.properties

  echo replicating permissions.json
  cp ./permissions.json ../temp/permissions.json

  echo replicating allowlist.json
  cp ./allowlist.json ../temp/allowlist.json

  echo replicating structures
  cp -r ./structures ../temp

  echo all replication done

  # Get new bedrock server from web site
  # pretends to be Safari to obtain the server zip
  echo obtaining server zip
  wget ${URL} --user-agent=safari
  echo unzipping
  unzip -o ${URL##*/} 2>&1 > /dev/null
  echo removing zip
  rm bedrock-server*.zip
  echo new server deployment done

  # Relocate files
  echo recovering server.properties
  cp ./backup/server.properties ./server.properties

  echo recovering permissions.json
  cp ./backup/permissions.json ./permissions.json

  echo recovering allowlist.json
  cp ./backup/allowlist.json ./allowlist.json

  echo recovering permissions.json
  cp ./backup/permissions.json ./permissions.json

  echo recovering structures
  cp -r ./backup/structures ./
  echo all recovery done

  # Start process
  echo restart server
  ~/bedrock/run.sh
fi
```

こちらも自動起動するように設定します。

```bash: crontab
0 5 * * * /home/kkamio/bedrock/update2.sh      # 毎日AM5:00にアップデート実行
```

# さいごに
今回は統合版Minecraftのサーバ設置の一部始終をお伝えいたしました。
お伝えした内容で以下のことができるようになりました。

- 公式サーバをインストールして走らせる
    - `screen`で操作できるように（後述）
- 毎日3回バックアップを取る
    - 最大5個のバージョンを残しておく
- 毎月1回アーカイブを残す
    - Minecraft Overviewerで地図を作るため
- 毎日1回再起動する
    - 再起動にあたり自動でbedrock_serverも起動
- 毎日1回ホストを更新する

まだ粗削りな部分がありますので、今後もサーバに手を加えつつこちらのページも更新していきます。