3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ProxmoxのLXC上にminecraftのサーバーを立てる(PaperMC)[備忘録]

3
Last updated at Posted at 2025-08-18

どういう記事?

Discordのサーバーでマイクラ鯖を立てようという事になり、ProxmoxのLXC上にマイクラのサーバーを立てたので、その備忘録です。筆者はマイクラを遊んだ事が無く、基礎的な知識が欠落していますのでご留意ください。一応想定プレイヤー人数は全部で10人もいかないだろう、ぐらいで建てました(なので同時にアクセスするのは多くて2,3人想定)。

めっちゃ雑に書いていて、「手順書」ではないので注意してください

環境

  • CPU: 8 x Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz
  • proxmox 8.4.1
  • LXC image: Ubuntu 24.04.3 LTS
  • LXC RAM: 8GB
  • LXC Swap: 4GB
  • LXC Cores: 3

サーバーアプリケーションの選定の話

マインクラフトのサーバーアプリケーションには:

  • Vanilla: 純正のやつ
  • MODサーバー: MODが使えるやつ
  • Pluginサーバー: Pluginが使えるやつ

の3種類ぐらいがあるようです(新しいキャラやブロックを追加するならMOD、ゲームシステム自体に変更が必要ならPluginという住み分けのようです)。

今回はJava版と統合版(Bedrock版)のユーザーが一緒に遊べるようにしたく、Geyserというプラグインを使いたかった為、Pluginサーバーの中でメジャーそうなPaperMCを使う事にしました。

参考:

LXCのRAMについては、以下のページで最低でもRAMが6~10GBはあった方が良いと書いてあったので、8GBにしています。

立てていく

step1: LXC自体の準備

自分は、Ubuntuベースでサーバーを立てる時には、ロケールの設定やgitの設定などをshell scriptにしてそれを実行しています。以下はその一部です(全部出すのは、自分の稚拙なshell scriptだと怒られが発生しそうなので止めておきます。適当にLLMにでも作ってもらってください。そっちのが良いと思います)。

storageは30GBほど用意しましたが、これはあんまりよくわかってないからです。
ネットワークについては、LXC自体にもIPアドレスを割り当てています。

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#  基本パッケージ更新
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
apt update
apt upgrade -y
apt autoremove -y
apt clean

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#  タイムゾーン&ロケール設定
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
timedatectl set-timezone Asia/Tokyo
locale-gen en_US.UTF-8
update-locale LANG=en_US.UTF-8

# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
#  UFW 設定
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw --force enable
ufw status verbose

# などなど....あとはお好みでnvimの設定など

step2: minecraft userの追加

マイクラサーバー自体をrootで実行するわけにもいかないので、sudo権限を持たないminecraftのuserとgroupを作っておきます。

# Minecraftグループを作成
sudo groupadd minecraft

# Minecraftユーザーを作成
# -r: システムユーザーとして作成
# -g: プライマリグループを指定
# -d: ホームディレクトリを指定
sudo useradd -r -g minecraft -d /home/minecraft minecraft

セキュリティの事を考えると、ログインシェルは無い方が良いとは思ってます。

step3: 必要な物のインストール

Java21のinstall

PaperMCの以下のページの説明に従ってJavaをLXCにinstallします。ドキュメントはapt-getですが自分はaptを使いました。まぁ、その辺はお好みで....。

PaperMCのインストール

su minecraftでスー(ダイアン津田)した後、
このぺージで、PaperMCのjarのリンクをコピーして、/home/minecraftでwgetしてjarをダウンロードします。

cd /home/minecraft
wget {download url}

すると、jarがdownloadされます。

step4: 一旦動かしてみる

paperMCのドキュメントに従うだけではありますが、startup script generatorでワンライナーが生成出来るので、それを使います。

startup script generatorでメモリの割り当てを選択する項目がありますが、Aikar's flagの説明にある通り、LXCに割り当てたRAMと同じサイズで実行してはたぶん(OS分のメモリまで使って)良くないのでstartup script generatorではメモリは8-1.5=6.5GBを選択しています。

