#!/usr/bin/env bash # # Reaper's Sky - dedicated server deploy script (Debian 13 / trixie) # # Installs everything needed to run the Reaper's Sky NeoForge 21.1.248 server: # - OpenJDK 21 (JRE, headless) + curl/unzip # - NeoForge 21.1.248 server via its official installer # - the 59 server-safe mods (pinned in mods.json, verified by sha1) # - eula.txt + server.properties (IP reaperofveriod.nl) # - run.sh (8 GB, G1GC) # # Usage: sudo ./deploy.sh (installs packages, needs root/sudo) # ./deploy.sh (idempotent; safe to re-run) # # Defaults: # DIR = "$HOME/reaper-sky-server" # MEMORY = 8G set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" NEOFORGE_VERSION="21.1.248" MC_VERSION="1.21.1" INSTALLER_URL="https://maven.neoforged.net/releases/net/neoforged/neoforge/${NEOFORGE_VERSION}/neoforge-${NEOFORGE_VERSION}-installer.jar" # --- config (override via env if you want) ------------------------------------ SERVER_DIR="${DIR:-$HOME/reaper-sky-server}" MEMORY="${MEMORY:-8G}" SERVER_IP="${SERVER_IP:-}" # empty = bind all interfaces; reach server via edge port-forward DEFAULT_MOTD="Reaper's Sky" MOTD="${MOTD:-$DEFAULT_MOTD}" MAX_PLAYERS="${MAX_PLAYERS:-10}" log() { printf '\033[1;34m[deploy]\033[0m %s\n' "$*"; } die() { printf '\033[1;31m[deploy] ERROR:\033[0m %s\n' "$*" >&2; exit 1; } # --- 1. system packages (Debian 13 ships OpenJDK 21) -------------------------- install_packages() { if [ "$(id -u)" -ne 0 ]; then if command -v sudo >/dev/null 2>&1; then SUDO="sudo"; else SUDO=""; fi else SUDO="" fi if command -v java >/dev/null 2>&1; then log "Java already present: $(java -version 2>&1 | head -1)" else log "Installing openjdk-21-jre-headless, curl, unzip (apt)..." ${SUDO:+sudo} apt-get update -qq ${SUDO:+sudo} apt-get install -y -qq openjdk-21-jre-headless curl unzip fi java -version >/dev/null 2>&1 || die "Java 21 not available after install" } # --- 2. NeoForge server -------------------------------------------------------- install_neoforge() { mkdir -p "$SERVER_DIR" cd "$SERVER_DIR" if [ -f "run.sh" ] && [ -d "libraries/net/neoforged/neoforge/$NEOFORGE_VERSION" ]; then log "NeoForge $NEOFORGE_VERSION already installed." return fi log "Downloading NeoForge $NEOFORGE_VERSION installer..." curl -fL --retry 3 -o "neoforge-${NEOFORGE_VERSION}-installer.jar" "$INSTALLER_URL" log "Running installer --installServer ..." java -jar "neoforge-${NEOFORGE_VERSION}-installer.jar" --installServer rm -f "neoforge-${NEOFORGE_VERSION}-installer.jar" chmod +x run.sh } # --- 3. server mods (verified by sha1) ----------------------------------------- install_mods() { [ -f "$SCRIPT_DIR/mods.json" ] || die "mods.json not found next to deploy.sh" mkdir -p "$SERVER_DIR/mods" cd "$SERVER_DIR/mods" python3 - "$SCRIPT_DIR/mods.json" <<'PY' import json, sys, hashlib, subprocess, os manifest = json.load(open(sys.argv[1])) for m in manifest["mods"]: fname, url, want = m["file"], m["url"], m["sha1"] tmp = fname + ".part" if os.path.exists(fname): h = hashlib.sha1() with open(fname, "rb") as fh: for b in iter(lambda: fh.read(65536), b""): h.update(b) if h.hexdigest() == want: continue # already present & correct subprocess.run(["curl", "-fL", "--retry", "3", "-o", tmp, url], check=True) h = hashlib.sha1() with open(tmp, "rb") as fh: for b in iter(lambda: fh.read(65536), b""): h.update(b) if h.hexdigest() != want: os.unlink(tmp) raise SystemExit(f"sha1 mismatch for {fname}") os.rename(tmp, fname) print(f" + {fname}") PY log "Mods ready: $(ls -1 "$SERVER_DIR/mods"/*.jar | wc -l) jars installed." } # --- 4. eula + server.properties ----------------------------------------------- write_config() { cd "$SERVER_DIR" if [ ! -f eula.txt ]; then printf 'eula=true\n' > eula.txt log "Accepted Minecraft EULA (eula.txt)." fi cat > server.properties < "$SERVER_DIR/run.sh" <<'EOF' #!/usr/bin/env bash cd "$(dirname "$(readlink -f "$0")")" exec java -XmsMEMORY -XmxMEMORY -XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 \ @libraries/net/neoforged/neoforge/NEOFORGE_VERSION/unix_args.txt nogui EOF sed -i "s/MEMORY/$MEMORY/g; s/NEOFORGE_VERSION/$NEOFORGE_VERSION/g" "$SERVER_DIR/run.sh" chmod +x "$SERVER_DIR/run.sh" log "Wrote run.sh ($MEMORY RAM). Start with: cd $SERVER_DIR && ./run.sh" } install_packages install_neoforge install_mods write_config write_run log "Done. Reaper's Sky server is at: $SERVER_DIR" log "First boot generates the world. Run it with: cd $SERVER_DIR && ./run.sh" log "Console: run inside tmux/screen so it keeps running when you disconnect." log "To stop later: use the server console command stop"