#!/usr/bin/env bash # One-time setup for the LAN party's dedicated box: installs a Forge 1.20.1 # Minecraft server, wraps it in lazymc (auto-sleep when empty / auto-wake on # connect), and serves the client install scripts + modpack.zip over HTTP — # all as systemd services so the box can run unattended for the 3 days. # # Target: a Linux machine (Debian/Ubuntu/etc with systemd) at the venue. # Run as a normal user with sudo rights: ./setup-server.sh set -euo pipefail # ---- EDIT ME ---- FORGE_MC_VERSION="1.20.1" FORGE_BUILD="47.4.28" # current recommended build for 1.20.1 — check files.minecraftforge.net if this is stale MC_PUBLIC_PORT=25565 # what players connect to (lazymc listens here) MC_INTERNAL_PORT=25566 # real server listens here, lazymc proxies to it FILESERVER_PORT=8000 # install.sh / install.ps1 / modpack.zip served from here SLEEP_AFTER="5m" # idle time before lazymc stops the real server MIN_RAM="2G" MAX_RAM="6G" # 5-8 players; see ../HOSTING.md sizing table — bump to 8G (9-12p) or 10-12G (13-15p) # ------------------ BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SERVER_DIR="$BASE_DIR/mcserver" DIST_DIR="$BASE_DIR/dist" FORGE_VERSION="${FORGE_MC_VERSION}-${FORGE_BUILD}" command -v java >/dev/null || { echo "Java not found. Install a Java 17+ JDK (e.g. 'sudo apt install -y openjdk-17-jre-headless') then re-run."; exit 1; } command -v python3 >/dev/null || { echo "python3 not found. Install it (e.g. 'sudo apt install -y python3') then re-run."; exit 1; } mkdir -p "$SERVER_DIR" "$DIST_DIR" # ---- 1. Install the Forge server ---- if [[ ! -f "$SERVER_DIR/run.sh" ]]; then echo "==> Downloading Forge $FORGE_VERSION installer" installer_url="https://maven.minecraftforge.net/net/minecraftforge/forge/${FORGE_VERSION}/forge-${FORGE_VERSION}-installer.jar" curl -fsSL -o "$SERVER_DIR/forge-installer.jar" "$installer_url" read -rp "Do you accept the Minecraft EULA (https://aka.ms/MinecraftEULA)? [y/N] " eula_ans [[ "$eula_ans" =~ ^[Yy]$ ]] || { echo "EULA not accepted, aborting."; exit 1; } echo "==> Running Forge server installer" (cd "$SERVER_DIR" && java -jar forge-installer.jar --installServer) echo "eula=true" > "$SERVER_DIR/eula.txt" else echo "==> Forge server already installed, skipping" fi # server.properties: lazymc will rewrite host/port/rcon itself, we just set gameplay-relevant bits touch "$SERVER_DIR/server.properties" for kv in "online-mode=false" "motd=LAN Party - Create & Delight" "difficulty=normal" "max-players=20"; do key="${kv%%=*}" if grep -q "^${key}=" "$SERVER_DIR/server.properties" 2>/dev/null; then sed -i "s/^${key}=.*/${kv}/" "$SERVER_DIR/server.properties" else echo "$kv" >> "$SERVER_DIR/server.properties" fi done mkdir -p "$SERVER_DIR/mods" echo "==> NOTE: copy the same mod jars from your client modpack's mods/ folder into $SERVER_DIR/mods/ (Create, Flywheel, Farmer's Delight + addons, JEI, etc.) before first boot." # ---- 2. Install lazymc ---- if [[ ! -x "$BASE_DIR/lazymc" ]]; then echo "==> Downloading latest lazymc" api_url="https://api.github.com/repos/timvisee/lazymc/releases/latest" release_json="$(curl -fsSL "$api_url")" asset_url="$(echo "$release_json" | grep -oE '"browser_download_url": *"[^"]+linux-x64"' | cut -d'"' -f4 | head -n1)" [[ -n "$asset_url" ]] || { echo "Could not find linux-x64 lazymc asset" >&2; exit 1; } curl -fsSL -o "$BASE_DIR/lazymc" "$asset_url" chmod +x "$BASE_DIR/lazymc" else echo "==> lazymc already present, skipping" fi cat > "$BASE_DIR/lazymc.toml" < Wrote lazymc.toml (sleeps after ${SLEEP_AFTER} empty, public port ${MC_PUBLIC_PORT} -> internal ${MC_INTERNAL_PORT})" # ---- 3. systemd services ---- sudo tee /etc/systemd/system/mc-lazymc.service >/dev/null </dev/null < Done." echo " - Minecraft server: public port ${MC_PUBLIC_PORT}, sleeps after ${SLEEP_AFTER} idle, wakes on connect." echo " - File server: http://:${FILESERVER_PORT}/ serving ${DIST_DIR}/" echo " - Put install.sh, install.ps1 and modpack.zip into ${DIST_DIR}/ (see ../HOSTING.md)." echo " - Copy your client mod jars into ${SERVER_DIR}/mods/ if you haven't yet, then: sudo systemctl restart mc-lazymc" if command -v ufw >/dev/null && sudo ufw status | grep -q "Status: active"; then echo "==> ufw is active — opening ${MC_PUBLIC_PORT}/tcp and ${FILESERVER_PORT}/tcp" sudo ufw allow "${MC_PUBLIC_PORT}/tcp" sudo ufw allow "${FILESERVER_PORT}/tcp" fi