Files
mc-lan-party/HOSTING.md
T
Mykhailo Ivanchenko cd694a67b6 Move file distribution to Gitea, deploy server on mivanchenko.de
Drops the standalone fileserver systemd unit from setup-server.sh in
favor of Gitea's already-public raw-file serving. Adds VR (Vivecraft)
and quest (FTB Quests) mod docs, the DH/Chunky server-side crash
warning, and documents the real deployment target (always-on homelab
box, not a venue-local machine).
2026-10-23 15:01:00 +02:00

12 KiB
Raw Blame History

How to run this at the LAN party

1. Prep the modpack instance once, yourself, beforehand

  1. Install Fjord Launcher Unlocked normally on your own machine.
  2. Create a new instance: Minecraft 1.20.1, Forge. Name it exactly LANParty (or change INSTANCE_NAME/$InstanceName in both scripts to match).
  3. Add the mods from modpack.md (use the launcher's built-in Modrinth/CurseForge browser, or drop jars straight into the instance's mods/ folder).
  4. Set up the server and pregenerate first — do the "Set up the dedicated venue box" and "Pre-generate chunks before the party starts (Chunky)" steps below before continuing here. Distant Horizons can only cache real terrain that already exists; it can't backfill detail after the fact.
  5. Launch the client, go to Multiplayer → Add Server, enter minecraft.mivanchenko.de:25565 (not a raw IP — see "Moving the server to the venue" below), and join for real. Set your preferred video settings (these land in options.txt). Then do a flying pass to populate the Distant Horizons cache — client-only DH can't backfill terrain it hasn't actually received as real chunks, so this has to be done by hand:
    • Switch to Creative, double-tap Space for creative flight (hold sprint to go faster).
    • Temporarily bump your client's render distance up (Video Settings) — DH only caches what the server actually sends within that range, so a higher render distance covers more ground per pass.
    • Fly a spiral or back-and-forth grid centered on spawn, covering roughly the same radius you pregenerated with Chunky (800 blocks ≈ 50 chunks), spacing passes about 1–1.5× your render distance apart so coverage overlaps slightly.
    • Partial coverage is fine — anywhere you don't reach just falls back to the normal fog edge, same as skipping this step, not an error.
    • Quit when you've covered the zone. This is what actually populates Distant_Horizons_server_data/ in the instance with real LOD data — do not try to shortcut this by installing Distant Horizons on the dedicated server instead (see the warning in modpack.md's Performance section — DH-on-server crashes when Chunky is also present).
  6. Quit the launcher, then export the instance via right-click the instance → Export Instance (don't blindly zip the raw folder — the exporter lets you pick what's included). Check: mods/, config/, options.txt, servers.dat, Distant_Horizons_server_data/. Uncheck: logs/, crash-reports/, screenshots/, and any asset/library caches — those regenerate automatically on first launch and just bloat the zip. Name the result modpack.zip, with the instance's folder (LANParty/...) as the zip's top-level entry.

Caveats for this to actually pay off for participants:

  • Don't rename the server list entry or change Distant Horizons' "Server Folder Name Mode" setting afterward — both are part of the cache key ("<server name> <ip>:<port>" by default). Change either and participants' clients won't find the cache you built.
  • Don't regenerate/reset the server world after this point. If the actual party world differs from the one you explored, the cached LOD will show stale terrain that doesn't match reality.
  • This cache is for scenery beyond render distance only — it doesn't substitute for the server having online-mode=false or for Chunky's pregen; all three pieces (pregen, DH cache, offline accounts) are independent and all need to land in the final zip/setup.

2. The server: mivanchenko.de (always-on, not a box you carry to the venue)

This setup runs on the existing homelab box at mivanchenko.de (SSH: ssh server, i.e. port 222, same machine already running Gitea/n8n/the SMB stack/etc) rather than a machine physically present at the party. That means no DNS repoint, no file-server migration, no "moving to the venue" step — minecraft.mivanchenko.de already resolves here and stays pointed here.

Tradeoff to be aware of: since the server isn't on the venue's local network, players connect over the internet, not LAN — latency depends on the venue's internet connection, not your switch. For a 3-day modded-Minecraft LAN party this is usually fine (Minecraft is forgiving of 20–60ms), but if the venue's internet is bad, this is the thing that bites. Worth testing from the venue ahead of time if you can.

Server location: ~/lan-minecraft/server/ on the box. Setup:

ssh server
cd ~/lan-minecraft
# copy server/setup-server.sh here (or git clone the mc-lan-party repo), then:
cd server && ./setup-server.sh
# then copy your client modpack's mod jars into mcserver/mods/, and:
sudo systemctl restart mc-lazymc

