Files
ulicraft-server-v1/plan/05-minecraft.md
Oier Bravo Urtasun 27237bc7c1 feat(mods): replace packwiz with distribution-fed custom mod volume
Drop packwiz entirely. The server now loads a filtered mod subset from a
local ./server-mods volume instead of fetching a packwiz pack at boot.

New flow:
- tooling/classify-mods.py (tomllib only, no network) reads each jar's
  META-INF/neoforge.mods.toml and seeds mods-sides.json with a side
  (client|server|both; default both). Existing entries are preserved.
- mods-sides.json: committed, keyed by jar filename, hand-editable override
  surface. Initial seed: 65 both, 11 client, 0 server (76 jars).
- tooling/sync-server-mods.sh mirrors the both/server jars from
  $DISTRIBUTION_WEB_ROOT into ./server-mods/ (authoritative; prunes strays;
  halts on a missing jar). Replaces render-pack.sh.
- compose: minecraft mounts ./server-mods:/mods:ro with REMOVE_OLD_MODS=TRUE
  (itzg auto-syncs /mods -> /data/mods). Removed PACKWIZ_URL, the pack.
  extra_host (auth. kept for authlib), and depends_on caddy (drasl kept).

Both classify-mods.py and sync-server-mods.sh resolve their source dir as:
CLI arg / MODS_DIST_DIR env / $DISTRIBUTION_WEB_ROOT (in that order).

Removed: tooling/render-pack.sh + add-custom-mod.sh (packwiz tooling),
pack/ (packwiz source), custom/ (76 jars now sourced from the distribution),
the pack. caddy vhost + its mounts/alias, and the packwiz .gitignore block.

Client distribution is UNCHANGED: HeliosLauncher still installs the full
modset from distribution.json. Docs (CLAUDE.md, plan/04/05/14, runtime)
updated; plan/04-packwiz.md stubbed as superseded by plan/04-mods.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 23:34:38 +02:00

1.9 KiB

Minecraft server — itzg NeoForge

Summary

itzg/minecraft-server:java21, NeoForge 1.21.1, offline-mode + authlib-injector pointing at drasl. Mods come from a local ./server-mods volume (mounted at /mods), NOT packwiz — see 04-mods.md. itzg installs MC + NeoForge + libraries on first boot and auto-syncs /mods/data/mods every boot; the stack assumes the internet is present (for the NeoForge installer), so TYPE=NEOFORGE boots normally every time.

Server config

TYPE=NEOFORGE, VERSION=1.21.1, NEOFORGE_VERSION=21.1.x
REMOVE_OLD_MODS=TRUE          # ./server-mods is the authoritative mod set
volume  ./server-mods:/mods:ro

./server-mods is populated by tooling/sync-server-mods.sh (the both/server subset of mods-sides.json, copied from $DISTRIBUTION_WEB_ROOT). First boot installs MC + NeoForge + libraries into the mc_data volume; every boot itzg mirrors /mods into /data/mods and prunes removed ones (REMOVE_OLD_MODS).

Auth / config

ONLINE_MODE=FALSE
ENFORCE_SECURE_PROFILE=FALSE                 # pairs with drasl SignPublicKeys=false
JVM_OPTS=-javaagent:/extras/authlib-injector.jar=http://auth.${BASE_DOMAIN}/authlib-injector

authlib URL uses the auth subdomain; resolves internally via the caddy alias. (Server still needs the agent even though Fjord clients have it built in.)

Memory: INIT_MEMORY 4G, MAX_MEMORY 10G, USE_AIKAR_FLAGS TRUE. RCON enabled for mc-backup.

Tasks

  • Compose: authlib URL http://auth.${BASE_DOMAIN}/authlib-injector
  • Compose: mount ./server-mods:/mods:ro + REMOVE_OLD_MODS=TRUE
  • Run tooling/sync-server-mods.sh before bring-up (populates ./server-mods)
  • Mount ./runtime for authlib-injector.jar at /extras
  • depends_on: drasl (authlib must resolve at boot)
  • Confirm ENFORCE_SECURE_PROFILE=FALSE ↔ drasl SignPublicKeys=false
  • Verify a client joins with their drasl skin