#!/usr/bin/env bash set -euo pipefail # ── Minecraft Bedrock Server Installer ── v3.0 ── apt update apt install -y unzip wget screen curl ca-certificates jq if ! id -u minecraft >/dev/null 2>&1; then useradd -r -m -s /bin/bash minecraft; fi mkdir -p /opt/minecraft-bedrock chown -R minecraft:minecraft /opt/minecraft-bedrock cd /opt/minecraft-bedrock # Fetch latest Linux ZIP link via official services API with HTML fallback # NOTE: Regex matches both old (1.x.x) and new (26.x) Mojang versioning schemes API_JSON=$(curl -fsSL "https://net-secondary.web.minecraft-services.net/api/v1.0/download/links" 2>/dev/null || true) LATEST_URL=$(printf '%s' "$API_JSON" | jq -r '.result.links[] | select(.downloadType=="serverBedrockLinux") | .downloadUrl // empty' 2>/dev/null || true) if [[ -z "${LATEST_URL:-}" ]]; then HTML=$(curl -fsSL --http1.1 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36" "https://www.minecraft.net/en-us/download/server/bedrock" 2>/dev/null || true) LATEST_URL=$(printf '%s' "$HTML" | grep -Eo 'https://www\.minecraft\.net/bedrockdedicatedserver/bin-linux/bedrock-server-[0-9.]+\.zip' | head -1 || true) fi if [[ -z "${LATEST_URL:-}" ]]; then echo "ERROR: Could not find Bedrock server URL" >&2 exit 1 fi # HEAD check for MIME type and optional size if ! curl -fsSI --http1.1 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36" "$LATEST_URL" | grep -iqE '^content-type:\s*(application/x-zip-compressed|application/zip|application/octet-stream)'; then echo "ERROR: Unexpected Content-Type for Bedrock ZIP (must be application/zip or octet-stream)" >&2 exit 1 fi echo "Downloading: $LATEST_URL" curl -fL --http1.1 -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36" --retry 3 --retry-delay 2 -o bedrock-server.zip "$LATEST_URL" zip_size=$(stat -c '%s' bedrock-server.zip) if (( zip_size < 1048576 )); then # 1MB sanity check echo "ERROR: Downloaded bedrock-server.zip is too small (${zip_size} bytes)." >&2 exit 1 fi ACTUAL_SHA=$(sha256sum bedrock-server.zip | awk '{print $1}') echo "bedrock-server.zip sha256: ${ACTUAL_SHA}" # Checksum enforcement: # REQUIRE_BEDROCK_SHA=0 (default) – SHA is computed and printed; no pre-set value required. # REQUIRE_BEDROCK_SHA=1 – strict mode; set REQUIRED_BEDROCK_SHA256 before running. # Mojang does not publish upstream checksums, so default is 0. # To record a known-good SHA for future verification: note the printed sha256 above. if [[ "${REQUIRE_BEDROCK_SHA:=0}" = "1" ]]; then if [[ -z "${REQUIRED_BEDROCK_SHA256:-}" ]]; then echo "ERROR: REQUIRE_BEDROCK_SHA=1 but REQUIRED_BEDROCK_SHA256 is not set." >&2 echo " Run once with REQUIRE_BEDROCK_SHA=0, record the printed SHA, then set REQUIRED_BEDROCK_SHA256." >&2 exit 1 fi if [[ "${ACTUAL_SHA}" != "${REQUIRED_BEDROCK_SHA256}" ]]; then echo "ERROR: SHA256 mismatch (expected ${REQUIRED_BEDROCK_SHA256}, got ${ACTUAL_SHA})" >&2 exit 1 fi echo "SHA256 verified against REQUIRED_BEDROCK_SHA256." else echo "INFO: Checksum enforcement disabled (REQUIRE_BEDROCK_SHA=0). Record the SHA above if strict mode is needed." fi # Test and extract the archive unzip -tq bedrock-server.zip >/dev/null unzip -o bedrock-server.zip && rm -f bedrock-server.zip if [[ ! -f bedrock_server ]]; then echo "ERROR: bedrock_server binary missing after extraction" >&2 exit 1 fi cat > start.sh <<'E2' #!/usr/bin/env bash exec env LD_LIBRARY_PATH=. ./bedrock_server E2 chmod +x start.sh chown -R minecraft:minecraft /opt/minecraft-bedrock # Ensure screen runtime directory exists with correct ownership and mode # NOTE: Required on Debian 12/13 so screen can create sockets. # In LXC, utmp group may not exist; fall back to root:root with 0777 if getent group utmp >/dev/null 2>&1; then install -d -m 0775 -o root -g utmp /run/screen || true printf 'd /run/screen 0775 root utmp -\n' > /etc/tmpfiles.d/screen.conf else install -d -m 0777 -o root -g root /run/screen || true printf 'd /run/screen 0777 root root -\n' > /etc/tmpfiles.d/screen.conf fi systemd-tmpfiles --create /etc/tmpfiles.d/screen.conf || true if command -v runuser >/dev/null 2>&1; then runuser -u minecraft -- bash -lc 'cd /opt/minecraft-bedrock && screen -dmS bedrock ./start.sh' else su -s /bin/bash -c 'cd /opt/minecraft-bedrock && screen -dmS bedrock ./start.sh' minecraft fi echo "✅ Bedrock setup complete. Attach: screen -r bedrock"