リソースパックのセルフホスト
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はMinecraftのマルチパックAPIを使うため、そのJavaパックはサーバーが送る他のパックと共存できます。現在のBukkitプラグイン記述子はMinecraft 1.21.4以降を要求します。
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 にしてリモートフォールバックを使うか、携帯回線などの外部ネットワークから公開URLをテストしてください。恒久的なセルフホスト構成にするなら、スプリットホライズンDNS(同じ公開ホスト名が、ネットワーク内部ではサーバーのLANアドレスに解決される)を使ってください。selfHostExternalHost を 127.0.0.1 に設定してはいけません:ループバックやプライベートホストは公開ホストの健全性チェックで拒否され、外部クライアントには配信できません。
ポート解決
2つの設定が相互作用します:
selfHostPort— 明示的なポート(任意の正の整数)または自動導出のための-1(既定)。networkHttpOffset-v2—selfHostPort = -1のときだけ参照されます。Minecraftサーバーポートに加算してHTTPポートを導出します。既定1。(プロキシネットワークでは、この同じ値がバックエンドのHTTPポートに対するプロキシのフォールバック推測にもなります — 下記参照。)
既定は selfHostPort: -1 + networkHttpOffset-v2: 1 なので:
- MCポート 25565 → HTTPポート 25566
- MCポート 25584 → HTTPポート 25585
これにより、単一ホストのネットワーク上で管理者設定なしにバックエンド間で自動的にHTTPポートが千鳥配置になります — 各バックエンドにはすでに固有のMCポートがあるので、各バックエンドは固有のHTTPポートを得ます。
なぜオフセット1なのか?
ほとんどの共有/マネージドMinecraftホスティング(Pterodactylベースのパネルなど)は、コンテナごとに狭いポート範囲(多くは4〜10ポート)しか割り当てません。大きいオフセットは範囲外に着地し、ホストファイアウォールがHTTPポートをサイレントにブロックします。オフセット1ならタイトな割り当てでも収まります。
完全なポート制御を持つセルフホスト管理者はこれを任意の値にバンプできます。プロキシネットワークでは、バックエンドが実際にバインドした正確なHTTPポートをプロキシへ自動通知するため、オフセットを変更したり明示的な selfHostPort を設定したりしても、プロキシはそれに追従します。プロキシの 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の検出が完全にスキップされ、プローブは明示的な値に対して実行されます。
設定リファレンス
# Whether the built-in HTTP server may be used as a delivery path at all.
# When false, ordinary self-host attempts are disabled. selfHostForce still overrides it.
selfHostEnabled: true
# Port for the self-host HTTP server.
# -1 (default) = auto-derive: HTTP port = Minecraft server port + networkHttpOffset-v2.
# Set to any positive value to force an explicit port.
selfHostPort: -1
# Added to the Minecraft server port when selfHostPort = -1.
# Default 1 (MC 25565 -> HTTP 25566). On a proxy network this is only a FALLBACK:
# the backend announces the exact HTTP port it actually bound to the proxy, so
# you no longer have to match this against the proxy's network-http-offset-v2.
networkHttpOffset-v2: 1
# Public hostname or IP clients use to reach the self-host server.
# Leave empty for auto-detect (api.ipify.org / checkip.amazonaws.com).
selfHostExternalHost: ""
# Try self-host FIRST with three sanity checks, fall back to remote if any fail.
# When false, use the legacy order: remote upload first, self-host only on upload failure.
preferSelfHost: true
# Skip ALL other delivery paths and force self-hosting.
# Bypasses sanity checks AND remote upload. Mainly for testing.
selfHostForce: false
# Print every step of pack preparation and the hosting handshake.
# Default false — see "What the console actually prints" below.
# `/rspm verbose on|off` flips this same key at runtime and saves it here.
verboseLogging: false
コンソールに実際に出力されるもの
RSPMは通常の起動時、ホスティングについて意図的に1行だけを出力します — 経緯ではなく結果です:
[ResourcePackManager] Resource pack is live via self-hosting — http://play.example.com:25566/rspm.zip
あるいは、リモート経路が選ばれた場合:
[ResourcePackManager] Resource pack is live via automatic hosting — https://magmaguy.com/rsp/<uuid>
この行は、配信経路が新たに初期化されるたびに1回出力されます。プレイヤーの再試行やキープアライブのティックでは出力されません。パックが変わっていないリロードでは、新しい結果を出力する代わりに既存のホスティング登録を再利用できます。
健全性チェックの失敗は警告ではありません。 失敗したプローブはRSPMが自力で回復する状況なので、障害としてではなく詳細情報としてログに記録され、各メッセージがそれを明示します(Self-host check: local pack link is not public. This is OK.)。求めない限り目にすることはありません — プラグインが既に処理済みのことを警告すると障害のように読まれ、オペレーターに存在しない問題を追わせてしまいます。
判断の連鎖全体 — どのチェックが失敗したか、プローブURL、理由コード、ステージングされた各パックとマージされた各クラスター — を見るには、次を実行します:
/rspm verbose on
そして /rspm reload を実行します。ホスティングに関するバグ報告を出す前に入れるべきスイッチです。このコマンドは config.yml に verboseLogging: true を書き込み、設定は再起動をまたいで保持されるため、終わったら /rspm verbose off を実行してください。設定キーを手で編集しても効果はまったく同じです。
なお verboseLogging はパック準備とホスティングを対象とします。Bedrockコンバーターには別途 bedrockConverterDebug という専用スイッチがあります — Bedrock変換を参照してください。
バックエンドHTTPサーバーのルート
組み込みHTTPサーバーは常にパックzipを次の場所で提供します:
http://<host>:<port>/rspm.zip
ネットワークモード(RSPMがVelocity/BungeeCord/Waterfallプロキシの背後にある)では、プロキシプラグインが取得するための追加のルートが登録されます:
http://<host>:<port>/bedrock.zip # the Bedrock-converted pack
http://<host>:<port>/mappings.json # the Geyser custom-mappings JSON
http://<host>:<port>/rspm-update.jar # the universal RSPM update jar (authenticated)
パックとBedrock成果物のルートはファイルバックです:各ルートはリクエストごとにファイルを新しく読むので、同じパスを書き換える再ミックスはHTTPサーバーを再起動することなく自動的に取り込まれます。Bedrockのルートは強いETagを使い、互換性のために If-Modified-Since もサポートするため、何も変わっていないときのプロキシのポーリングは 304 を受け取り、帯域コストはほぼゼロです。これらのルートは、裏にあるファイルが存在しないとき(例:最初のミックスが完了する前)にきれいに404を返します。アップデート用のルートは、共有ネットワークキーから導出されたベアラートークンで別途保護されており、有効なアップデートjarを提供できる場合にのみ利用可能になります。
セルフホストが有効か確認する
/rspm status には次が表示されます:
Active delivery: SELF-HOSTED— セルフホストが使用中Active delivery: REMOTE (magmaguy.com)— リモート自動ホストが使用中URL: ...— クライアントが実際に見るURLResolved external host—selfHostExternalHostが何に解決されたかPublic IP (auto-detected)— ipify/AWS が何を返したか(あれば)selfHostPort— 自動か明示か、および解決された値
セルフホストを期待していたのにリモートになっている場合は、/rspm status を見てください — 起動ログは設計上、自己修復されたプローブ失敗について沈黙します。どの健全性チェックがなぜ失敗したかを見るには、/rspm verbose on と /rspm reload を実行してください。
よくある間違い
- ヘアピンが壊れているルーターでLayer 3プローブを信用する — プローブは magmaguy.com の視点から実行されるため、外部クライアントは動作するがオペレーター自身のLANがループバックしないケースを捕捉できません。確信がない場合は、携帯電話のセルラー回線からテストしてください。
networkHttpOffset-v2をホスティングプロバイダーのポート範囲を超えてバンプする — 症状は、プロキシ側でサイレントなCONNECT_FAILEDが永遠に続く、というものです。バックエンドは実際にバインドしたポートをプロキシに通知しますが、HTTPサーバーは依然として到達可能なポートにバインドする必要があり、プロキシも依然としてそこに到達できる必要があります。mcPort + offsetがコンテナの割り当てポート帯域の外に着地すると、通知の有無にかかわらずバインド/ファイアウォールが失敗します。オフセットを上げる前に、そのポートがコンテナの割り当て帯域内にあることを確認してください。