Перейти к основному содержимому

Самостоятельный хостинг ресурс-пака

ResourcePackManager поставляется с собственным небольшим HTTP-сервером. Когда autoHost: true (по умолчанию) и preferSelfHost: true (по умолчанию), плагин пытается хостить собранный пак из той же JVM, что и сам Minecraft-сервер — без внешнего файлового хоста, без отдельного веб-сервера, без ручной вставки URL.

Эта страница описывает, как работает этот путь самостоятельного хостинга, что делают проверки исправности, как выбирается порт и hostname, и что настраивать, когда значения по умолчанию вам не подходят.

Если вместо этого вы хотите хостить zip через свой собственный существующий веб-сервер вне RSPM, см. раздел про autoHost: false на странице устранения неполадок.

Дерево решений по доставке

Когда игрок подключается, RSPM выбирает URL для доставки по такому приоритету:

  1. selfHostForce: true — прямой self-host, без проверок, без удалённой загрузки. Главным образом для тестирования self-host пути. Обходит все остальные флаги.
  2. preferSelfHost: true И selfHostEnabled: true И не в сетевом режиме — попробовать self-host с тремя проверками исправности (см. ниже). Если все проходят, фиксируется self-host. Если хоть одна не прошла, откат на удалённый путь.
  3. Иначе — загрузить пак на https://magmaguy.com/rsp/ и анонсировать этот URL. Если загрузка не удалась или проверка SHA1 сообщает SESSION_NOT_FOUND, откат на self-host (при условии selfHostEnabled: true).

Как только URL получен, RSPM использует multi-pack API Minecraft, поэтому его Java-пак может сосуществовать с другими паками, отправляемыми сервером. Текущий дескриптор Bukkit-плагина требует Minecraft 1.21.4 или новее.

Три проверки исправности

Когда preferSelfHost: true, RSPM выполняет эти проверки по порядку перед тем, как зафиксировать self-host:

Уровень 1 — эвристическая проверка разрешённого внешнего хоста

Если разрешённый хост (см. «Определение внешнего хоста» ниже) — это RFC1918 (10.*, 172.16-31.*, 192.168.*), loopback (127.*), link-local (169.254.*) или unspecified (0.0.0.0), self-host никак не сможет работать для интернет-клиентов. Сразу пропустить и использовать удалённый хостинг.

Это ловит очень распространённый сценарий «ipify-запрос не удался, откатился на LAN-IP».

Уровень 2 — локальная самопроверка

Открывается HEAD-запрос на http://127.0.0.1:<port>/rspm.zip, проверяется HTTP 200 и непустое тело. Ловит:

  • коллизии при привязке порта (что-то другое уже на выбранном порту)
  • отсутствующий файл пака (маршрут зарегистрирован, но zip ещё не на диске)
  • баги регистрации маршрутов

Агрессивный таймаут (3 с), чтобы медленная проверка не затягивала загрузку.

Уровень 3 — проверка внешней доступности

POST анонсированного URL на POST /rsp/probe на хостере magmaguy.com. Хостер скачивает URL с публичной vantage point (с SSRF-защитой и жёстким таймаутом) и отчитывается, доступен ли он.

Ловит наиболее распространённую боевую проблему: у сервера есть публичный IP, но HTTP-порт не проброшен на роутере или файрволе. Уровень 2 проходит (сервер отвечает на 127.0.0.1), но ни один реальный клиент никогда не сможет скачать пак.

Политика принятия решений по результатам проверки:

  • reachable=true → внешние клиенты могут достучаться до нашего URL. Фиксируется self-host.
  • reachable=false → внешние клиенты не могут. Сворачивается self-host, используется удалённый хостинг (который универсально доступен с magmaguy.com).
  • сама связь проверки не удалась (IOException) → не удалось проверить никак. По умолчанию оставляется self-host: отказывать из-за невозможности проверки было бы парадоксально, потому что удалённому пути magmaguy.com тоже нужен.

Что проверки всё ещё не обнаруживают

Граничный случай NAT-hairpin, когда порт открыт в публичный интернет (Уровень 3 проходит), но собственный роутер оператора не делает loopback трафика обратно изнутри LAN. Внешние клиенты работают, но оператор, тестирующий с той же машины, получает отказ.

Для быстрой проверки с хост-машины выставьте preferSelfHost: false и используйте удалённый резерв либо проверьте публичный URL из сотовой/внешней сети. Для постоянной self-host установки используйте split-horizon DNS (то же публичное имя хоста внутри вашей сети резолвится в LAN-адрес сервера). Не выставляйте selfHostExternalHost в 127.0.0.1: loopback и приватные хосты отклоняются проверкой публичности хоста и не могут обслуживать внешних клиентов.

Разрешение порта

Две настройки взаимодействуют:

  • 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?

Большинство shared / managed Minecraft-хостингов (панели на базе Pterodactyl и т. п.) выделяют узкий диапазон портов на контейнер (часто всего 4–10 портов). Большие смещения уходят за границы диапазона, и файрвол хостинга молча блокирует HTTP-порт. Смещение 1 помещается даже в самые узкие выделения.