生成されたスクリプトは以下です

java -Xms6656M -Xmx6656M -jar paper-1.21.8-31.jar nogui

これを最初に実行すると、eula.txt云々みたいなログが出てサーバーがFailします。

この時、同じディレクトリ(つまり/home/minecraft)にeula.txtというファイルが生成されているので、好きなエディタを使ってこれの中でtrueに変えます。

eula.txt
#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://aka.ms/MinecraftEULA).
#Thu Aug 14 13:56:30 UTC 2025
eula=true #<-ここ

再度、上記のコマンドを実行すると、サーバーが動くかと思います。

step5: 接続してみる

今回はFirewallとしてUFWを使用しているので、minecraftのdefault portである25565/tcpを開けます

sudo ufw allow 25565/tcp

これでMinecraftのMultiplay画面でIPアドレスを入れれば、接続が出来るかと思います。
(Minecraftを持ってない人は買いましょう。自分は公式HPで買いましたが、MicrosoftアカウントでSign Upしたため、Microsoft Storeでも購入済みになっていて、どっちで買っても同じなんだなってなりました。もしかしたらMojangアカウントの場合との違いはあるのかもしれませんが....)

サーバーの停止は、サーバー側のInteractive shell(?)で

stop

で出来ます。

Pluginのインストール

Geyserのインストール

/home/minecraft/pluginというディレクトリが生成されているので、そこに移動して、wgetでgeyserのjarをdownloadします。ダウンロードリンクは以下のページのspigotのボタンを右クリックで取得できます。

リンク上、spigotという名前になってダウンロードされるので、適当な名前にリネームします。

mv spigot Geyser-Spigot.jar

この状態で再度サーバーを起動すると、/home/minecraft/plugins/Geyser-Spigotというディレクトリが生成され、その中にconfig.ymlなどが生成されています。

MinecraftのPlugin導入においては、このjarとConfig類が入っている同名のディレクトリというセットの構成が一般的な?ようです。

特に今回このConfigは変えていません。
また、Bedrock版とJava版では使用ポート及びプロトコルが異なり、TCPではなくUDPになります。
なのでUFWのルールを追加します。

