背景
サーバー構成などの前情報はこちらを参照してください
概要
proxmox VE 8.3 のLXCコンテナ上に、Minecraft (spigot) を立てます。
コンテナに割り振っているIPは 192.168.1.10 とします。
コンテナのテンプレートは「rockylinux-9-default_20240912_amd64」
メモリは13GB、プロセッサは6コア与えています。
コンテナストレージは32GBとしています。
ディレクトリ構造は以下のように構成してる前提としています。
/home/mcuser/
├ bin/ // minecraftサーバー本体
├ buildtool/ // spigotサーバー生成ツール
├ scripts/ // minecraftサーバー起動管理スクリプト等
└ tmp/ // 一時ファイル
前準備
サーバーのファイル管理等で便利なので smb を導入しておきます
[root@minecraft ~]# dnf install samba samba-client samba-common -y
Linuxユーザーを作成していなければ作成しておきます。
Windowsのアカウント名と合わせておくと便利かもしれません。(その前提で進めます)
ここでは例として “mcuser” とします。
[root@minecraft ~]# adduser mcuser
[root@minecraft ~]# passwd mcuser
smbにユーザーを登録します
[root@minecraft ~]# pdbedit -a mcuser
vim /etc/samba/smb.conf で smbを設定します
[global]
passdb backend = tdbsam
printing = cups
printcap name = cups
load printers = yes
cups options = raw
# 文字コード設定
unix charset = UTF-8
dos charset = CP932
# workgroup 設定 (WindowsのWORKGROUP名と一致させる。)
workgroup = WORKGROUP
# 認証設定
security = user
# シンボリックリンクを参照できるようにする
wide links = yes
unix extensions = no
[homes]
comment = Home Directories
valid users = %S, %D%w%S
browseable = No
read only = No
inherit acls = Yes
smbの自動起動設定と起動
[root@minecraft ~]# systemctl enable smb.service
[root@minecraft ~]# systemctl enable nmb.service
[root@minecraft ~]# systemctl restart smb.service
[root@minecraft ~]# systemctl restart nmb.service
Java等のインストール
MC1.20.5以降の推奨Javaバージョンは 21 とのことなので、Java21 を導入します。
[root@minecraft ~]# yum install -y git
[root@minecraft ~]# yum install -y tmux
[root@minecraft ~]# yum install -y java-21-openjdk-devel
インストール
buildtool
まずは buildtool 環境を整えます
[root@minecraft ~]# mkdir /home/mcuser/buildtool
[root@minecraft ~]# cd /home/mcuser/buildtool
[root@minecraft buildtool]# curl -o BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar
[root@minecraft buildtool]# java -jar BuildTools.jar
java -jar BuildTools.jar を叩くと最新版のサーバーが作られます。
(でも公式最新リリースから間もなくは最新版にはならないようです?)
バージョンを指定する場合は –rev 1.21.7 のようにバージョン指定を付け加えてください。
正常にビルドが完了すると、 BuildTools.jar がある場所に、spigot-1.21.7.jar といったファイルが作成され、これがサーバーになります。
これを、/user/mcuser/bin にコピーしておいてください。
起動管理スクリプト
私が昔どこからか参考にしたスクリプトをベースに私なりに色々改造した独自起動管理スクリプトを紹介します。
Minecraftは起動時に色々トラぶることが多いので、変にデーモン化するより手の届く範囲でやったほうがやりやすいと永遠にLinux初心者の私は思います。
/user/mcuser/scripts/ に mcscript.sh を作成します。
vim scripts/mcscript.sh
#!/usr/local/bin/bash
# 応急起動用メモ
# java -server -Dfile.encoding=UTF-8 -Xms8G -Xmx8G -jar server.jar
#===== Settings =====
SERVICE='server.jar'
SESSION='minecraft'
OPTIONS='nogui'
USERNAME='mcuser'
ME=`whoami`
WORLD='world'
MCPATH='/home/mcuser/bin'
BACKUPPATH='/home/mcuser/backup'
UPDATEWORKPATH='/home/mcuser/tmp'
LOGFILE='/home/mcuser/scriptlog.log'
MAXHEAP=10G
MINHEAP=4G
NEWHEAP=1G
HISTORY=1024
CPU_COUNT=6
INVOCATION="java -server -Dfile.encoding=UTF-8 -Xms${MINHEAP} -Xmx${MAXHEAP} -Xmn${NEWHEAP} -XX:+UseG1GC -XX:MaxGCPauseMillis=50 -jar $SERVICE $OPTIONS"
#----------------------------------------------------------
# 実行ユーザー確認
# 違うユーザーでスクリプトを実行したときは su する
#----------------------------------------------------------
as_user() {
if [ $ME == $USERNAME ] ; then
bash -c "$1"
else
su - $USERNAME -c "$1"
fi
}
#----------------------------------------------------------
# サーバー起動
#----------------------------------------------------------
mc_start() {
# サーバーが動作中か確認
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "$SERVICE is already running!"
else
echo "Starting $SERVICE..."
cd $MCPATH
tmux new -s $SESSION -d "$INVOCATION"
# 起動待ち
echo "wait 7sec..."
sleep 7
# サーバーが動作中か確認
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "$SERVICE is now running."
else
echo "Error! Could not start $SERVICE!"
fi
fi
}
#----------------------------------------------------------
# ゲームの自動セーブを停止
#----------------------------------------------------------
mc_saveoff() {
# サーバーが動作中か確認
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "$SERVICE is running... suspending saves"
tmux send-keys -t $SESSION "say SERVER BACKUP STARTING. Server going readonly..." ENTER
tmux send-keys -t $SESSION "save-off" ENTER
sync
echo "wait 10sec..."
sleep 10
else
echo "$SERVICE is not running. Not suspending saves."
fi
}
#----------------------------------------------------------
# ゲームの自動セーブを有効化
#----------------------------------------------------------
mc_saveon() {
# サーバーが動作中か確認
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "$SERVICE is running... re-enabling saves"
tmux send-keys -t $SESSION "save-on" ENTER
tmux send-keys -t $SESSION "say SERVER BACKUP ENDED. Server going read-write..." ENTER
else
echo "$SERVICE is not running. Not resuming saves."
fi
}
#----------------------------------------------------------
# サーバーの停止
#----------------------------------------------------------
mc_stop() {
# サーバーが動作中か確認
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo [`date '+%F %T'`] 'Server stop script start'
echo "Announce Server stop call @ 30sec"
tmux send-keys -t $SESSION "say メンテナンスのため、30秒後にセーブが実行され、その5秒後にサーバーが停止します" ENTER
sleep 10
echo "@ 20sec"
tmux send-keys -t $SESSION "say メンテナンスのため、20秒後にセーブが実行され、その5秒後にサーバーが停止します" ENTER
sleep 10
echo "@ 10sec"
tmux send-keys -t $SESSION "say メンテナンスのため、10秒後にセーブが実行され、その5秒後にサーバーが停止します" ENTER
sleep 10
mc_stopf
else
echo [`date '+%F %T'`] 'server is not runnning'
fi
}
#----------------------------------------------------------
# サーバーの即時停止
#----------------------------------------------------------
mc_stopf() {
# サーバーが動作中か確認
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "Exec save-all command"
tmux send-keys -t $SESSION "save-all" ENTER
echo "wait 5sec..."
sleep 5
echo "Exec stop command"
tmux send-keys -t $SESSION "stop" ENTER
echo "Waiting for server to shut down"
for i in {1..60}; do
# 指定したプロセスが存在するか確認
if ! [ -n "$(tmux list-sessions | grep -o "${SESSION}")" ]; then
# プロセスが存在しない場合、終了
break
fi
# 1秒待機
sleep 1
echo "Waiting for server to shut down"
done
else
echo [`date '+%F %T'`] 'server is not runnning'
fi
# サーバーが動作中か確認
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "Error! $SERVICE could not be stopped."
else
echo "$SERVICE is stopped."
fi
}
#----------------------------------------------------------
# バックアップの実行
#----------------------------------------------------------
mc_backup() {
# ゲームを save
mc_save
echo "wait 10sec..."
sleep 10
# バックアップ中にsaveが動かないように止める
mc_saveoff
# ファイル名の作成
NOW=`date "+%Y-%m-%d_%H%M"`
BACKUP_FILE="$BACKUPPATH/${SESSION}_${NOW}.tar"
# バックアップを実行 (tarアーカイブ)
echo "Backing up $SERVICE"
as_user "tar -C $MCPATH -cf $BACKUP_FILE -X $MCPATH/exclude.conf $MCPATH "
# 止めていた save を有効化
mc_saveon
# バックアップの実行 (gzip圧縮)
echo "Compressing backup..."
as_user "gzip -f $BACKUP_FILE"
echo "Done."
# 古いバックアップのローテーション
if test -n "`ls -t $BACKUPPATH/* | tail -n+5`";then
echo "古いファイルを削除します"
rm -v `ls -t $BACKUPPATH/* | tail -n+5`
fi
echo "完了"
}
#----------------------------------------------------------
# サーバーコンソールからゲーム内にコマンドを発行する
#----------------------------------------------------------
mc_command() {
# 引数を代入
command="$1";
# サーバーが動作中か確認
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
# tmuxのスクロールバックバッファをクリア (TODO:意図通りにできていない)
tmux send-keys -t $SESSION 'clear' ENTER
tmux clear-history -t $SESSION
# ゲーム内にコマンドを発行
tmux send-keys -t $SESSION "$command" ENTER
# パネルの内容をキャプチャ
tmux capture-pane -t $SESSION
# キャプチャした内容を変数に保存して出力
OUTPUT=$(tmux show-buffer)
echo "$OUTPUT"
fi
}
#----------------------------------------------------------
# ゲームのセーブ
#----------------------------------------------------------
mc_save() {
echo "Exec save-all command"
tmux send-keys -t $SESSION "save-all" ENTER
}
#----------------------------------------------------------
# アップデート
#----------------------------------------------------------
mc_update_sub(){
local url="$1" # 最初の引数(URL)
local filename="$2" # 2番目の引数(ファイル名)
# プラグインダウンロード
curl -sS -L ${url} --output ${UPDATEWORKPATH}/${filename}
# ファイルを比較して違っていれば更新
if ! cmp -s ${UPDATEWORKPATH}/${filename} ${MCPATH}/plugins/${filename}; then
echo "${filename}に差異がありました。プラグインを更新します" | tee -a "$LOGFILE"
\cp -f ${UPDATEWORKPATH}/${filename} ${MCPATH}/plugins/${filename}
return 0
fi
return 1
}
mc_update() {
echo "update command"
update_flg=false
# 作業フォルダが無ければ作る
[ ! -d $UPDATEWORKPATH ] && mkdir $UPDATEWORKPATH
# プラグイン更新
mc_update_sub https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot Geyser-Spigot.jar && update_flg=true
mc_update_sub https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot floodgate-spigot.jar && update_flg=true
# サーバー動作中に更新があればプラグインをリロード
if [ "$update_flg" = true ]; then
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
tmux send-keys -t $SESSION "reload" ENTER
echo "$(date '+%Y-%m-%d %H:%M:%S') update & reloaded" | tee -a "$LOGFILE"
fi
fi
}
#==========================================================
# Start-Stop here
#==========================================================
case "$1" in
start)
mc_start
;;
stop)
mc_stop
;;
stopf)
mc_stopf
;;
restart)
mc_stop
mc_start
;;
backup)
mc_backup
;;
save)
mc_save
;;
status)
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "$SERVICE is running."
else
echo "$SERVICE is not running."
fi
;;
check)
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "$SERVICE is running."
else
echo "$SERVICE is not running. wait 120sec..."
sleep 120
if [ -n "$(tmux list-sessions 2>/dev/null | grep -o "${SESSION}")" ]; then
echo "$SERVICE is running."
else
mc_start
fi
fi
;;
command)
if [ $# -gt 1 ]; then
shift
mc_command "$*"
else
echo "Must specify server command (try 'help'?)"
fi
;;
attach)
echo "Minecraftサーバーコンソールにアタッチします"
echo "デタッチ方法は Ctrl + b -> d です (Ctrl+bしてから一度放した後に d キー押下)"
echo "Ctrl + c はプロセスを殺してしまうので注意してください"
echo "Escキーを押下するとキャンセルします。その他キーを押下するとアタッチを開始します..."
read -n 1 -s key
if [[ $key == $'\e' ]]; then
# Escキーを押下したとき
echo "Attach canceled"
else
# その他キーを押下したとき
tmux a -t $SESSION
fi
;;
update)
mc_update
;;
*)
echo "Usage: $0 {start|stop|backup|status|restart|command \"server command\"}"
exit 1
;;
esac
exit 0
使用方法は、
bash mcscript start
という感じです。
ざっくり引数の説明としては
・start : 起動
・stop:ゲーム内警告付き30秒後停止
・stopf:警告無し即時停止
・restart:start と stop を続けて実行する
・backup:バックアップを実行
・status:サーバーの稼働状態を表示
・check:サーバーが起動していたらなにもしない、停止していたら起動する(定期的に落ちる鯖の定期起動用)
・command:ゲーム内コマンドを呼び出す
・update:geyser と floodgate のプラグインをダウンロードし、変化があればプラグインを更新する(自分用です、使う場合はうまくカスタマイズしてください)
おまけ:各種プラグインの設定等
dynmap用データベース
Webマッププラグインdynmapはデータの管理にデータベースを使用することが出来ます。
パフォーマンス的にはデータベースを使った方が良いはずなので設定しておきます。
[root@minecraft ~]# dnf install -y mariadb-server
[root@minecraft ~]# systemctl enable --now mariadb;systemctl restart mariadb
初期設定をします。
mariadbのバージョンが新しい場合は mariadb_secure_installation に名前が変わっているので注意。
mysql_secure_installation
(dbrootpass)
Switch to unix_socket auth: n
Change root pass: n
Remove anonymous users: y
Deallow remote root login: y
Remove test db: y
Reload privilege table now: y
vim /etc/my.cnf.d/mariadb-server.cnf で mysql.sockの場所を確認しておきます。
私の環境では socket=/var/lib/mysql/mysql.sock でした。
データベースを作成します。
dynmapの初期設定に合わせて、DB名、User名、Password 全て dynmap にしてます。
mysql -u root -pdbrootpass
CREATE DATABASE dynmap;
GRANT ALL PRIVILEGES ON dynmap.* TO "dynmap"@"localhost" IDENTIFIED BY 'dynmap';
FLUSH PRIVILEGES;
間違った場合など、消す場合は、 drop database dynmap;
データベース設定
plugins/dynmap/configuration.txt
type: filetree をコメントアウト
以下のコメントアウトを外す
type: mysql
port: 3306
database: dynmap
userid: dynmap
password: dynmap
type は mariadb を設定すると説明しているところもあるが、Dynmap 自体が MariaDB ドライバーでコンパイルされていないと機能しないらしい。mysqlでも問題ないみたい。