Самостоятельные администраторы с полным контролем над портами могут увеличить это до любого значения. В прокси-сети бэкенд автоматически объявляет прокси точный HTTP-порт, на который привязался, поэтому прокси следует за ним, даже если вы измените смещение или зададите явный selfHostPort. Увеличивать network-http-offset-v2 прокси для совпадения имеет смысл только как запасной вариант на короткий промежуток до того, как бэкенд объявил порт (или если объявление не может достичь прокси).

Осторожно: коллизия с RCON

Если ваш хостинг включает RCON по умолчанию на MC port + 1, выберите смещение 2 или 3 во избежание коллизии портов. Проверьте server.properties на rcon.port=.

Версионированный ключ конфига

Настройка в config.yml буквально называется networkHttpOffset-v2. Ключ v1 был networkHttpOffset с дефолтом 100 — этот дефолт ломался на shared / managed-хостингах, где каждый игровой контейнер получает всего ~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() — bind-адрес сервера, когда непустой и не 0.0.0.0. Обычно LAN-адрес.
  3. InetAddress.getLocalHost() — best-effort.
  4. localhost — последний резерв. Клиенты вне коробки сюда не достучатся.

Если авто-определение приводит к не-маршрутизируемому адресу и preferSelfHost: true, эвристическая проверка Уровня 1 проваливается, и плагин переключается на удалённый хостинг.

Для максимально надёжной настройки self-host выставьте 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 намеренно печатает одну строку о хостинге при обычной загрузке — результат, а не путь к нему:

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

Эта строка печатается один раз при каждой свежей инициализации пути доставки, а не при повторных попытках игроков или тиках keep-alive. Перезагрузка, при которой пак не изменился, может переиспользовать существующую регистрацию хостинга вместо того, чтобы печатать новый результат.

Непройденные проверки исправности — не предупреждения. Непрошедшая проверка — это условие, из которого RSPM восстанавливается сам, поэтому оно логируется как деталь, а не как сбой, и каждое сообщение прямо об этом говорит (Self-host check: local pack link is not public. This is OK.). Вы его не увидите, пока не попросите — предупреждение о том, что плагин уже обработал, читается как сбой и заставляет операторов гоняться за несуществующей проблемой.

Чтобы увидеть всю цепочку решений — какая проверка не прошла, URL пробы, код причины, каждый подготовленный пак и каждый объединённый кластер — выполните:

/rspm verbose on

Затем выполните /rspm reload. Это тот переключатель, который надо включить до того, как открывать баг-репорт по хостингу. Команда записывает verboseLogging: true в config.yml, и настройка сохраняется между перезапусками, поэтому выполните /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-артефактов file-backed: каждый маршрут читает свой файл свежим при каждом запросе, поэтому пересборка, переписывающая тот же путь, подхватывается автоматически без перезапуска HTTP-сервера. Bedrock-маршруты используют строгие ETag и для совместимости поддерживают If-Modified-Since, поэтому опросы прокси без изменений получают 304 с практически нулевым трафиком. Эти маршруты корректно возвращают 404, когда подлежащий файл отсутствует (например, до завершения первой сборки). Маршрут обновления отдельно защищён bearer-токеном, выводимым из общего сетевого ключа, и доступен только тогда, когда есть валидный jar обновления, который можно предложить.

Проверка, что self-host активен

/rspm status показывает:

  • Active delivery: SELF-HOSTED — self-host используется
  • Active delivery: REMOTE (magmaguy.com) — удалённый авто-хостинг используется
  • URL: ... — фактический URL, который увидят клиенты
  • Resolved external host — во что разрешилось selfHostExternalHost
  • Public IP (auto-detected) — что вернули ipify/AWS, если что-то
  • selfHostPort — авто vs явный, и разрешённое значение

Если вы ожидали self-host, но видите удалённый, смотреть нужно в /rspm status — лог загрузки намеренно молчит о самоустранённых сбоях проб. Выполните /rspm verbose on и /rspm reload, чтобы увидеть, какая проверка исправности не прошла и почему.

Типичные ошибки

  • Доверять проверке Уровня 3 при сломанном hairpin на роутере — проверка идёт с vantage point magmaguy.com, поэтому она не может поймать случай, когда внешние клиенты работают, но собственная LAN оператора не делает loopback. Тестируйте с телефона по сотовой, если не уверены.
  • Увеличение networkHttpOffset-v2 за пределы диапазона портов вашего хостинг-провайдера — симптом — молчаливый CONNECT_FAILED навсегда на стороне прокси. Бэкенды объявляют прокси свой реальный привязанный порт, но HTTP-серверу всё равно нужно привязаться к доступному порту, а прокси всё равно нужно иметь возможность до него достучаться; если mcPort + offset уходит за пределы выделенной полосы портов вашего контейнера, привязка/файрвол падает независимо от объявления. Проверьте, что порт находится в выделенной полосе вашего контейнера, прежде чем увеличивать смещение.