[編集中]パルワールドの自己運営サーバーを構築。ついでにDiscord Webhookで通知も実装する。

とある活動でほかの方でも遊べるパルワールドサーバーを構築することにしました。
自宅のサーバーで空いているリソースを使って運営をすることを前提にしています。

実装する内容は下記の通り

・Discord Webhookでのサーバー起動通知(状況の把握)
・OS起動時の自動起動(オペレーションを減らす)
・サーバークラッシュ時の自動再起動(オペレーションを減らす)
・サーバー起動時の起動前バックアップ(直前の状態を記録しておく)
・定期的なサーバー再起動とバックアップの作成

バックアップについてはLinuxサーバー版はバックアップ機構が実装されておらず、もし取り返しが付かない不具合があり、大幅にロールバックしなければならない場合に日付で管理できるように。念のために。
ただ、世代管理については実装を見送っており、無限にバックアップは増え続けますので、適時オペレーションを行っていただき、ディスク使用量の肥大化は対処していただけますと…。

Systemdにて起動、停止を行う際の処理周りですが、普通にプロセスキルすればよいかとも思われると思いますが、直接起動してCtrl+Cキーで終了させた際にクラッシュする等の事象が散見されました。
タイミング次第ではデータが壊れそうな気がして恐いので、基本的にはRCONにてシャットダウンコマンドを送信し、シャットダウンを行うことにした。
そのため、結構回りくどい処理になっていますが、セーブデータの安全のために調整しました。ただ、結構突貫で作ってるので徐々になおしていきたいかなとは思っています。

また、現在運用中のサーバーはSELINUXの勉強も込みで有効のまま使っている状態になります。SELINUX周りは別記事にてすったもんだを記載していきます。
今回の記事では無効にした状態を想定して記載していきます。

基本的に当記事では、この記事を参照した上で構築する場合によくある構成へと再編して掲載させていただいています。
問題なく動くとは思いますが、すべてが当方環境と一緒では無いということだけ頭の片隅に置いていただけるようお願いします。

こちらで作ったものをそのまま使う場合は、いくつか必要なものがあります。
ARRCON(Github)
Discord.sh(Github)

ARRCONは、サーバー再起動(シャットダウン)通知の送信とシャットダウンコマンドの実施。
Discord.shは、Discordへの通知を行うために使用します。

当方の環境はFedora 38を使用しています。
CentOSなどLinux系の鯖であれば、基本的に同じように構築は可能では無いかと思います。

事前準備

サーバープログラムを実行するユーザーを作ります。
これは管理者権限に昇格できないユーザーであった方が、余計なディレクトリやファイルへのアクセス制限を施せる面で安心できるので作っておきます。
管理者権限でユーザーを作成し、llコマンドで作成状況を確認します。

sudo useradd -m steam
ll /home

正常に実行できていれば、下記のような表示になると思います。

[Joshua@master01 Joshua]# sudo useradd -m steam
[Joshua@master01 Joshua]# ll /home
合計 4
drwx------. 10 Joshua Joshua 4096  2月  6 01:46 Joshua
drwx------.  2 steam  steam    62  2月  6 20:08 steam
[Joshua@master01 Joshua]# 

俺鯖仕様では、screenコマンドを使用してバックグラウンドで動作するターミナルを生成して実行させているので、該当コマンドもインストールしておきます。Systemdを利用するようになってからはあまり必要性はないのですが、運用上の都合で残すことにしています。

dnf install screen

インストールするかどうか聞かれたらy →Enterで確定させます。

サーバーのシャットダウンや、定期再起動とバックアップ処理を意図的に開始させるためにRCONを使用しています。
今回はパルワールドサーバーのリモートコントロールと、管理者からのメッセージをゲーム内に通知させるために使います。
記事作成段階でのバージョンは3.3.7が最新バージョンなのでそちらを落としていきます。
解凍からコマンドとしてさくっと実行可能になるところまでまとめます。

wget https://github.com/radj307/ARRCON/releases/download/3.3.7/ARRCON-3.3.7-Linux.zip
unzip ARRCON-3.3.7-Linux.zip
sudo cp ARRCON /usr/bin/

ARRCONを/usr/binへコピーする理由ですが、これを行うとどのディレクトリで作業していても「ARRCON」と打ち込めば実行できるようになるんです。
実行するときにすごく楽になるんですよね。おいている場所次第では、
/home/Joshua/scripts/git/tools/ARRCON みたいなフルパス表記だったり、
~/ARRCON のようなホームディレクトリからの相対パス表記で実行して、実行したときのユーザーが違っててパスが通りませんでしたーとか、そもそもアクセス権限がありませんでしたーとか、そういうトラブルが起こりえるので。

