跳到主要内容

自托管资源包

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

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

如果你反而希望通过自己已有的、独立于 RSPM 的 Web 服务器托管 zip,请参阅 Troubleshooting page 中关于 autoHost: false 的一节。

分发决策树

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

  1. selfHostForce: true — 直接走自托管,不做任何探测,也不做远程上传。主要用于测试自托管路径。会绕过其他所有开关。
  2. preferSelfHost: trueselfHostEnabled: true 且不在网络模式 — 先尝试带三项完整性检查的自托管(见下文)。若全部通过,则确认走自托管;若任一项失败,则回退到远程路径。
  3. 否则 — 将资源包上传到 https://magmaguy.com/rsp/ 并公告该 URL。如果上传失败或 SHA1 校验返回 SESSION_NOT_FOUND,则回退到自托管(前提是 selfHostEnabled: true)。

一旦确定了 URL,RSPM 在 Minecraft 1.20.3+ 上使用多资源包 API(以便与其他服务器发送的资源包共存),在更早版本上则使用旧的单资源包方法。

三项完整性检查

preferSelfHost: true 时,RSPM 在确认走自托管之前会按顺序运行下面三项检查:

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

如果解析出的主机名(参见下文 “外部主机检测”)属于 RFC1918(10.*172.16-31.*192.168.*)、回环(127.*)、链路本地(169.254.*)或未指定(0.0.0.0),那么自托管对互联网客户端根本不可能可用。立即跳过,使用远程托管。

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

第 2 层 — 本地回环自探测

http://127.0.0.1:<port>/rspm.zip 发起 HEAD 请求,验证返回 HTTP 200 并且响应体非空。可捕获:

  • 端口绑定冲突(其他东西占用了所选端口)
  • 资源包文件缺失(路由已注册但 zip 尚未在磁盘上就位)
  • 路由注册的 bug

该探测使用激进的超时(3 秒),以免一个慢探测拖延启动。

第 3 层 — 外部可达性探测

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

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

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

  • reachable=true → 外部客户端可以访问到我们的 URL。确认走自托管。
  • reachable=false → 外部客户端访问不到。拆掉自托管,改用远程托管(从 magmaguy.com 看是普遍可达的)。
  • 探测通信本身失败(IOException) → 无法证实任何一种结果。默认保留自托管:以“无法探测”为由拒绝是自相矛盾的,因为远程路径同样需要 magmaguy.com。

这些检查仍然检测不到的情况

NAT 回流(hairpin)边缘情况:端口对公网完全开放(第 3 层通过),但运维人员自家路由器不会把 LAN 内的流量回环回来。外部客户端正常工作,但运维人员从同一台机器测试时失败。

目前的变通方法:当从主机本机测试而路由器存在 hairpin 问题时,设置 preferSelfHost: falseselfHostExternalHost: 127.0.0.1

端口解析

两个设置会互相影响:

  • 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 端口冲突

如果你的宿主默认在 MC 端口 + 1 上启用 RCON,请将偏移改为 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 中看到的主机名。留空(默认)则按以下优先级自动检测:

  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 检测,探测会针对你显式给出的值运行。

配置项参考

# 是否允许使用内置 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: ""

# 先尝试带三项完整性检查的自托管,任一项失败则回退到远程。
# 设为 false 时,使用旧顺序:先尝试远程上传,仅在上传失败时才走自托管。
preferSelfHost: true

# 跳过所有其他分发路径,强制走自托管。
# 会绕过完整性检查以及远程上传。主要用于测试。
selfHostForce: false

后端 HTTP 服务器路由

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

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

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

http://<host>:<port>/bedrock.zip   # 转换后的基岩版资源包
http://<host>:<port>/mappings.json # Geyser 自定义映射 JSON

三个路由都由文件支持:每次请求都会重新读取文件,所以即使重新合并写入了同一个 zip 路径,也会被自动采纳,无需重启 HTTP 服务器。两个基岩版路由都支持 If-Modified-Since,因此代理轮询器在内容未变时几乎零带宽。所有路由在底层文件缺失时(例如首次合并尚未完成)都会干净地返回 404。

验证自托管是否启用

/rspm status 会显示:

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

如果你预期走自托管但实际显示远程,启动日志会解释是哪一项完整性检查失败了以及原因。

常见错误

  • selfHostPort 设为任意值,却没在代理一侧同步修改 — 在网络模式下,代理使用 mcPort + network-http-offset-v2 来计算每个后端的 HTTP 端口。显式的 selfHostPort 会覆盖自动派生,但代理并不知道这件事,仍然会去轮询 mcPort + offset。除非你准备好在两端协调,否则在网络模式下请保留 selfHostPort: -1
  • 在路由器存在 hairpin 问题时仍然相信第 3 层探测的结果 — 该探测从 magmaguy.com 的可视点运行,所以无法捕获“外部客户端可用、但运维人员自家 LAN 无法回环”的情况。不确定时请用蜂窝网络下的手机测试。
  • networkHttpOffset-v2 调过你托管商的端口范围 — 症状是代理侧永远静默的 CONNECT_FAILED。提高偏移之前,先确认 mcPort + offset 落在容器分配的端口区间内。