跳到主要内容

自托管资源包

ResourcePackManager 内置了自己的小型 HTTP 服务器。当 autoHost: true(默认)且 preferSelfHost: true(默认)时,插件会尝试在与 Minecraft 服务器同一个 JVM 中托管合并后的资源包——无需外部文件托管服务、无需独立的 Web 服务器、也无需手动粘贴 URL。

本页介绍该自托管路径的工作原理、各项完整性检查的作用、端口与主机名的选择方式,以及当默认设置不合适时该如何配置。

如需在 RSPM 前部署 HTTPS 反向代理并保留自动分发,请使用下文的 selfHostExternalUrl。只有当其他系统同时负责托管和向玩家分发时,才使用 autoHost: false。

分发决策树​

当玩家加入时,RSPM 按以下优先级选择分发 URL:

正常自动分发要求 autoHost: true。当 autoHost: false 时,只有显式设置 selfHostForce: true 才会发送 URL。

  1. selfHostForce: true — 直接尝试自托管,不做探测或远程上传,主要用于测试这条路径。覆盖 autoHost 和 selfHostEnabled,但 URL 验证和 HTTP 监听器启动仍须成功。
  2. preferSelfHost: true 且 selfHostEnabled: true:执行下列检查并尝试自行托管,代理后端也适用。检查失败时退回远程托管。
  3. 否则 — 复用或上传资源包到 https://magmaguy.com/rsp/,然后公告该 URL。如果初始化、SHA1 校验或上传失败,则在 selfHostEnabled: true 时尝试经过验证的自托管。SESSION_NOT_FOUND 还会清除远程会话,让后续尝试能重新初始化。自动回退采用与优先自托管相同的检查;两条路径均失败时,不会公告新的分发 URL。

远程主机接受最大 50,000 KiB(51,200,000 字节)的 Java 资源包。RSPM 会在上传前检查大小。超过此大小的资源包永远不会被上传:控制台会打印 Automatic hosting skipped: resource pack is <size> bytes; the limit is 51200000 bytes.。随后 RSPM 会对该资源包停止使用远程托管,并持续重试经过验证的自托管(当 selfHostEnabled: true 时),直到托管因新的资源包或重载而重新开始。请减小资源包体积或让自托管可以访问,然后运行 /rspm reload。

一旦拿到 URL,RSPM 会使用 Minecraft 的多资源包 API,因此它的 Java 资源包可以与服务器发送的其他资源包共存。当前的 Bukkit 插件描述符要求 Minecraft 1.21.4 或更高版本。

三项完整性检查​

RSPM 在选择自动自托管之前会依次运行这些检查,包括远程托管失败后的回退。只有 selfHostForce: true 可以跳过:

第 1 层 — 对解析出的外部主机名做启发式检查​

如果解析出的主机(参见下文“外部主机检测”)属于 RFC1918(10.*、172.16-31.*、192.168.*)、回环(127.* 或 localhost)、链路本地(169.254.*)或未指定地址(0.0.0.0),则跳过自托管。IPv6 未指定、回环、链路本地、站点本地和唯一本地地址也会被拒绝。这只是对主机字符串的启发式检查;主机名仍须通过下述下载检查。

这能捕获非常常见的“ipify 查询失败、回退到 LAN IP”的失败模式。

第 2 层 — 本地及公告 URL 下载​

RSPM 先向 http://127.0.0.1:<port>/rspm.zip,再向玩家将收到的确切 URL 发送带字节范围的 GET 请求,将开头最多 1 KiB 与本地资源包比较。接受 HTTP 200 或 206;报告的长度必须匹配,206 响应还须包含预期的 Content-Range。重定向会被拒绝。可检测:

  • 端口绑定冲突(其他东西占用了所选端口)
  • 资源包文件缺失(路由已注册但 zip 尚未在磁盘上就位)
  • 错误路由、HTML 错误页或不一致的资源包字节
  • 服务器自身无法下载公告 URL 的情况,包括 NAT 回流故障

每次连接和读取的超时为 3 秒,读取样本另有独立的 3 秒期限。这些是有限样本检查,不是完整的客户端下载。

第 3 层 — 外部可达性探测​

向 magmaguy.com 托管端的 POST /rsp/probe 提交公告出的 URL。该托管端会从一个公共可视点(带 SSRF 防护和较紧的超时)尝试拉取该 URL,并把可达情况回报。

这能捕获生产环境中最常见的失败模式:服务器有公网 IP,但 HTTP 端口没有在路由器或防火墙上放通。第 2 层会通过(服务器在 127.0.0.1 上有响应),但任何真实客户端都根本下载不到资源包。