コピーしたら実際にテストしてみましょう。

ARRCON -v

問題なく動いていれば下記のように表示されます。

[Joshua@master01 Joshua]# ARRCON -v
ARRCON v3.3.7
 (Copyright © 2022 by radj307)

Steamの導入とサーバーインストール

Linuxサーバーへ手動インストールを行っていきますので、SteamCMD公式手順のhttps://developer.valvesoftware.com/wiki/SteamCMD#Manually
Manuallyの項目をそのまま実行していきます。

yum install glibc.i686 libstdc++.i686
su - steam
mkdir ~/Steam && cd ~/Steam
curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf -
ll

順当に実行していくと下記のように推移していくと思います。

[Joshua@master01 Joshua]# su - steam
[steam@master01 ~]$ mkdir ~/Steam && cd ~/Steam
[steam@master01 Steam]$ curl -sqL "https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz" | tar zxvf -
steamcmd.sh
linux32/steamcmd
linux32/steamerrorreporter
linux32/libstdc++.so.6
linux32/crashhandler.so
[steam@master01 Steam]$ ll
合計 4
drwxr-xr-x. 2 steam steam   93  2月  6 21:04 linux32
-rwxr--r--. 1 steam steam 1166  1月  5  2018 steamcmd.sh

steamclient.soが見つからない旨のエラーが出る場合、それが解消した際にユーザー情報の整合性が合わなくなり最初からになるそうなので、前もって対処しておきます。
Steamのライブラリをダウンロードし、該当ファイルへのシンボリックリンクを作成します。

パルワールド公式の作業手順を、cpコマンドからlnコマンドへ変更していますが、cpコマンドだと更新時に再度コピーし直さなければならなくなるため、シンボリックリンクを作成することでsteamclient.soへリダイレクトするようにしておきます。

https://tech.palworldgame.com/dedicated-server-guide

mkdir -p ~/.steam/sdk64/
./steamcmd.sh +login anonymous +app_update 1007 +quit
ln -s ~/Steam/linux64/steamclient.so ~/.steam/sdk64/

「ll ~/.steam/sdk64/」コマンドを実行して、水色ファイル名 -> 緑ファイル名となることを確認して下さい。緑字が赤字になっていたらパスが通っていません。

ここまで来たらPalworld Serverをインストールします。

./steamcmd.sh +login anonymous +app_update 2394010 validate +quit

Discordのチャンネルへ投稿するBOTを作るために、Discord.shを実装します。
ファイルのダウンロードと実行権限を付与しておきます。

wget https://github.com/fieu/discord.sh/releases/download/v2.0.0/discord.sh
chmod 700 discord.sh

Palworldを一度起動します。
[S_API] SteamAPI_Init(): Loaded~~~~~~~
の表示が出てきたら閉じて構いません。Ctrl+Cキーで強制終了します。

これで最低限必要なファイル群が作成されます。
その後は今回の運用を行うために最低限設定する必要があるので、

cp steamapps/common/PalServer/DefaultPalWorldSettings.ini steamapps/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini
vim steamapps/common/PalServer/Pal/Saved/Config/LinuxServer/PalWorldSettings.ini

上記コマンドをを実行し、デフォルト設定をコピーし、下記の項目を設定して下さい

AdminPassword=”” ””の中にパスワードを入力
RCONEnabled=False ⇒ RCONEnabled=True へ変更

起動とバックアップを行うスクリプトを配置します。

「vim boot-palworld」コマンドを入力し、下記のソースコードをコピペします。
Webhook URLの作成については当記事では触れません。
「Discord Webhook 作成」あたりで検索し、URLを発行して下さい。

#!/bin/bash

export TERM=xterm

#Install directory Config
InstallDir="/home/steam/Steam/steamapps/common/PalServer"
SteamCMD="/home/steam/Steam"

#Discord Webhook Config
WEBHOOK="URL"
#icon="BOT ICON URL"

#Server Info
date=`date +"%Y-%m-%d_%I%M%S"`
host=`hostname`
top=`/usr/bin/top -b -n 1`
CPUUsage=`echo "${top}" | grep "%Cpu(s)" | awk '{a += $2; a += $4; a += $6  } END  {print a}'`
MEMTotal=`echo "${top}" | grep "MiB Mem" | awk '{print $4}'`
MEMFree=`echo "${top}" | grep "MiB Mem" | awk '{print $8}'`

#echo "$top" > test
#echo $CPUUsage
#echo $MEMTotal
#echo $MEMFree

