#!/bin/bash # Minecraft Bedrock server startup script for HuggingFace Spaces # No set -e — we handle errors explicitly LOG_DIR="/data/logs" MC_DIR="/data/bedrock-server" SCRIPTS_DIR="/data/scripts" PLAYIT_LOG="$PLAYIT_HOME/playit.log" MC_LOG="$LOG_DIR/minecraft.log" STATUS_FILE="/tmp/mc_status.json" mkdir -p "$LOG_DIR" # ── Write initial status ────────────────────────────────────────────── write_status() { cat > "$STATUS_FILE" </dev/null || echo 'unknown')" } EOF } MC_ONLINE=false PLAYIT_ONLINE=false TUNNEL_ADDR="" STARTED_AT=$(date -Iseconds) write_status # ── Graceful shutdown handler ───────────────────────────────────────── shutdown_handler() { echo "" echo "$(date) [SHUTDOWN] Signal received — shutting down gracefully..." # Stop Minecraft if [ -n "$MC_PID" ] && kill -0 "$MC_PID" 2>/dev/null; then echo "$(date) [SHUTDOWN] Stopping Minecraft (PID $MC_PID)..." kill -SIGTERM "$MC_PID" wait "$MC_PID" 2>/dev/null echo "$(date) [SHUTDOWN] Minecraft stopped." fi # Stop playit if [ -n "$PLAYIT_PID" ] && kill -0 "$PLAYIT_PID" 2>/dev/null; then echo "$(date) [SHUTDOWN] Stopping playit (PID $PLAYIT_PID)..." kill -SIGTERM "$PLAYIT_PID" wait "$PLAYIT_PID" 2>/dev/null fi # Final backup before exit echo "$(date) [SHUTDOWN] Running final backup..." bash "$SCRIPTS_DIR/backup.sh" || true echo "$(date) [SHUTDOWN] Done. Goodbye!" exit 0 } trap 'shutdown_handler' SIGTERM SIGINT SIGHUP # ── Banner ──────────────────────────────────────────────────────────── echo "=======================================================" echo " ⛏️ Alpha MC — Minecraft Bedrock Server" echo "=======================================================" echo " Started : $(date)" echo " CPU : $(nproc) cores" echo " RAM : $(free -h | awk '/Mem:/{print $3 " used / " $2 " total"}')" echo " Disk : $(df -h /data | awk 'NR==2{print $3 " used / " $2 " total (" $5 " full)"}')" echo "=======================================================" echo "" # ── Validate SECRET_KEY ─────────────────────────────────────────────── if [ -z "$SECRET_KEY" ]; then echo "╔══════════════════════════════════════════════════════╗" echo "║ ⚠️ WARNING: SECRET_KEY is not set! ║" echo "║ Tunnel will NOT work. ║" echo "║ Add it in: Space Settings → Repository Secrets ║" echo "╚══════════════════════════════════════════════════════╝" fi # ── Status dashboard on port 7860 (keeps HF from pausing) ──────────── echo "[*] Starting status dashboard on port 7860..." python3 "$MC_DIR/status_server.py" > "$LOG_DIR/status_server.log" 2>&1 & STATUS_PID=$! echo "[OK] Status dashboard started (PID $STATUS_PID) → visit the Space URL!" # ── Cron daemon ─────────────────────────────────────────────────────── service cron start 2>/dev/null && echo "[OK] Cron started" || echo "[!] Cron unavailable (non-fatal)" crontab /data/crontab.txt 2>/dev/null || true # ── Setup playit.gg tunnel ──────────────────────────────────────────── mkdir -p "$PLAYIT_HOME" cat > "$PLAYIT_HOME/playit.toml" << 'EOF' [tunnel.minecraft-bedrock] type = "minecraft-bedrock" local_ip = "127.0.0.1" local_port = 19132 EOF > "$PLAYIT_LOG" echo "[*] Starting playit tunnel agent..." playit --secret "$SECRET_KEY" >> "$PLAYIT_LOG" 2>&1 & PLAYIT_PID=$! echo "[OK] playit started (PID $PLAYIT_PID)" # ── Wait for tunnel to establish ────────────────────────────────────── echo "" echo "══════════════ WAITING FOR PLAYIT TUNNEL ══════════════" FOUND=0 for i in $(seq 2 2 180); do sleep 2 if ! kill -0 "$PLAYIT_PID" 2>/dev/null; then echo "[!] playit crashed. Log:" tail -20 "$PLAYIT_LOG" echo "[!] Will continue without tunnel — restart Space to retry." break fi CLAIM=$(grep -oE 'https://playit\.gg/claim/[A-Za-z0-9_=+-]+' "$PLAYIT_LOG" 2>/dev/null | head -1) if [ -n "$CLAIM" ]; then echo "" echo "╔══════════════════════════════════════════════════════╗" echo "║ 🔗 CLAIM YOUR TUNNEL — open this URL: ║" echo "║ $CLAIM" echo "║ Tunnel will activate after you visit the link. ║" echo "╚══════════════════════════════════════════════════════╝" FOUND=1 PLAYIT_ONLINE=true break fi ADDR=$(grep -oE '[a-z0-9-]+\.playit\.gg(:[0-9]+)?' "$PLAYIT_LOG" 2>/dev/null | head -1) if [ -n "$ADDR" ]; then echo "" echo "╔══════════════════════════════════════════════════════╗" echo "║ ✅ TUNNEL IS LIVE! ║" echo "║ Connect in Minecraft: $ADDR" echo "╚══════════════════════════════════════════════════════╝" TUNNEL_ADDR="$ADDR" FOUND=1 PLAYIT_ONLINE=true break fi echo " [${i}s] waiting for tunnel..." done if [ "$FOUND" -eq 0 ]; then echo "[!] No tunnel after 180s. Continuing anyway." tail -20 "$PLAYIT_LOG" fi # ── Start Minecraft Bedrock server ──────────────────────────────────── echo "" echo "[*] Starting Minecraft Bedrock server..." cd "$MC_DIR" ./bedrock_server >> "$MC_LOG" 2>&1 & MC_PID=$! # Wait a moment and confirm it's running sleep 3 if kill -0 "$MC_PID" 2>/dev/null; then echo "[OK] Minecraft started (PID $MC_PID)" MC_ONLINE=true else echo "[!] Minecraft failed to start. Check logs: $MC_LOG" tail -20 "$MC_LOG" fi write_status # ── Background services ─────────────────────────────────────────────── "$SCRIPTS_DIR/monitor.sh" & echo "[OK] Monitor started (PID $!)" "$SCRIPTS_DIR/health_check.sh" & echo "[OK] Health check started (PID $!)" echo "" echo "══════════════════════════════════════════════════════" echo " 🎮 Server is running! Dashboard at the Space URL." echo "══════════════════════════════════════════════════════" echo "" # ── Keep container alive, refresh status every 30s ─────────────────── while true; do sleep 30 # Update online status if kill -0 "$MC_PID" 2>/dev/null; then MC_ONLINE=true else MC_ONLINE=false echo "$(date) [WARN] Minecraft not running — health_check.sh will restart it." fi if kill -0 "$PLAYIT_PID" 2>/dev/null; then PLAYIT_ONLINE=true else PLAYIT_ONLINE=false fi write_status done