针对探测结果的决策策略:

  • reachable=true 且 HTTP 200 或 206 → 探测从其公网位置访问到了 URL。选择自托管。
  • reachable=false 或其他 HTTP 状态 → 验证失败。撤回候选 Java URL,尝试通过 magmaguy.com 远程托管。网络模式下保留后端 HTTP 监听器,以便代理轮询产物。
  • 探测通信本身失败(IOException),或探测客户端不可用 → 可达性尚未验证。尝试远程托管;无法联系探测服务并不证明上传也会失败。自动回退不能跳过这项检查。

这些检查的局限​

从公告 URL 下载现在能够检测服务器自身网络中的 NAT 回流故障,但无法证明每位玩家的网络都可访问,也不能证明 Minecraft 客户端能完成整个下载。请用真实客户端验证完整下载和资源包接受情况;检查公网访问时,使用另一个外部网络。

如果只是想在宿主机上快速测试,请设置 preferSelfHost: false 使用远程回退,或者从蜂窝网络/外部网络访问那个公网 URL。若要长期使用自托管,请采用分离视图 DNS(split-horizon DNS,让同一个公网主机名在你的内网中解析到服务器的 LAN 地址)。不要把 selfHostExternalHost 设为 127.0.0.1:回环地址与私有地址会被公网主机名完整性检查拒绝,而且它们本来也无法为外部客户端提供服务。

端口解析​

两个设置会互相影响:

  • selfHostPort — 1 至 65535 的显式端口,或用 -1(默认)自动计算。计算出的端口也必须在此范围内;其他值会阻止监听器启动。
  • networkHttpOffset-v2 — 仅在 selfHostPort = -1 时才参考。加到 Minecraft 服务器端口上以派生出 HTTP 端口。默认 1。(在代理网络中,这同一个值也是代理对某个后端 HTTP 端口的回退猜测——见下文。)

默认值是 selfHostPort: -1 + networkHttpOffset-v2: 1,所以:

  • MC 端口 25565 → HTTP 端口 25566
  • MC 端口 25584 → HTTP 端口 25585

不同的 Minecraft 端口会得到不同的 HTTP 端口,但计算结果仍可能与另一个后端的 Minecraft 端口或其他服务冲突。请检查所有监听器以及托管商分配的端口。

为什么偏移是 1?​

共享或管理型托管可能只为每个容器分配少量端口。偏移 1 让计算出的端口靠近游戏端口,但不会预留它,也不保证托管商已分配或开放它。请在管理面板确认确切的 HTTP 端口。

拥有完整端口控制权的自托管管理员可以把它改成任意值。在代理网络中,后端会把它实际绑定到的确切 HTTP 端口自动公告给代理,因此即便你更改了偏移或设置了显式的 selfHostPort,代理也会随之跟进。只有在后端尚未完成公告的那个短暂窗口内(或公告无法送达代理时),把代理的 network-http-offset-v2 调成一致才有意义,那只是作为回退使用。

注意:RCON 端口冲突​

如果你的宿主默认在 MC port + 1 上启用 RCON,请将偏移改为 2 或 3 以避免端口冲突。在 server.properties 中查看 rcon.port=。

带版本号的配置键​

config.yml 中的键名就是 networkHttpOffset-v2。v1 的键名为 networkHttpOffset,默认值 100,可能让监听器超出托管商分配的端口范围。v2 默认值为 1,但该端口仍须可用且可访问。

如果你从 v1 升级,废弃的 v1 键会以无害遗留物的形式留在你的配置中,等你手动清理——RSPM 故意不读取它。

外部主机检测​

selfHostExternalHost 控制客户端在 URL 中看到的主机名。留空(默认)则按以下优先级自动检测:

  1. api.ipify.org / checkip.amazonaws.com — 返回本主机的公网 IPv4。每次 /rspm reload 之间只缓存一次,避免反复请求 IP 服务。
  2. Bukkit.getIp() — 服务器绑定地址,仅在非空且不为 0.0.0.0 时使用。通常是 LAN 地址。
  3. InetAddress.getLocalHost() — 尽力而为。
  4. localhost — 最后的兜底。盒子外的客户端访问不到。

如果自动检测落在了不可路由的地址上,且 preferSelfHost: true,第 1 层启发式检查会失败,插件会切换到远程托管。

要获得最可靠的自托管设置,请把 selfHostExternalHost 显式设为你的公网主机名(例如 play.example.com)。这会完全跳过 ipify/AWS 检测,探测会针对你显式给出的值运行。

配置项参考​

HTTPS 与反向代理​

将 selfHostExternalUrl 设为完整的公开下载 URL:

autoHost: true
selfHostEnabled: true
preferSelfHost: true
selfHostPort: 25566
selfHostExternalUrl: "https://packs.example.com/rspm.zip"

配置反向代理,将此公开路径转发到 RSPM 内部的 http://<server>:25566/rspm.zip 路由并终止 TLS。RSPM 仍运行 HTTP 监听器;此设置不会安装证书或配置 Web 服务器。

确切 URL 会发送给 Java 玩家,并用于外部可达性探测,不会追加 /rspm.zip。它在 Java 分发中覆盖 selfHostExternalHost 和公网 IP 检测;selfHostPort 仍控制内部监听器。代理轮询基岩版产物仍使用后端 HTTP 端点。

