Files

156 lines
5.5 KiB
Bash
Executable File

#!/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 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]))
keep = set()
for m in manifest["mods"]:
fname, url, want = m["file"], m["url"], m["sha1"]
keep.add(fname)
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
if not url:
raise SystemExit(f"no download URL for {fname}")
subprocess.run(["curl", "-fsSL", "--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}")
# remove jars that are no longer part of the pack
for f in sorted(os.listdir(".")):
if f.endswith(".jar") and f not in keep:
os.unlink(f)
print(f" - {f} (stale)")
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 <<EOF
# Generated by Reaper's Sky deploy.sh
server-ip=$SERVER_IP
server-port=25565
motd=$MOTD
max-players=$MAX_PLAYERS
online-mode=true
difficulty=hard
level-type=default
allow-nether=true
spawn-protection=0
view-distance=10
simulation-distance=10
EOF
log "Wrote server.properties (IP=$SERVER_IP, max=$MAX_PLAYERS)."
}
# --- 5. run script ---------------------------------------------------------------
write_run() {
cat > "$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"