#起動段階で頻繁にクラッシュする可能性も無いと言いきれないため、判定を行う処理
#
#未実装
#
#下記コマンド引数のみsudoできるようにsudorsを編集しておく
#sudo systemctl stop palworld
#exit 1



#SteamCMDを扱う際にcdでディレクトリ移動を行う
cd ${SteamCMD}

#Webhook API連携のためにGitから落としてきたDiscord.shを採用。導入時Ver2.0
#アップデートの開始(あった場合は)とバックアップ開始を宣言。
$SteamCMD/discord.sh \
  --webhook-url="$WEBHOOK" \
  --username "Pal Server - ${host} -" \
  --description "Check for updates and begin backup of user data." \
  --color "0xFF0000"

#SteamCMDにてインストール先指定し、匿名ユーザーとして認証、2394010(PalWorld Dedicated Server)のアップデートチェック、アップデート
#validateは整合性チェックだが起動時間が延びるので無効にする。そのうちアップデートがあった際の挙動を整合チェックありに変える
./steamcmd.sh +force_install_dir ${InstallDir} +login anonymous +app_update 2394010 +quit
#./steamcmd.sh +force_install_dir ${InstallDir} +login anonymous +app_update 2394010 validate +quit

#バックアップとサーバー起動の為にcd
cd ${InstallDir}
tar --exclude "./Pal/Saved/Crashes" -zcvf ./Backup${date}.tar.gz ./Pal/Saved

#Screenコマンドを用いてサーバーを起動。起動時に自動デタッチ、Screen nameをPalに設定。
#screen -r Pal で確認可能。
screen -S Pal -d -m ./PalServer.sh -useperfthreads -NoAsyncLoadingThread -UseMultithreadForDS

#起動に時間が掛るため、安全にログインできるまでのマージンを確保
sleep 15

#起動が完了したものとして告知
${SteamCMD}/discord.sh \
  --webhook-url="$WEBHOOK" \
  --username "Pal Server - ${host} -" \
  --description "Start PalServer." \
  --color "0x00FF00" \
  --field "CPU;${CPUUsage}%;false" \
  --field "Memory Total;${MEMTotal}MiB"\
  --field "Memory Used ;${MEMFree}MiB"

WEBHOOK=”URL” のURL部分に、DiscordのWebhook URLを入力します。

「vim stop-palworld」コマンドを入力し、下記のソースコードをコピペします。

#!/bin/bash

pass="RCONパスワードを入力"

echo "Shutdown 120 After_120_seconds,_the_server_will_restart_to_prevent_bugs_and_for_backup." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 29
echo "broadcast 90_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 30
echo "broadcast 60_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 30
echo "broadcast 30_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 15
echo "broadcast 15_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 14_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 13_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 12_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 11_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 10_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 9_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 8_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 7_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 6_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 5_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 4_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 3_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 2_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 1_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 1
echo "broadcast 0_seconds_to_shutdown." | ARRCON -H 127.0.0.1 -P 25575 -p $pass

pass=”RCONパスワードを入力” の「RCONパスワードを入力」部分に、AdminPasswordに設定した値と同じものを入力します。

「vim shutdown-palworld」コマンドを実行し、下記のソースコードをコピペします。

#!/bin/bash

pass="RCONパスワードを入力"

echo Save | /usr/bin/ARRCON -H 127.0.0.1 -P 25575 -p $pass
echo Shutdown 10 Server_Shutdown | /usr/bin/ARRCON -H 127.0.0.1 -P 25575 -p $pass
sleep 20

↑と同じようにパスワードを設定します。

下記コマンドを実行し、作成したスクリプトに実行権限を付与します。

chmod 700 *-palworld

「vim /usr/lib/systemd/system/palworld.service」コマンドを入力し、下記のソースコードをコピペします。

[Unit]
Description=Palworld Server
After=local-fs.target network-online.target

[Service]
Type=forking
#KillMode=control-group

User=steam
Group=steam
TimeoutStopSec=20
WorkingDirectory=/home/steam/Steam/steamapps/common/PalServer
ExecStart=/home/steam/Steam/boot-palworld
ExecStop=/home/steam/Steam/shutdown-palworld
Restart=always

#SELinuxを有効にしたいけど勉強中でわけわかめ過ぎて編み出したやつ
#インストール先のコンテキスト情報をもとに
#同じもの設定したらいけるんじゃね?的に適用。
#SELinuxContext=unconfined_u:unconfined_r:unconfined_t:s0

[Install]
WantedBy=multi-user.target
sudo firewall-cmd --add-port=8122/udp --permanent
sudo firewall-cmf --reload
sudo systemctl daemon-reload
sudo systemctl start palworld