只接受带主机名的完整 HTTP 或 HTTPS URL,不得包含嵌入的凭据或片段。URL 中的显式端口须在 1 至 65535 之间。无效 URL 会阻止自托管。正常自动托管可以回退到远程服务,强制自托管则不能。留空以使用主机和端口检测。

设置​

# 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 a value from 1 to 65535 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: ""

# Optional complete public Java-pack URL, including the path.
# Your reverse proxy supplies HTTPS and forwards to the internal /rspm.zip route.
selfHostExternalUrl: ""

# 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

控制台实际会打印什么​

Java 远程托管和 Bedrock 中继失败后,会采用带随机变化的指数退避。每个流程同时只允许一次尝试,最多重试五次,然后等待 15–30 分钟再开始下一轮。成功后重置重试额度;HTTP 客户端不会另行自动重试。Java 托管会先检查远程 SHA-1,再决定是否上传。Bedrock 重试会在最多 20 分钟内复用已成功上传且没有变化的文件。常规的每 25 分钟中继续期仍会上传文件,以延长服务器上的有效期。

在正常启动时,RSPM 刻意只打印一行关于托管的信息 —— 只讲结果,不讲过程:

[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>

这一行只在每次有分发路径被全新初始化时打印一次,玩家重试或保活心跳都不会重复打印。如果一次 reload 后的资源包没有变化,它可以复用已有的托管注册,而不会打印新的结果行。

可达性检查失败记录在详细日志级别。 例如:Self-host check: local pack link is not public. This is OK.。主机检查和 localhost 检查以 This is OK. 结尾;公告 URL 的下载检查和外部验证在报告失败时不带此后缀。无效 URL 设置、监听器启动失败和远程通信失败仍可能产生警告。单次检查失败不能证明远程回退已成功;请检查最终分发状态。

要查看完整的决策链 —— 哪一项检查失败、探测 URL、原因代码、暂存的每个资源包与合并的每个集群 —— 请运行:

/rspm verbose on

然后执行 /rspm reload。这是在为托管问题提交 bug 报告之前应该先打开的开关。该命令会把 verboseLogging: true 写入 config.yml,且该设置会在重启后保留,所以排查完毕后请运行 /rspm verbose off;手动编辑这个配置键的效果完全相同。

请注意,verboseLogging 覆盖的是资源包准备与托管。基岩版转换器有自己独立的开关 bedrockConverterDebug —— 参见基岩版转换。

后端 HTTP 服务器路由​

内置的 HTTP 服务器始终在下面这个地址提供资源包 zip:

http://<host>:<port>/rspm.zip

在网络模式下(RSPM 处于 Velocity / BungeeCord 代理之后),还会额外注册供代理插件拉取的路由:

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)

资源包和基岩版产物路由以文件为基础,在每次请求时解析当前已发布的产物。重新合并并成功发布后无需重启 HTTP 服务器即可使用;仅替换磁盘文件并不会授权分发。如果没有当前获准的产物、文件缺失,或字节与发布摘要不符,路由返回 404。基岩版路由还要求转换保持启用。强 ETag 支持 If-None-Match,优先于兼容性的 If-Modified-Since 检查;没有变化的轮询可收到无响应体的 304。更新路由由共享网络密钥派生的 bearer 令牌单独保护,并且只有能提供有效更新 jar 时才可用。

验证自托管是否启用​

/rspm status 会显示:

  • Active delivery: SELF-HOSTED — 当前使用自托管
  • Active delivery: REMOTE (magmaguy.com) — 当前使用远程 auto-host
  • URL: ... — 客户端实际看到的 URL
  • Resolved external host — selfHostExternalHost 解析得到的值
  • Public IP (auto-detected) — ipify/AWS 报告的结果(如有)
  • selfHostPort — 是自动还是显式,以及解析得到的值

如果你预期走自托管但看到的是远程,/rspm status 就是该看的地方 —— 启动日志按设计对已自愈的探测失败保持沉默。运行 /rspm verbose on 并执行 /rspm reload,即可看到是哪一项完整性检查失败以及原因。

常见错误​

  • 把探测成功视为完整的客户端测试 — 本地样本和公网探测仅覆盖特定网络路径。请用真实玩家验证完整下载和资源包接受情况;强制自托管会完全跳过这些检查。
  • 把 networkHttpOffset-v2 调过你托管商的端口范围 — 症状是代理侧永远静默的 CONNECT_FAILED。后端确实会把它真实绑定的端口公告给代理,但 HTTP 服务器仍然必须绑定到一个可达的端口,代理也仍然必须能够访问它;如果 mcPort + offset 落到容器分配的端口区间之外,那么无论是否公告,绑定/防火墙都会失败。在提高偏移之前,先确认该端口落在容器分配的端口区间内。