setup-server.sh installs the Forge 1.20.1 server and wraps it in lazymc, which sleeps the real server after 5 idle minutes and transparently wakes it the instant someone connects — no manual start/stop for the whole 3 days. It does not handle file distribution (see section 3 — that's Gitea now, not this script).

Since port 25565 is reached directly (Minecraft is raw TCP, not HTTP — Caddy on this box only proxies HTTP(S) on 80/443 and has no layer4/TCP module, so it genuinely can't front Minecraft traffic), there's no Caddy entry to add for minecraft.mivanchenko.de. lazymc just binds 0.0.0.0:25565 on the host directly, same way crafty_container already exposes its own Minecraft ports on this box.

Services temporarily stopped on this box to free up resources for the party (docker stop, not removed — bring back with docker start <name> after): smb-crm, smb-db, breathemate-license, crafty_container, n8n-n8n-1, open-webui, mcpo.

Useful commands during the party:

  • sudo systemctl status mc-lazymc — check if the MC server is asleep/awake
  • sudo journalctl -u mc-lazymc -f — watch it wake/sleep live
  • sudo systemctl restart mc-lazymc — pick up new mods or a config change

Resource sizing for the venue box (5–15 players)

Create is the dominant cost here — it's heavier on the server tick thread (CPU) than on RAM, because kinetic networks and contraptions get simulated every tick regardless of how many players are nearby. Farmer's Delight/its addons are cheap by comparison. Numbers below assume this modpack (~10 mods) and are total host box numbers, not just the JVM heap:

Concurrent players JVM heap (-Xmx, set in setup-server.sh) Host RAM (total, incl. OS + other running services) CPU Free disk Network
5–8 6G 10–12 GB 4 cores, 3.5 GHz+ single-core perf matters more than core count ~10 GB (world + mods + Forge libs + logs) Gigabit LAN recommended, Wi-Fi workable
9–12 8G 12–16 GB 4–6 cores, 3.5 GHz+ ~15 GB Gigabit LAN recommended
13–15 10–12G 16 GB+ 6+ cores, 3.5 GHz+ ~20 GB Gigabit LAN, wire the host box if possible

Practical knobs to turn if the box is lighter than the table:

  • Lower server.properties view-distance to 6–8 — this is the single biggest CPU/RAM lever on a modded server, and the Distant Horizons client mod (see modpack.md) makes a short server view-distance look fine anyway.
  • Set simulation-distance a notch below view-distance if things chug — it controls how far Create's kinetic networks/entities get ticked, independent of render range.
  • MIN_RAM/MAX_RAM in setup-server.sh default to 2G/4G — bump MAX_RAM to match the table above for your headcount before running the script (or edit lazymc.toml's command line afterward and sudo systemctl restart mc-lazymc).
  • An SSD matters more than raw disk size here — Create's block-entity-heavy contraptions do a lot of small, frequent chunk saves; a spinning HDD will show up as tick-time spikes.

Pre-generate chunks before the party starts (Chunky)

Chunky (server-side mod, already listed in modpack.md) fills in a radius of real terrain ahead of time so nobody hits on-the-fly generation lag while exploring. Do this once, before participants arrive:

  1. Make sure mcserver/mods/ has the Chunky jar, then sudo systemctl restart mc-lazymc and let the server boot (connect once from a client, or sudo journalctl -u mc-lazymc -f and wait for "Done").

  2. Run the commands below either from the server console (attach via sudo systemctl stop mc-lazymc && cd mcserver && bash run.sh nogui, temporarily bypassing lazymc so you get an interactive console) or via RCON (mcrcon -H 127.0.0.1 -P 25575 -p <password from server.properties> "<command>"):

    /chunky center 0 0        # or your build area's coordinates
    /chunky radius 800        # 800 blocks ≈ 50 chunks (1 chunk = 16 blocks)
    /chunky start
    /chunky confirm           # if it warns about area size
    
  3. Watch progress with /chunky status. For ~50 chunks radius this finishes in seconds to a couple minutes depending on the box.

  4. If you stopped lazymc to get console access in step 2, restart it afterward: sudo systemctl start mc-lazymc.

Repeat with /chunky world the_nether / /chunky world the_end first if you want the Nether/End build areas pregenerated too (useful since the roadmap sends people there for Nether's/End's Delight dishes).

3. File distribution: Gitea, not a local file server

install.sh, install.ps1, and (once built) modpack.zip are committed straight to the mc-lan-party repo on Gitea (git.mivanchenko.de, already proxied by Caddy and public), served via its raw-file URLs. No separate file-server process on the venue/server box — one less moving part, and it's fine for now per your call; worth revisiting (e.g. Gitea releases/LFS, or an object store) if modpack.zip turns out large enough that Gitea's raw-file serving gets awkward.

Give participants:

  • Windows: irm https://git.mivanchenko.de/mivanchenko/mc-lan-party/raw/branch/main/install.ps1 | iex
  • Linux / macOS: curl -fsSL https://git.mivanchenko.de/mivanchenko/mc-lan-party/raw/branch/main/install.sh | bash

Each script asks for a nickname, derives a stable offline-mode UUID from it (so the same name = same player data across the whole 3-day party, even if they re-run the script), seeds that into a fresh accounts.json, downloads Fjord Launcher Unlocked + the modpack from Gitea, and launches straight into the instance already connected to minecraft.mivanchenko.de.

Make sure your Minecraft server itself is running with online-mode=false in server.properties — offline accounts only work against offline-mode servers.

Notes / things that can break

  • The scripts pull Fjord Launcher Unlocked's latest GitHub release dynamically, so they stay correct even after version bumps — but if hero-persson/FjordLauncherUnlocked ever disappears, swap the repo slug at the top of the scripts for a current fork.
  • install.sh needs curl, unzip/find (standard on any Linux/macOS box) and relies on FUSE for running the AppImage directly; if a participant's distro lacks FUSE, the AppImage will fail to launch — tell them to run ./FjordLauncher.AppImage --appimage-extract once and point LAUNCHER_BIN at the extracted AppRun.
  • Re-running either script is safe/idempotent: it skips re-downloading the modpack if the instance folder already exists, and just overwrites accounts.json with the (same, deterministic) account if the nickname is unchanged.
  • lazymc's first wake after a sleep takes as long as the Forge server normally does to boot (expect 20–60s depending on the box) — the client will show a "starting" MOTD/kick message during that window; just reconnect after a few seconds.
  • setup-server.sh pins a Forge build (47.4.28 for 1.20.1) — check files.minecraftforge.net if it's gone stale by the time you run this.
  • Double-check the server's mod list is byte-for-byte the same mods as the client instance (same versions) — Forge is strict about mod-list mismatches between client and server and will refuse to connect otherwise.