きっかけ
ふと、久しぶりにminecraftをやりたいなぁと思い、せっかくならマルチプレイ用のサーバをEC2上に構築しようと思った。
その際の構築メモ(備忘録)。
ざっくり要件
- 自宅でサーバを立てるのはネットワーク要件諸々が厳しかったので、クラウドかつカスタムがしやすいEC2を使用する
- minecraftはJava版の最新バージョンを使用する
- 参加人数は今のところ1~3人程度
- 1日1回程度バックアップを取りたい
- アクティブユーザが少ない平日昼間の時間帯はインスタンスをシャットダウンしてコストを抑えたい
EC2インスタンスの準備
インスタンスのスペック
- Ubuntu Server 20.04 LTS
- t3.small
- ボリューム 20GB
EC2周りの設定
インスタンス作成時にセキュリティグループのインバウンドルールを設定しておく。
- TCP, UDP: 25565
- SSH: マイIP
またElastic IPを発行し、作成したインスタンスと紐付けておく。
サーバ構築
インスタンスにログイン
$ ssh ubuntu@xxx.xxx.xxx.xxx -i key.pem
パッケージを更新
$ sudo apt update
$ sudo apt upgrade
タイムゾーンを変更
$ sudo timedatectl set-timezone Asia/Tokyo
必要なパッケージのインストール
$ sudo apt install -y default-jdk screen wget
minecraft実行用のユーザを作成
$ sudo useradd -m -r -d /opt/minecraft minecraft
今回作るワールドの名前をsurvival
としてディレクトリを作成
$ sudo mkdir /opt/minecraft/survival
minecraft公式ページのダウンロードページからjarダウンロード用のURLをコピーしてダウンロード
$ sudo wget -O /opt/minecraft/survival/server.jar https://launcher.mojang.com/v1/objects/1b557e7b033b583cd9f66746b7a9ab1ec1673ced/server.jar
使用許諾契約に同意するためのファイルを事前に作成
$ sudo bash -c "echo eula=true > /opt/minecraft/survival/eula.txt"
オーナーを変更
$ sudo chown -R minecraft:minecraft /opt/minecraft/survival/
サービス設定ファイルの作成
- サービス名とディレクトリ名とリンクさせる
-
-Xmx1G
は搭載メモリに応じて適宜変更する - stop時はサーバ内にアナウンスを流し、1分間の猶予の後に止めてセーブする
[Unit]
Description=Minecraft Server: %i
After=network.target
[Service]
WorkingDirectory=/opt/minecraft/%i
User=minecraft
Group=minecraft
Restart=always
ExecStart=/usr/bin/screen -DmS mc-%i /usr/bin/java -Xmx1G -jar server.jar nogui
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say 60秒後にサーバがシャットダウンされます"\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say 速やかにログアウトしてください"\015'
ExecStop=/bin/sleep 50
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say 10秒後にサーバがシャットダウンされます"\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say 速やかにログアウトしてください"\015'
ExecStop=/bin/sleep 10
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "save-all"\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\015'
[Install]
WantedBy=multi-user.target
設定ファイルをリロード
$ sudo systemctl daemon-reload
インスタンス起動時に自動起動するように設定
$ sudo systemctl enable minecraft@survival
minecraftサーバの起動
サービスの起動。survival
を指定する
$ sudo systemctl start minecraft@survival
statusで状態を確認できる。stopやrestartも使える。
$ sudo systemctl status minecraft@survival
$ sudo systemctl stop minecraft@survival
$ sudo systemctl restart minecraft@survival
minecraftの初期設定
起動しているscreenに入る。PIDを調べてアタッチする。
スクリーンから抜ける(デタッチ)時はCtrl + A → D
$ sudo -i
# su minecraft
$ screen -ls
$ screen -r [PID]
オペレータ権限を付与する。
opが付与されたユーザはゲーム内からも管理コマンドを実行可能。
op [ユーザ名]
ホワイトリスト設定を使用して、ホワイトリストに追加したminecraftサーバに入れるようにする。
人を追加するときは随時whitelist add [ユーザ名]
で追加する。
ホワイトリストを有効化
whitelist on
ホワイトリストにユーザ追加
whitelist add [ユーザ名]
ここまで設定すれば遊ぶ準備は整っている。
この後はバックアップと起動停止の設定を行う。
バックアップと起動停止
インスタンスの自動終了を設定(crontab)
自動起動に合わせてCloudWatch Eventsで設定したかったが、minecraftサーバのセーフティな終了とバックアップを行いたかったのでcrontabで設定した。
バックアップ用のディレクトリを作る
$ sudo mkdir /opt/minecraft/backup
バックアップ用のシェルスクリプトを用意する。
やっていることは以下の通り。
- サーバを停止後、全体を圧縮したバックアップファイルを生成する。
- バックアップは最新10日間を残して削除する(ファイル個数で判定するほうが良さそう)。
- バックアップ後に引数によってサーバを起動するかシャットダウンを行うようにする。
#!/bin/bash
SERVER_NAME="survival"
sudo systemctl stop minecraft@${SERVER_NAME}
sleep 5
TIMESTAMP=`date +%Y%m%d-%H%M%S`
MINECRAFT_PATH="/opt/minecraft/${SERVER_NAME}"
BACKUP_FILE="/opt/minecraft/backup/${SERVER_NAME}/mc_backup_full_${TIMESTAMP}.tar.gz"
sudo tar cfvz $BACKUP_FILE $MINECRAFT_PATH
sudo chown ubuntu:ubuntu ${BACKUP_FILE}
sudo find /opt/minecraft/backup -name '*.tar.gz' -mtime +10 -delete
if [ "$1" = "start" ]; then
sudo systemctl start minecraft@${SERVER_NAME}
elif [ "$1" = "shutdown" ]; then
sudo shutdown -h now
fi
スクリプトファイルに実行権限を与えておく
$ sudo chmod 644 /opt/minecraft/minecraft_backup.sh
cronにスケジュールを設定する。
- 平日午前2時にバックアップ後、インスタンスをシャットダウンする
- 土日午前6時にバックアップ後、再度サーバを立ち上げる
※祝日の考慮はめんどくさいのでCloudWatch Eventsの兼ね合いを考えて行っていない
$ crontab -e
0 2 * * 1-5 /usr/bin/sh /opt/minecraft/minecraft_backup.sh shutdown
0 6 * * 6-7 /usr/bin/sh /opt/minecraft/minecraft_backup.sh start
インスタンスの自動起動を設定(CloudWatch Events)
CloudWatch Eventsで設定した。
SSM Automationで新しいロールを作ると権限が足りないエラーになってしまうので、先にIAMでロールを生成する。
AmazonSSMAutomationRole
のポリシーをアタッチしたロールを作成する。
ロールを作成したらCloudWatch
-> イベント
-> ルール
で自動起動用のルールを作成する。
以下の画像のように設定する。
- 平日17時に起動するようにCron式を設定する。
0 0 ? * 2-6 *
※Cron式はGMTなので、JSTにするため+9時間する - オートメーションパラメータ定数の
instanceId
はEC2インスタンスのIDを入力する - ロールは先ほどIAMで作成したロールを選択する
感想
メモリは最低2GBの割り当ては必要かな〜と考えていたが、1GBでも3人程度なら今のところほぼ快適に動作している。
ただ、負荷がかかる処理をするとメモリが割と枯渇気味になるので、更にワールドを拡張したり人数が増える際にインスタンスタイプを上げる必要があると思う。
参考にさせていただいたサイト