1台のサーバーで、複数グループ分のMinecraft Educationワールドを同時運用するためのDocker構成です。
前提: 公式ドキュメントに記載のサーバー構築手順(デバイスコード認証・管理ツールによる有効化など)を理解していることを前提としています。
- Dedicated Server FAQ
- Dedicated Server Alternate Configuration(Tooling and Scripting Notebook)
cp .env.example .env.env を編集して最低限以下を設定します。
SERVER_PUBLIC_IP_LAN=192.168.1.100 # LAN 内からの接続先IP(必須)
# SERVER_PUBLIC_IP_WAN=example.com # LAN 外から接続させる場合のみ設定LAN 内用と LAN 外用のアドレスを両方定義しておき、ワールドごとに SERVER_NETWORK_WORLD_N=wan のように指定すれば、どちらの接続先を広告するかをワールド単位で切り替えられます(未指定なら SERVER_NETWORK_COMMON、それも無ければ lan)。
その他の設定は _COMMON 項目で全ワールドのデフォルト値を一括設定できます。個別ワールドで上書きしたい場合は _WORLD_1 のように指定します。
優先順位: 個別設定(
_WORLD_N)> 共通設定(_COMMON)> デフォルト値
make add # ワールド1(帯 19200-19299)
make add # ワールド2(帯 19300-19399)ポートは自動採番されます。 1ワールドが連続した100ポートの帯を占め、先頭がシグナリング、残り99本が nethernet のゲーム通信用になります(理由は下記「トランスポートとポート」)。ワールド番号・ポート・UDP 範囲がすべて .env に自動追記されます。
make ports # 割り当て一覧と、次に使えるポートを表示
make add PORT=19500 # ポートを明示したい場合(100の倍数で指定)ポート番号の注意:
- 自動採番は 19200 から始まり、既存の帯を跨がない次の100境界を選びます(開始値は
MakefileのPORT_BASE)。PORT=を明示する場合は100の倍数にしてください(make addが拒否します)。帯の境界を揃えないと隣のワールドの帯に食い込みます。- 同一ホスト上のワールドには必ず別々のポートを割り当ててください。同じポートで2つ起動すると、参加者側に「無効なテナントID(Invalid Tenant ID)」エラーが出ます。
- 先頭の番号は UDP と TCP の両方で公開されます。
transport=nethernetのワールドでは、残り99本も UDP で公開されます。ルーターやファイアウォールには**帯ごと(例: 19200-19299/udp)**を開けておけば足ります。- 既定ポート(19132)を避けるという公式の推奨にも、この採番は合致しています。
.env の TRANSPORT_COMMON で接続方式を選べます。.env.example の既定は nethernet です。RakNet は将来のバージョンで削除される見込みのため、新規構築は NetherNet から始める想定にしています。既存環境で確実に動かしたい場合は raknet に変更してください。
補足:
.envにTRANSPORT_COMMONの行自体が無い場合はraknetで動きます(compose テンプレートのフォールバック)。既存環境を更新したときに、意図せず方式が切り替わらないようにするためです。
raknet |
nethernet(.env.example の既定) |
|
|---|---|---|
| 方式 | 従来の Bedrock UDP トランスポート | WebRTC ベース |
server-port |
UDP で直接待ち受け | TCP(HTTP シグナリング用のデュアルスタックソケット) |
| ゲーム通信 | 同じ UDP ポート | クライアントごとにネゴシエートされる UDP |
| 必要な公開ポート | UDP のみ | TCP(シグナリング)+ UDP(ゲーム通信) |
nethernet のゲーム通信は、既定では OS のエフェメラルポートから確保されるため、そのままでは Docker で公開できません。そこで server-udp-ports で範囲を固定し、クライアントへ広告する外部アドレスも宣言します。
ここが重要な点で、NetherNet はプレイヤー1人が参加するごとに UDP ポートを1つ確保します。プレイヤーが自宅で世界をホストする P2P 実装をそのまま流用しているためです。単一ポートを指定すると内部的に min=max となり、同時1接続しか受け付けられません(1人目は入れてしまうので、2人目が入れないまで気づけません)。
そのため本リポジトリでは、1ワールド = 連続した100ポートの帯として割り当てます。
| 用途 | 設定 | 例(最初のワールド) |
|---|---|---|
| シグナリング | SERVER_PORT_WORLD_N(TCP。raknet では UDP) |
19200 |
| ゲーム通信 | SERVER_UDP_RANGE_WORLD_N(UDP 範囲) |
19201-19299(99本) |
ポートは100飛ばしで採番されるので、UDP 範囲は常にその直後の99本になり、帯どうしが重なることが原理的にありません。ファイアウォールや VPS の転送設定も、ワールドあたり 19200-19299/udp の1ルールで済みます。99本は max-players=40 に対して十分な本数です。
make ports # 割り当て一覧と、次に使えるポートを表示
make check-ports # ポート重複・UDP 範囲の未設定を検査(up / restart / build 前に自動実行)帯の幅は Makefile の PORT_BLOCK、make ports の提案開始値は PORT_BASE で変えられます。ただしこの帯は VPS の iptables 転送やクラウドのセキュリティリストにも登録することになるため、一度決めたら変えない運用を前提にしています。また Linux の既定エフェメラルポート帯(32768-60999)と重なる番号は避けてください(公式 how-to の例 49152-49200 はこの帯の内側にあり、ホスト上の他プロセスと衝突しえます)。
compose が公開する UDP 範囲の行は、transport=nethernet のワールドにだけ make sync が出力します(raknet のワールドで使わない 100 ポートを公開しないため)。.env の TRANSPORT_WORLD_N を変えたら make up を実行すれば再生成されます。
ホスト側の設定: 範囲公開では Docker が1ポートごとに iptables ルール(userland proxy 有効時は
docker-proxyプロセスも1つずつ)を作るため、ポート数が増えると起動が遅くなります。/etc/docker/daemon.jsonに{"userland-proxy": false}を設定すると iptables DNAT のみになり、コストが大幅に下がります。
補足:
raknetではenable-lan-visibility=true(デフォルト)のため、サーバーは LAN 探索用に UDP 19132 も内部でバインドします。各ワールドは独立したコンテナ内で動くのでホスト側の衝突は起きません。インターネット公開時: 公式 how-to では、
nethernetのシグナリングが HTTP/TCP であることから、server-portの前段にリバースプロキシ(nginx 等)を置いてレート制限を行うことを推奨しています。ゲーム通信そのものは UDP で直接流れるため、プロキシを通す必要があるのはシグナリングだけです。なお iOS 系クライアントはシグナリングポートに TLS で接続しますが、サーバー側は平文 HTTP を話すため、LAN 外からの接続が失敗する事例が報告されています(BDS-23108)。この場合は Caddy / nginx で TCP 側を TLS 終端する必要があります。この構成はまだ本リポジトリに含まれていません。
make upサーバーバイナリは起動時に自動でダウンロードされます。server/bedrock_server_edu に手動配置するとダウンロードをスキップします。
初回起動時にログ(logs/world{N}/)にデバイスコードとURLが出力されます。ブラウザでそのURLを開き、テナントのグローバル管理者アカウントでサインインしてください。
テナント設定で「Allow Teachers to Manage Servers」が有効な場合は、教員(Faculty)アカウントでもサーバーの作成・認証ができます。ただしテナント側の Dedicated Server 有効化そのものは、グローバル管理者しか行えません。
サインイン後に sessions/world{N}/edu_server_session.json が生成され、以降は自動更新されます。
Dedicated Server Admin Portal でサーバーの Enabled をオンにしてください(オフのままでは誰も参加できません)。
Broadcast は任意です。
- オン: テナント内の全ユーザーのサーバー一覧に自動表示されます(ユーザー側から一覧を削除することはできません)。
- オフ: ユーザーがクライアントの「サーバーを追加」から、12桁の英数字(大文字小文字の区別なし)のサーバーIDを手入力して参加します。
Windows の場合: Docker Desktop は WSL2 上で動作するため、WSL2 のターミナル(Ubuntu 等)で実行してください。
permission denied while trying to connect to the Docker daemon socketになる場合: 実行ユーザーがdockerグループに属していません。以下で追加し、一度ログアウトして入り直してください。sudo usermod -aG docker $USER # 再ログイン後に有効
make: command not foundになる場合(NAS 等): Docker デーモンへの接続に root 権限が必要で、かつmakeが sudo のPATHに含まれていない環境では、以下のように現在のPATHを引き継いで実行してください。sudo env "PATH=$PATH" make up
# 本番運用
make up NOTIFY=true BACKUP=true # 全ワールド + 通知 + 自動バックアップ
# 起動オプション
make up # 全ワールドのみ起動
make up WORLDS="1 2" # 指定ワールドのみ起動
make up NOTIFY=true # 通知スタックも一緒に起動
make up BACKUP=true # バックアップサービスも一緒に起動
# その他
make build # イメージを再ビルド
make down # 全ワールドを停止
make restart # 全ワールドを再起動
make logs N=1 # ワールド1 のログを表示
make ps # 全コンテナの状態を表示
make backup # 今すぐ手動バックアップ
make add # 新しいワールドを追加(ポート・UDP 範囲を自動採番)
make add PORT=19500 # ポートを明示して追加(100の倍数)
make ports # ポート割り当てと次に使えるポートを表示
make check-ports # ポート重複・UDP 範囲の未設定を検査(up 時に自動実行)
make dirs # マウント先ディレクトリを作成(up 時に自動実行)設定ファイルを更新したときは再ビルドが必要:
property-definitions.json/entrypoint.sh/Dockerfileはビルド時にイメージへ COPY されるため、これらの変更(新バージョン対応の取り込みなど)を反映するにはイメージの再ビルドが必要です。make build # イメージを再ビルド make down make upなお Minecraft サーバーバイナリ自体は起動時に自動更新されるため、バイナリのバージョンアップだけであれば再ビルドは不要です(再ビルドが必要なのは上記リポジトリ側ファイルを変更した場合)。
コンテナはホストの実行ユーザーと同じ UID で動きます(make が id -u / id -g の値を自動で渡すため、設定は不要です)。ホスト側ディレクトリがその UID で書き込めないと、ログもワールドデータも保存できず、サーバーバイナリも毎回ダウンロードし直しになります。
症状の確認:
docker logs --tail 30 minecraft-edu-world1 # Permission denied が出ていないか
ls -ld worlds/world1 logs/world1 server # 所有者が root になっていないか
docker exec minecraft-edu-world1 id # コンテナ実行ユーザーの UID対処: 所有者を自分(make を実行するユーザー)に揃えます。
make down
sudo chown -R $(id -u):$(id -g) worlds sessions logs chat_logs server
make up
sudo make upでは解決しません。sudoが影響するのは docker クライアントの実行権限までで、コンテナ内のプロセスは常にPUIDのユーザーとして動作するためです。
この問題は、worlds/ などが存在しない状態で docker compose up すると Docker デーモン(root)がマウント元ディレクトリを root 所有で作成してしまうために起きます。現在は make up / restart / build が実行前に make dirs でディレクトリを作成するため、新規環境では発生しません。
なお、この問題が出るのは Linux ホストのみです。Docker Desktop(Windows / macOS)は VM 経由のバインドマウントが UID を無視し、NAS も共有フォルダのパーミッションが緩いため表面化しません。
以前のバージョンはコンテナ実行ユーザーが UID 999 固定でした。更新後はホストの実行ユーザーと同じ UID になるため、一度だけ所有者を移し替えてイメージを再ビルドしてください。
make down
sudo chown -R $(id -u):$(id -g) worlds sessions logs chat_logs server
make build
make up所有者がホストの自分のユーザーになるため、以降はビヘイビアパックの配置やワールドデータのバックアップに sudo が不要になります。
別の UID で動かしたい場合(共有サーバーで専用アカウントを使う等)のみ、
.envにPUID=/PGID=を書けばそちらが優先されます。変更後はmake buildが必要です。
Makefile # ワールドの起動・追加コマンド
docker-compose.world{N}.yml.example # ワールド定義テンプレート(make add が使用)
docker-compose.notify.yml # 通知スタック(Vector + Apprise)
docker-compose.backup.yml # 自動バックアップ(make up BACKUP=true)
Dockerfile / entrypoint.sh # コンテナ定義
property-definitions.json # 環境変数 → server.properties のマッピング定義
.env.example # 環境変数テンプレート
vector/vector.toml.example # Vector 設定テンプレート
apprise/minecraft.yml.example # 通知先設定テンプレート
docker-compose.world1.yml # make add で生成
docker-compose.world2.yml # make add で生成
.env # .env.example からコピー
worlds/world{N}/ # ワールドデータ
├── worlds/{LEVEL_NAME}/ # ゲームワールドデータ
├── behavior_packs/ # ビヘイビアパック
├── resource_packs/ # リソースパック
├── allowlist.json
├── permissions.json
└── packetlimitconfig.json
sessions/world{N}/ # Entra 認証セッション(自動更新。失効時は再度デバイスコード認証)
logs/world{N}/ # サーバーログ
chat_logs/world{N}/ # チャットログ(CHAT_LOGGING_ENABLED=true のとき出力)
server/ # サーバーバイナリ手動配置用(省略可)
プレイヤーの参加/退出・チャット・サーバーイベントを ntfy や LINE 等に通知できます。
cp vector/vector.toml.example vector/vector.toml
# vector.toml を編集して ntfy トピック等を設定
cp apprise/minecraft.yml.example apprise/minecraft.yml
# minecraft.yml を編集して通知先 URL を設定(LINE 等)
make up NOTIFY=trueChatLog ファイル(chat_logs/world{N}/)を監視し、[日時] - で始まる行をすべて通知します。
前提: ChatLog ファイルはサーバー本体の機能(
chat-logging-enabled、1.21.133 以降)で出力されます。.envのCHAT_LOGGING_ENABLED_COMMON=true(既定値)が必要です。この設定はあとから変更できますが、反映にはサーバーの再起動が必要です。
- 公式ドキュメント(Servers セクション)
- Dedicated Server FAQ
- Dedicated Server System Requirements
- IT Admin: Create Dedicated Servers
- Teacher View: Create Dedicated Servers
- Dedicated Server Alternate Configuration
- Modifying Existing Servers(
server.propertiesの各項目一覧) - Dedicated Server Advanced Setup(allowlist・パスコード)
- Enabling Cross-Tenant Play(他テナントからの参加。本構成では未検証)
リポジトリのコード: PolyForm Noncommercial 1.0.0(非商用利用のみ許可)
Minecraft Education Edition サーバーバイナリの利用は Microsoft の利用規約に従います。