```shell
sudo ufw allow 19132 /udp

Floodgateのインストール

jarを/home/minecraft/plugins/にダウンロードしてサーバーを起動させると、Configが生成されるところまではGeyserと同じです。

ここで、Geyserのconfig.ymlの中のAuth-typeをonlineからFloodgateに変更します。

これでBedrock版のユーザーが、Bedrock版の認証でサーバーにアクセスできました。

ただ、bedrockの人がjava版で入ろうとしたときに問題が起こったので、global linkingもしくはlocal linkingを用いてbedrockユーザーもjava版のUUIDで参加してもらった方がよいです。

DiscordSRVのインストール

Githubの最新のリリースからこれも同様にjarをダウンロードします。

DiscordSRV自体がDiscord botとなってサーバーと色々同期をしたりするわけですが、そのあたりのセットアップは公式ドキュメントを読むのが最もわかりやすいです(Discord botの開発経験があると尚良し)

余談ですが、DiscordSRVがメッセージを送る(=Minecraftと同期する)チャンネルのIDをスレッドのIDにしたらどうだろうと思ったものの、それは動きませんでした。

今回は、Discordのサーバーに参加しており、かつ特定のロールを持つ人だけがMinecraftに参加できるようにしたいので、/home/minecraft/plugins/DiscordSRV/linking.configを変えておきます。変更する項目だけ抜き出します。ロールのIDはDiscordの権限設定で、右クリックメニューからコピーできます。

plugins/DiscordSRV/linking.yml
Require linked account to play:
  Enabled: true

# デフォルトではDiscordSRVの開発者の名前が入ってるので、自分の名前に変える
Bypass names: [{username(IGN)}] 

Subscriber role:
    Require subscriber role to join: true
    Subscriber roles: ["{Role_Id}"]

  # Message to kick players with telling them to link their accounts
  # Use {BOT} as a placeholder for the bot's name
  # Use {CODE} as a placeholder for the code people need to DM the bot
  # Use {INVITE} as a placeholder for the invite link people need to join the Discord server, uses DiscordInviteLink configured in config.yml
  Not linked message: "&7アカウントを&9Discord&7とリンクする必要があります。\n\n&7Discord内で&b{BOT}&7にDMで&b{CODE}&7を送信してください。"

ちなみに、Minecraftのusername(In-Game Name)というのはGlobalで一意なもののようです。

また、デフォルトではDiscord上でマインクラフトのコマンドを実行できる機能がオンになっているのですが、今回はオフにしておきます(管理人以外が実行出来ても怖いので)。

plugins/DiscordSRV/config.yml
DiscordChatChannelConsoleCommandEnabled: false

LuckPermsのインストール

権限管理用のLucky Permsを入れます(権限管理の何かが無いと、DiscordSRVのコマンド打つのもダルイっぽい)。

以下のページのBukkitのアドレスをコピーして、/home/minecraft/plugins/でwgetします。

今まで同様、Minecraft serverを再起動するとLuckPermsディレクトリが生成されています。

基本的な設定は公式のページに従うだけではあります。

マイクラ内ではなく、サーバーのconsoleで以下のコマンドを実行し、管理者に全ての権限を与えます。

lp user <your username> permission set luckperms.* true

今回は、管理者と利用者の2グループを作って置きます。具体的な権限の設定は後でやります。

lp creategroup admin
lp creategroup member

memberよりはadminの方が権限を多く持つハズなので、adminはmemberの権限を継承するようにしておきます。

lp group admin parent add member

EssentialXのインストール

discord上での名前とマイクラ上での名前を一致できるようにしたく、/nickコマンドを使えるようにしたいので、EssentialXを入れます(ほかにもいろいろ便利なコマンドがあるらしい)。

EssentialXはいくつかのjarに分かれているそうですが、とりあえずCoreを入れます。

また、EssentialXがPermission系のpluginとやり取りをするのにVaultというプラグインが必要なようです。

最新のjarを/pluginsでwgetすれば大丈夫っぽいです。

EssentialXも同様にlatest releaseのjarを/pluginでwgetします。

この状態でサーバーを起動させると、/plugins/Essentialsが生成されて、その中にconfig.ymlが生成されています。

この段階で一部のコマンドはvanillaのコマンドからEssentialXのものに置き換えられるようですので、LuckPermで許可をする場合、EssentialXのものを指定する必要があります。

今回は、マイクラ内でもマイクラのユーザー名ではなくDiscord上での名前で表示出来るようにしたいので、その辺りの設定をしていきます。基本的にはEssentialXのdisplayNameを使ってusernameを置き換えていきます。

今回変えた部分を抜粋しておきます。

/plugins/Essentials/config.yml
# The character(s) to prefix all nicknames, so that you know they are not true usernames.
# Players with 'essentials.nick.hideprefix' will not be prefixed with the character(s).
nickname-prefix: ''

# Disable this if you have any other plugin that modifies the display name of a player.
change-displayname: true

# This option will cause Essentials to show players' display names instead of usernames when tab completing Essentials commands.
# If your tab completions include prefixes and suffixes, set this option to false.
change-tab-complete-name: true

# When this option is enabled, the (tab) player list will be updated with the display name.
# The value of 'change-displayname' above must be true.
change-playerlist: true

# Set the locale for all messages.
# If you don't set this, the default locale of the server will be used.
# For example, to set the language to English, set locale to 'en'. It will then use the file 'messages_en.properties'.
# Don't forget to remove the # in front of the line.
# For more information, visit https://essentialsx.net/wiki/Locale.html
locale: ja

# You can set custom join and quit messages here. Set this to "none" to use the default Minecraft message,
# or set this to "" to hide the message entirely.
#
# Available placeholders:
# {PLAYER} - The player's display name.
# {USERNAME} - The player's username.
# {PREFIX} - The player's prefix.
# {SUFFIX} - The player's suffix.
# {ONLINE} - The number of players online.
# {UNIQUE} - The number of unique players to join the server.
# {UPTIME} - The amount of time the server has been online.
custom-join-message: "{PLAYER} joined the server"
custom-quit-message: "{PLAYER} left the server"

権限の設定

とりあえず今回は、/me/nickを全員使えるようにしました(paperMCを起動したサーバーのコンソールで実行)

lp group {group name} permission set essentials.me true
lp group {group name} permission set essentials.nick true

他どういう権限が必要か正直わからないので、この辺は遊ぶ人に聞こうと思っています。
あと、本当はサーバーに入った人を自動的にmember groupに追加するようにできないかと思いましたが、調べるのが面倒なこともあり、defaultにmember権限を継承させました。いい方法あれば教えてください。

mcrconのインストール

Minecraftのサーバーアプリケーションに外からコマンドを送るためにMCRconをinstallします。これはシステムディレクトリにインストールするので一度exitしてsudo権限のあるユーザで行います。どうもパッケージレジストラにあるのは古いっぽいので、Github repoの説明に従ってLXC内でbuildします。

systemdで管理する

今回のサーバー自体はsystemdで管理しようと思います。色々と楽なので。
以下のようなsystemdのConfig fileを/etc/systemd/system内にminecraft.serviceとして作成します。

minecraft.service
[Unit]
Description=Minecraft Server (PaperMC)
After=network.target

[Service]
Type=simple
User=minecraft
Group=minecraft
WorkingDirectory=/home/minecraft
ExecStart=/usr/bin/java -Xms6656M -Xmx6656M -jar paper-1.21.8-31.jar --nogui
ExecStop=/bin/bash -c '/usr/bin/mcrcon -H 127.0.0.1 -P 25575 -p "mcrcon_password" stop || true'
TimeoutStopSec=60
Restart=always
RestartSec=10
StandardInput=null
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

サーバーを公開する

最初はcloudflare tunnelで行けるかと思いましたが、どうも無理っぽいとなり、

次に自宅のルーターでポートフォワーディングするかとなりましたが、ISPのルーター(PR-500KI)がロックされており出来ず(Cloudflare APIで自宅IPを動的にDNSに設定する所までやったのに!)

結局、playit.ggというサービスを使う事にしました。

このサービスは多くのマイクラサーバーで使われているようで、一旦これで行こうという事にしました。無料でTCP及びUDPのトンネリングができ、マインクラフト用の設定もあります。

まずアカウントを作り、ダウンロードページのダウンロードスクリプトを実行して、systemdで起動します。

sudo systemctl start playit
sudo systemctl enable playit

サーバー側でplayit setupとすると、サーバーにtoken?付きのURLが出るので、それをwebで開くと接続が完了します。

あとはdashboardでtunnelを2つ設定すると、publicなURLが発行されます。

2026/01/20 追記

バックアップについて

これはもっと前に実装してたのですが、Qiitaを更新していなかったので、書いておきます。
バックアップはほぼユーザーがいないであろう午前4時に自動でサーバーを落として、同じLXC内に保存することにしました。本当に失ってはいけないデータなら、object storageにいれるべきですが、そこまでするのは面倒だな....ということで、一旦こうしました。

バックアップに使用したのはResticというソフトウェアです。これはバックアップを指定しているファイルのうち、変更があったファイルだけを更新してくれます。
Restic自体は外部のobject storageにも対応しているので、いざとなればそちらにデータをuploadすることもできます。

バックアップは以下のようなbashファイルを作成して、バックアップ前後にDiscordとサーバー内に連絡を流すようにしました。

minecraft-backup.sh
#!/bin/bash
# Configuration (edit these values)
RCON_HOST="localhost"
RCON_PORT="{your port}"
RCON_PASSWORD="{your password}"
MINECRAFT_SERVICE="minecraft"
BACKUP_REPO="{バックアップの保存先}"
MINECRAFT_DIR="/home/minecraft"

# Send mcrcon command (ignore failures)
mcrcon_send() {
    mcrcon -H "$RCON_HOST" -P "$RCON_PORT" -p "$RCON_PASSWORD" "$1" 2>/dev/null
}

echo "Starting backup process..."

# 5-minute notice
mcrcon_send "say [システム] 5分後にバックアップのためサーバーを再起動します"
sleep 240

# 1-minute notice
mcrcon_send "say [システム] 1分後に再起動します。安全な場所に移動してください"
sleep 50

# Final notice
mcrcon_send "say [システム] まもなく再起動します..."
sleep 10

# Stop server
echo "Stopping server..."
systemctl stop "$MINECRAFT_SERVICE"
sleep 5

# Backupを取るファイルの一覧
echo "Creating backup..."
restic -r "$BACKUP_REPO" --password-file /usr/local/bin/repo.pass backup \
  "$MINECRAFT_DIR/world" \
  "$MINECRAFT_DIR/world_nether" \
  "$MINECRAFT_DIR/world_the_end" \
  "$MINECRAFT_DIR/server.properties" \
  "$MINECRAFT_DIR/bukkit.yml" \
  "$MINECRAFT_DIR/spigot.yml" \
  "$MINECRAFT_DIR/config" \
  "$MINECRAFT_DIR/plugins" \
  "$MINECRAFT_DIR/ops.json" \
  "$MINECRAFT_DIR/whitelist.json" \
  "$MINECRAFT_DIR/banned-ips.json" \
  "$MINECRAFT_DIR/banned-players.json" \
  "$MINECRAFT_DIR/permissions.yml" \
  --tag "backup-$(date +%Y%m%d_%H%M%S)" \
  --exclude="plugins/*.jar" \
  --exclude="plugins/*/cache/" \
  --exclude="plugins/dynmap/web/tiles/" \
  --exclude="plugins/*/temp/" \
  --exclude="plugins/*/logs/"

BACKUP_RESULT=$?

# Start server
echo "Starting server..."
systemctl start "$MINECRAFT_SERVICE"
sleep 30

# Completion notice
if [ $BACKUP_RESULT -eq 0 ]; then
    mcrcon_send "say [システム] バックアップ完了!サーバー再開しました"
    echo "Backup completed successfully"

    restic -r "$BACKUP_REPO" forget --keep-daily 15 --prune
else
    mcrcon_send "say [システム] バックアップでエラーが発生しました"
    echo "Backup failed"
fi

exit $BACKUP_RESULT

これを毎日定期実行するのに /etc/systemd/systemに、mc-restic.serviceというサービスファイルとmc-restic.timerというタイマーのファイルを作成しました。

mc-restic.service
[Unit]
Description=Minecraft restic backup (stop server, backup, start server)
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/minecraft-backup.sh
mc-restic.timer
[Unit]
Description=Run mc-restic.service daily at 04:00

[Timer]
OnCalendar=*-*-* 04:00:00
Persistent=true

[Install]
WantedBy=timers.target

これで

sudo systemctl enable mc-restic.timer

とすればタイマーが有効になり、毎日朝4時に実行されます。

Java版とBedrock版の両方を持つユーザーのアカウントの取り回しについて

この項目はまだ対応できてません。今後追記します

最初にBedrock版で参加し、DiscordSRVでの認証を通ったユーザーが、Java版で参加しようとすると、コードの入力を求められるのに、Discord bot側ではすでにLink済みになっている、という事象が発生しました。

これは、一番の根本の原因はBedrock版とJava版でID体系が異なる、という事でした(Bedrock版はXUID、Java版はUUID)。そのため、DiscordSRV的には、知らないUUIDのユーザーがアクセスしてきたが、DiscordのユーザーIDは既に登録されている、となり、どうにもならなくなっていたようです。

GeyserMCにはこのあたりを解決するための仕組みとして、Linkingが用意されているようです。

ただし、まだ2点ほど大きな問題が残ります。

  1. DiscordSRVでRequire linked account to playを有効にしていると、1Discordアカウントにつき1マイクラアカウントとなり、後から紐づけたいアカウントでサーバー接続ができずlinkingが出来ない
  2. Bedrockのユーザーを、Java版のIDに付け替えて接続するという仕組みなので、既にBedrockで遊んでいた場合、リンク後にBedrock版のデータにはアクセスできなくなる

(書きかけ)

バージョンアップについて

ずっと1.28.1で運用してきてたのですが、バージョンアップを放置していて、Bedrock版の人が参加できなくなっていました。そこで、1.21.8から1.21.11へのupdateを行います。

基本的にはPaparMCのドキュメントに従うだけですが、以下自分が行った手順を記しておきます。

まずは/home/minecraft/plugins/updateフォルダを作成します。このupdateフォルダはPaperMCが勝手に起動時に読み取るので、マイクラ鯖を動かしているユーザーの権限にしておいた方が良さそうな気がします。

sudo -u minecraft mkdir /home/minecraft/plugins/update

現在入れているpluginを調べて、どのpluginが最新版が出ているかを調べました。見た所、最新版のリリースがあったのは、

  • GeyserMC
  • floodgate
  • luckperms
  • DiscordSRV

でした(essentialXのみリリース無し)。従ってこれらの最新のjarを作成したupdateにダウンロードしていきます。この時のwgetもminecraftユーザーでやりました。

sudo -u minecraft wget https://download.luckperms.net/1612/bukkit/loader/
LuckPerms-Bukkit-5.5.24.jar

sudo -u minecraft wget https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot
sudo -u minecraft mv spigot Geyser-Spigot.jar

sudo -u minecraft wget https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot
sudo -u minecraft mv spigot floodgate-Spigot.jar

sudo -u minecraft wget https://github.com/DiscordSRV/DiscordSRV/releases/download/v1.30.4/DiscordSRV-Build-1.30.4.jar

これでpluginは全部download出来たので、次にpaperMC自体の最新のjarをhome/minecraft/にダウンロードします。

 sudo -u minecraft wget {paperMCのページから取ってきたURL}

で、次の定期再起動時に自動で使用するjarが切り替わって欲しいので、minecraft.service内の

minecraft.service
 ExecStart=/usr/bin/java -Xms6656M -Xmx6656M -jar paper-1.21.8-31.jar --nogui

のバージョン部分を新しいものに変えます。

minecraft.service
 ExecStart=/usr/bin/java -Xms6656M -Xmx6656M -jar paper-1.21.11-98.jar --nogui

その後

sudo systemctl daemon-reload

して、serviceファイルの変更が反映されるようにします。
因みにこの結果、バージョンは正しく上がったものの、geyserMCが最新版のBedrockに対応していないという事態が発生しました。geyserのDiscordにも入ってみたりしましたが、ちょくちょくgeyserのupdateをしていたら治りました。まぁ、geyserもOSSのprojectですから、公式のupdateからのタイムラグはあるようですね。

問題なく動作するようになったら、過去のpapermcのjarは消しておきましょう。

感想

最初自宅のLAN内に建てた時は「簡単やーーん」となりましたが、アレもコレもとやっているうちにどんどん大変になり時間もかかりました。あれ、この感じ、なんか色んな所でやってるな....って思いました。実際の進捗率が飽和関数なのに、自分の体感の進捗率は一次関数的に伸びてくのが良くないですね。うーん..........。

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?