リソースパックのセルフホスト
ResourcePackManagerは自前の小さなHTTPサーバーを同梱しています。autoHost: true(既定)と preferSelfHost: true(既定)の場合、プラグインはマージされたパックをMinecraftサーバーと同じJVMからホストしようとします — 外部ファイルホストも、別のWebサーバーも、手動でのURL貼り付けも不要です。
このページでは、そのセルフホスト経路がどう動くか、健全性チェックが何をするか、ポートとホスト名がどう選ばれるか、既定では合わないセットアップのときに何を設定すればよいかを説明します。
代わりに、RSPMの外部で自前の既存Webサーバー経由でzipをホストしたい場合は、トラブルシューティングの autoHost: false のセクションを参照してください。
配信判定ツリー
プレイヤーが参加したとき、RSPMは次の優先順位で配信URLを選びます:
selfHostForce: true— まっすぐセルフホストへ。プローブもリモートアップロードもなし。主にセルフホスト経路のテスト用です。他のすべてのフラグをバイパスします。preferSelfHost: trueかつselfHostEnabled: trueかつネットワークモードでない — 3つの健全性チェック(後述)を伴うセルフホストを試します。すべて通ればセルフホストに確定します。いずれかが失敗すれば、リモート経路にフォールバックします。- それ以外 — パックを
https://magmaguy.com/rsp/にアップロードし、そのURLを通知します。アップロードが失敗するか、SHA1チェックがSESSION_NOT_FOUNDを報告した場合、セルフホストにフォールバックします(selfHostEnabled: trueを前提)。
URLが手に入ると、RSPMは1.20.3以降では Minecraft のマルチパックAPI(他のサーバー送信パックと共存するため)を、それより古いバージョンでは従来の単一パック方式を使います。
3つの健全性チェック
preferSelfHost: true のとき、RSPMはセルフホストにコミットする前に次のチェックを順番に実行します:
Layer 1 — 解決された外部ホストのヒューリスティックチェック
解決されたホスト(後述の「外部ホスト検出」を参照)がRFC1918(10.*、172.16-31.*、192.168.*)、ループバック(127.*)、リンクローカル(169.254.*)、または未指定(0.0.0.0)の場合、セルフホストはインターネット上のクライアントに対しては動作しようがありません。即座にスキップしてリモートホスティングを使用します。
これはとてもよくある「ipify検索に失敗して、LAN IPにフォールバックした」失敗モードを捕捉します。
Layer 2 — localhostセルフプローブ
http://127.0.0.1:<port>/rspm.zip への HEAD リクエストを開き、HTTP 200と非空ボディを検証します。以下を捕捉します:
- ポートバインドの衝突(選んだポートに他のものがいる)
- パックファイルの欠落(ルートは登録されているがzipがまだディスクにない)
- ルート登録のバグ
積極的にタイムアウトする(3秒)ため、遅いプローブが起動を長引かせることはありません。
Layer 3 — 外部到達性プローブ
通知されたURLを magmaguy.com ホスターの POST /rsp/probe にPOSTします。ホスターは公開された視点からそのURLを取得し(SSRFガードとタイトなタイムアウト付き)、到達可能だったかを報告します。
これは本番で最もよくある失敗モードを捕捉します:サーバーは公開IPを持っているが、HTTPポートがルーターやファイアウォールで転送されていない、というケースです。Layer 2は通る(サーバーは 127.0.0.1 で応答する)が、本当のクライアントはパックをダウンロードできません。
プローブ結果に対する判定ポリシー:
- reachable=true → 外部クライアントが私たちのURLに到達できます。セルフホストにコミットします。
- reachable=false → 外部クライアントは到達できません。セルフホストをティアダウンし、リモートホスティングを使用します(これは magmaguy.com から普遍的に到達可能です)。
- プローブ通信自体が失敗(IOException) → どちらでもないので検証できませんでした。デフォルトでセルフホストを維持します:リモート経路も magmaguy.com を必要とするため、プローブ不能を理由にコミットを拒否するのは矛盾しているからです。
チェックが依然として検出しないもの
NATヘアピンのエッジケース:ポートはパブリックインターネットに開かれていて(Layer 3が通る)、オペレーター自身のルーターはLAN内部からのトラフィックをループバックしません。外部クライアントは動作しますが、同じマシンからテストしているオペレーターは失敗します。
当面の回避策:ヘアピンが壊れているルーター環境のホストマシンからテストするときは、preferSelfHost: false または selfHostExternalHost: 127.0.0.1 に設定してください。
ポート解決
2つの設定が相互作用します:
selfHostPort— 明示的なポート(任意の正の整数)または自動導出のための-1(既定)。networkHttpOffset-v2—selfHostPort = -1のときだけ参照されます。Minecraftサーバーポートに加算されます。既定1。
既定は selfHostPort: -1 + networkHttpOffset-v2: 1 なので:
- MCポート 25565 → HTTPポート 25566
- MCポート 25584 → HTTPポート 25585
これにより、単一ホストのネットワーク上で管理者設定なしにバックエンド間で自動的にHTTPポートが千鳥配置になります — 各バックエンドにはすでに固有のMCポートがあるので、各バックエンドは固有のHTTPポートを得ます。
なぜオフセット1なのか?
ほとんどの共有/マネージドMinecraftホスティング(Pterodactylベースのパネルなど)は、コンテナごとに狭いポート範囲(多くは4〜10ポート)しか割り当てません。大きいオフセットは範囲外に着地し、ホストファイアウォールがHTTPポートをサイレントにブロックします。オフセット1ならタイトな割り当てでも収まります。
完全なポート制御を持つセルフホスト管理者はこれを任意の値にバンプできますが、プロキシネットワークを運用している場合は、プロキシの network-http-offset-v2 も必ずそれに合わせてバンプする必要があります。
注意:RCONとの衝突
ホスティングが既定でRCONを MCポート + 1 で有効化している場合、ポート衝突を避けるためオフセット2または3を選んでください。server.properties の rcon.port= を確認してください。
バージョン管理された設定キー
config.yml の設定は文字どおり networkHttpOffset-v2 という名前です。v1キーは networkHttpOffset で既定100でした — その既定は、各ゲームコンテナが連続するポートを ~4〜10 個しか得られない共有/マネージドホスティングで壊れ、MC + 100 が範囲外に落ち、HTTPサーバーは内部でバインドされるがホストファイアウォールが外部トラフィックを落とし、プロキシはサイレントなCONNECT_FAILEDを永遠に受け取る、というものでした。v2は既定 1 で出荷され、MC + 1 は最も狭いコンテナ割り当ての内側に十分留まります。
v1からアップグレードする場合、死んだv1キーは手動でクリーンアップするまで設定ファイルに無害な遺物として残ります — RSPMは意図的にそれを読みません。
外部ホスト検出
selfHostExternalHost はクライアントがURLで見るホスト名を制御します。空(既定)のままにすると、次の優先順位で自動検出します:
- api.ipify.org / checkip.amazonaws.com — このホストの公開IPv4を返します。
/rspm reloadごとに1回キャッシュされるので、IPサービスを叩きすぎることはありません。 Bukkit.getIp()— サーバーのバインドアドレス。非空かつ0.0.0.0でない場合に使用されます。通常はLANアドレスです。InetAddress.getLocalHost()— ベストエフォート。localhost— 最終フォールバック。ボックスの外のクライアントはここに到達できません。
自動検出がルーティング不可なアドレスに着地し、preferSelfHost: true の場合、Layer 1のヒューリスティックチェックが失敗し、プラグインはリモートホスティングに切り替えます。
最も信頼できるセルフホストセットアップのためには、selfHostExternalHost を公開ホスト名(例:play.example.com)に明示的に設定してください。これによりipify/AWSの検出が完全にスキップされ、プローブは明示的な値に対して実行されます。
設定リファレンス
# 組み込みHTTPサーバーが配信経路として使用されてよいかどうか。
# false の場合、他のフラグにかかわらずセルフホストは試行されません。
selfHostEnabled: true
# セルフホスト用HTTPサーバーのポート。
# -1(既定)= 自動導出:HTTPポート = Minecraftサーバーポート + networkHttpOffset-v2。
# 任意の正の値を設定すると、明示的なポートを強制します。
selfHostPort: -1
# selfHostPort = -1 のときにMinecraftサーバーポートに加算されます。
# 既定 1(MC 25565 -> HTTP 25566)。プロキシネットワークでは、
# プロキシの network-http-offset-v2 と一致させる必要があります。
networkHttpOffset-v2: 1
# クライアントがセルフホストサーバーに到達するために使用する公開ホスト名またはIP。
# 自動検出のためには空のままにします(api.ipify.org / checkip.amazonaws.com)。
selfHostExternalHost: ""
# 3つの健全性チェックでまずセルフホストを試し、いずれかが失敗したらリモートにフォールバックします。
# false の場合、旧来の順序を使います:まずリモートアップロード、アップロード失敗時のみセルフホスト。
preferSelfHost: true
# 他のすべての配信経路をスキップして、セルフホストを強制します。
# 健全性チェック「と」リモートアップロードをバイパスします。主にテスト用。
selfHostForce: false
バックエンドHTTPサーバーのルート
組み込みHTTPサーバーは常にパックzipを次の場所で提供します:
http://<host>:<port>/rspm.zip
ネットワークモード(RSPMがVelocity/BungeeCord/Waterfallプロキシの背後にある)では、プロキシプラグインが取得するための追加の2つのルートが登録されます:
http://<host>:<port>/bedrock.zip # Bedrock変換されたパック
http://<host>:<port>/mappings.json # Geyserカスタムマッピング JSON
3つすべてのルートはファイルバックです:ルートはリクエストごとにファイルを新しく読むので、同じzipパスを書き換える再ミックスはHTTPサーバーを再起動することなく自動的に取り込まれます。Bedrockのルートは If-Modified-Since をサポートするため、何も変わっていないときのプロキシポーラーの帯域コストはほぼゼロです。すべてのルートは、裏にあるファイルが存在しないとき(例:最初のミックスが完了する前)にきれいに404を返します。
セルフホストが有効か確認する
/rspm status には次が表示されます:
Active delivery: SELF-HOSTED— セルフホストが使用中Active delivery: REMOTE (magmaguy.com)— リモート自動ホストが使用中URL: ...— クライアントが実際に見るURLResolved external host—selfHostExternalHostが何に解決されたかPublic IP (auto-detected)— ipify/AWS が何を返したか(あれば)selfHostPort— 自動か明示か、および解決された値
セルフホストを期待していたのにリモートになっている場合、起動ログにどの健全性チェックが、なぜ失敗したかが説明されています。
よくある間違い
selfHostPortを任意の値に設定し、プロキシでそれを忘れる — ネットワークモードでは、プロキシはmcPort + network-http-offset-v2を使って各バックエンドのHTTPポートを計算します。明示的なselfHostPortは自動導出を上書きしますが、プロキシはそれを知らないので、依然としてmcPort + offsetをポーリングします。調整を覚悟できない場合は、ネットワークモードではselfHostPort: -1のままにしてください。- ヘアピンが壊れているルーターでLayer 3プローブを信用する — プローブは magmaguy.com の視点から実行されるため、外部クライアントは動作するがオペレーター自身のLANがループバックしないケースを捕捉できません。確信がない場合は、携帯電話のセルラー回線からテストしてください。
networkHttpOffset-v2をホスティングプロバイダーのポート範囲を超えてバンプする — 症状は、プロキシ側でサイレントなCONNECT_FAILEDが永遠に続く、というものです。オフセットを上げる前に、mcPort + offsetがコンテナの割り当てポート帯域内にあることを確認してください。