# 📖 Alpha MC — Complete Setup Guide > Everything explained: what every file does, how to set it up, and how it all works together. --- ## 📋 Table of Contents 1. [How It All Works](#how-it-all-works) 2. [File-by-File Explanation](#file-by-file-explanation) 3. [Step-by-Step Setup](#step-by-step-setup) 4. [HuggingFace Secrets Reference](#huggingface-secrets-reference) 5. [Google Drive Backup Setup](#google-drive-backup-setup) 6. [How to Connect and Play](#how-to-connect-and-play) 7. [Troubleshooting](#troubleshooting) 8. [FAQ](#faq) --- ## How It All Works ``` ┌─────────────────────────────────────────────────────┐ │ HuggingFace Space (Docker) │ │ │ │ ┌──────────────┐ ┌─────────────────────────┐ │ │ │ Minecraft │ │ Status Dashboard │ │ │ │ Bedrock │ │ (port 7860, HTTP) │ │ │ │ Server │ │ Shows: status, logs, │ │ │ │ (UDP 19132) │ │ tunnel address, RAM/CPU │ │ │ └──────┬───────┘ └─────────────────────────┘ │ │ │ │ │ ┌──────▼───────┐ ┌─────────────────────────┐ │ │ │ playit.gg │ │ Cron Jobs │ │ │ │ agent │ │ - Backup every 6 hours │ │ │ │ (tunnel) │ │ - Log rotation weekly │ │ │ └──────┬───────┘ └─────────────────────────┘ │ └─────────┼───────────────────────────────────────────┘ │ UDP tunnel ▼ playit.gg servers │ ▼ Your friends' Minecraft (anywhere in the world) ``` **Why playit.gg?** HuggingFace Spaces only expose HTTP (TCP) ports publicly. Minecraft Bedrock uses UDP, which HF doesn't support directly. playit.gg acts as a free UDP tunnel — the Minecraft server connects outward to playit.gg, and players connect to playit.gg's address. **Why port 7860?** HuggingFace watches this port. If nothing responds on 7860, it marks your Space as "idle" and pauses it. Our status dashboard runs on 7860 and keeps it alive. --- ## File-by-File Explanation ### 🐳 `Dockerfile` The main blueprint Docker uses to build your container. **What it does, line by line:** - `FROM ubuntu:22.04` — Starts with a clean Ubuntu Linux environment - `ENV DEBIAN_FRONTEND=noninteractive` — Stops apt-get from asking questions during install - `apt-get install` — Installs tools: curl/wget (downloading), unzip (extracting), python3 (status server + Drive backup), cron (scheduled jobs) - `pip install` — Installs Python libraries for Google Drive API - `mkdir -p` — Creates the folder structure: `/data/bedrock-server/`, `/data/scripts/`, `/data/logs/`, `/data/playit_gg/` - `COPY prepare.sh ... && RUN bash prepare.sh` — Runs the download script at build time (downloads Minecraft + playit) - `WORKDIR /data/bedrock-server` — Sets the default directory (fixes the path bug from before) - `COPY server.properties allowlist.json permissions.json ./` — Copies game config INTO the server folder - `COPY start.sh run.sh status_server.py ./` — Copies startup scripts into server folder - `COPY backup.sh ... /data/scripts/` — Copies utility scripts to their own folder - `chmod +x` — Makes all `.sh` scripts executable (runnable) - `EXPOSE 7860 19132/udp 19133/udp` — Declares which ports the container uses - `CMD ["bash", "/data/bedrock-server/start.sh"]` — The command that runs when the container starts --- ### 🔧 `prepare.sh` Runs **once during Docker build** to download Minecraft and playit. **What it does:** 1. Fetches the Minecraft.net download page with a browser-like User-Agent (so the site doesn't block it) 2. Tries 3 different URL patterns to extract the Bedrock server download link (in case the page layout changes) 3. Downloads the `.zip` with retry logic (retries up to 4 times with exponential backoff: 5s, 10s, 20s) 4. Extracts it to `/data/bedrock-server/` 5. Downloads the latest `playit-linux-amd64` binary from GitHub releases 6. Makes both executables **Why it runs at build time:** So the Minecraft server binary is baked into the Docker image. Every time your Space restarts, Minecraft is already there — no download wait. --- ### 🚀 `start.sh` The **main startup script** — this is what runs every time your Space starts. **What it does, in order:** 1. **Sets up graceful shutdown** — catches SIGTERM signal (when HF stops the container), runs a final backup, stops Minecraft cleanly before exiting 2. **Prints a banner** with system info (CPU cores, RAM, disk) 3. **Warns if SECRET_KEY is missing** so you know immediately if the tunnel won't work 4. **Starts `status_server.py`** on port 7860 — the live dashboard (also prevents HF from pausing the Space) 5. **Starts cron daemon** for scheduled backups and log rotation 6. **Configures playit.toml** — tells playit.gg which local port to tunnel (19132 UDP) 7. **Starts the playit agent** with your SECRET_KEY 8. **Waits up to 180 seconds** for the tunnel to show a claim URL or live address, printing progress every 2 seconds 9. **Starts `bedrock_server`** (the actual Minecraft process), redirecting its output to `/data/logs/minecraft.log` 10. **Starts monitor.sh and health_check.sh** in the background 11. **Keeps running** in a loop, updating the status JSON file every 30 seconds and watching if Minecraft/playit are still alive **Key fixes from original:** - No `set -e` (crashes won't kill the whole script) - Proper SIGTERM trap for graceful shutdown - Status JSON written continuously so the dashboard has fresh data --- ### 🌐 `status_server.py` A Python HTTP server that serves a **live web dashboard** on port 7860. **What it shows:** - 🟢/🔴 Server online/offline status - RAM usage (used / total) - Disk usage (used / total / percent) - CPU load average - Tunnel address to copy into Minecraft - Last 40 lines of the Minecraft server log (auto-scrolled) **How it works:** - Reads `/tmp/mc_status.json` (written by `start.sh` every 30 seconds) - Reads the last 40 lines of `/data/logs/minecraft.log` using the `tail` command - Reads the playit log to extract the tunnel address - Generates a full HTML page on every request - Page auto-refreshes every 15 seconds via a `` tag - No dependencies needed beyond Python's built-in `http.server` **Why this matters:** Without something running on port 7860, HuggingFace marks your Space as idle within minutes and pauses it. This keeps it alive 24/7. --- ### ⚙️ `server.properties` The Minecraft Bedrock server configuration file. | Setting | Value | Explanation | |---|---|---| | `server-name` | Gaganpreet's Minecraft Server | Name shown in the server browser | | `gamemode` | survival | Players are in survival mode | | `difficulty` | hard | Hard difficulty | | `allow-cheats` | false | No commands like /gamemode | | `max-players` | 20 | Up to 20 players at once | | `online-mode` | true | Requires legitimate Xbox/Microsoft account | | `white-list` | false | Anyone can join (set to true + edit allowlist.json to restrict) | | `server-port` | 19132 | Main UDP port (IPv4) | | `server-portv6` | 19133 | IPv6 UDP port | | `view-distance` | 10 | Chunks loaded around each player | | `tick-distance` | 4 | Active simulation distance | | `player-idle-timeout` | 30 | Kick players idle for 30 minutes | | `level-name` | Bedrock level | Name of the world folder | | `level-seed` | *(blank)* | Random seed — fill in a number for a specific world | | `server-authoritative-movement` | server-auth | Server controls player movement (anti-cheat) | --- ### 📋 `allowlist.json` Controls who can join if `white-list=true` in server.properties. **Default:** Empty array `[]` — whitelist is disabled so anyone can join. **To add a player:** ```json [ { "ignoresPlayerLimit": false, "name": "PlayerGamerTag", "xuid": "2535123456789" } ] ``` Get a player's XUID from sites like xuidgrabber.com. --- ### 🔑 `permissions.json` Sets operator/member/visitor permissions for specific players. **Default:** Empty `[]` — everyone gets the `default-player-permission-level` from server.properties. **To make someone an operator:** ```json [ { "permission": "operator", "xuid": "2535123456789" } ] ``` --- ### 💾 `backup.sh` Creates world backups locally and optionally uploads to Google Drive. **What it does:** 1. Checks if the worlds folder exists and has data 2. Creates a `.tar.gz` archive of the entire `worlds/` folder with a timestamp in the filename (e.g. `world_20240425_143000.tar.gz`) 3. Saves it to `/data/bedrock-server/backups/` 4. Prunes old backups — keeps only the 10 most recent 5. If `GDRIVE_SA_KEY` secret is set → calls `google_drive_backup.py` to upload the new backup to Google Drive 6. If `GDRIVE_SA_KEY` is not set → logs a helpful message and skips Drive upload gracefully **Run manually:** `bash /data/scripts/backup.sh` --- ### ☁️ `google_drive_backup.py` Uploads the latest backup `.tar.gz` to a Google Drive folder using a **Service Account** (no browser, works headlessly). **How it's different from the original:** - Original used `InstalledAppFlow` → needs a browser popup → **impossible in Docker** - New version uses a **Service Account** → authenticates silently using a JSON key stored as a base64 HF Secret - Supports **resumable uploads** with 5 MB chunks → handles large world files reliably - Shows upload progress percentage - Auto-deletes oldest Drive backups beyond 10 files - Cleans up the temp credentials file after upload **Required HF Secret:** `GDRIVE_SA_KEY` (base64-encoded service account JSON — see setup below) --- ### 🏥 `health_check.sh` Runs in the background and **automatically restarts** Minecraft or playit if either crashes. **What it does (every 30 seconds):** 1. Checks if `bedrock_server` process is running — if not, restarts it 2. Checks if `playit` process is running — if not, restarts it with your SECRET_KEY 3. Logs all events with timestamps to `/data/logs/health.log` **Why this matters:** Without this, if Minecraft crashes at 3am while your friends are playing, the server stays down until you manually restart the Space. With this, it auto-recovers within 30 seconds. --- ### 📊 `monitor.sh` Logs system resource stats every 60 seconds to `/data/logs/monitor.log`. **Each log line contains:** timestamp, CPU load average, RAM used/total, disk used/total, Minecraft PID, playit PID. Useful for diagnosing performance issues or seeing exactly when the server went down. --- ### 🔄 `auto_restart.sh` A simple utility script to restart Minecraft after a delay. **Usage:** `bash /data/scripts/auto_restart.sh 10` — restarts after 10 seconds Called automatically by health_check.sh when needed. --- ### 🕐 `crontab.txt` Schedules automatic recurring tasks using cron. ``` 0 */6 * * * bash /data/scripts/backup.sh ``` → Runs backup.sh every 6 hours (at 00:00, 06:00, 12:00, 18:00) ``` 0 0 * * 0 truncate -s 0 /data/logs/*.log ``` → Every Sunday at midnight, clears all log files so they don't grow forever --- ### 🗺️ `run.sh` A simple wrapper that changes directory to the Minecraft server folder and runs `start.sh`. Kept for compatibility. --- ### 🔧 `setup_google_drive.sh` Run this **on your own computer** (not on HuggingFace) to walk through the Google Cloud setup and generate your `GDRIVE_SA_KEY`. It even base64-encodes the key file for you automatically if `service-account.json` is in the same folder. --- ## Step-by-Step Setup ### Step 1 — Upload all files to HuggingFace 1. Go to your Space: `https://huggingface.co/spaces/Gagan1322/alpha_mc` 2. Click **Files** tab → **Add file** → **Upload files** 3. Upload ALL of these files: ``` Dockerfile README.md prepare.sh start.sh run.sh status_server.py server.properties allowlist.json permissions.json backup.sh monitor.sh health_check.sh auto_restart.sh crontab.txt google_drive_backup.py setup_google_drive.sh ``` 4. Commit the changes --- ### Step 2 — Add your playit Secret Key 1. Go to your Space → **Settings** tab → **Repository secrets** 2. Click **New secret** 3. Name: `SECRET_KEY` 4. Value: your playit agent secret key from `https://playit.gg/account/agents` - **Regenerate your key first!** The old one was exposed in a screenshot. 5. Click **Add secret** --- ### Step 3 — Restart the Space 1. Go to the **App** tab of your Space 2. Click the **⋮** (three dots) menu → **Restart Space** 3. Wait 2-3 minutes for the Docker image to build (first time only) 4. The Space URL will show your live status dashboard --- ### Step 4 — Get the Tunnel Address 1. Open the Space URL in your browser 2. Look at the dashboard — when the tunnel is live, the **Connect Address** section shows something like: ``` abc123.playit.gg:12345 ``` 3. If it shows a **claim URL** instead: - Click that URL → sign into playit.gg → accept the tunnel - Wait 10 seconds → the dashboard will show the live address --- ### Step 5 — Connect in Minecraft 1. Open Minecraft Bedrock Edition on your phone/PC/console 2. Go to **Play** → **Servers** tab → **Add Server** 3. Server Address: paste the `*.playit.gg` address 4. Port: paste the port number after the colon (or leave as 19132 if no port shown) 5. Click **Save** → Join! --- ## HuggingFace Secrets Reference Add these in: Space → Settings → Repository Secrets | Secret Name | Required? | Description | |---|---|---| | `SECRET_KEY` | ✅ Yes | Your playit.gg agent secret key. Without this, nobody can join. | | `GDRIVE_SA_KEY` | ❌ Optional | Base64-encoded Google Service Account JSON. Enables Drive backups. | --- ## Google Drive Backup Setup ### Why Service Account instead of OAuth? The old `credentials.json` approach uses OAuth's "installed app" flow which **opens a browser to sign in**. Docker containers have no browser. It can never work headlessly. A Service Account authenticates with a static JSON key — no browser, no interaction, just works. ### Step-by-Step **1. Create a Google Cloud Project** - Go to https://console.cloud.google.com - Top bar → Select project → New Project → name it `alpha-mc` → Create **2. Enable Google Drive API** - APIs & Services → Library → search "Google Drive API" → Enable **3. Create a Service Account** - IAM & Admin → Service Accounts → Create Service Account - Name: `minecraft-backup` → Done - Click the new account → **Keys** tab → Add Key → Create new key → **JSON** → Download - This downloads something like `alpha-mc-abc123.json` — rename it to `service-account.json` **4. Share a Drive Folder with the Service Account** - Open Google Drive → New folder → name it exactly: `Minecraft-Bedrock-Backups` - Right-click the folder → Share - Open `service-account.json` and find the `"client_email"` field — copy that email address - Paste it in the share dialog → role: **Editor** → Share **5. Generate the GDRIVE_SA_KEY** On your computer (Linux/Mac terminal or Git Bash on Windows): ```bash base64 -w 0 service-account.json ``` This prints a long string of random-looking characters. Copy ALL of it. On Windows (PowerShell): ```powershell [Convert]::ToBase64String([IO.File]::ReadAllBytes("service-account.json")) ``` **6. Add to HuggingFace** - Space → Settings → Repository Secrets → New secret - Name: `GDRIVE_SA_KEY` - Value: paste the base64 string - Add secret → Restart Space **7. Verify** - Check `/data/logs/backup.log` after 6 hours - Should show: `Google Drive upload successful!` - Check your Google Drive folder — the backup `.tar.gz` should appear there ### Security Rules - ❌ NEVER commit `service-account.json` to git - ❌ NEVER upload credentials/key files to HuggingFace files tab - ❌ NEVER share your service account JSON publicly - ✅ ONLY store it as a HF Secret (encrypted, not visible in git history) --- ## How to Connect and Play ### Finding the Address The address is shown in two places: 1. **Status Dashboard** — open the Space URL in any browser 2. **Space Logs** — in the App tab logs, look for `TUNNEL IS LIVE` ### Sharing with Friends Just give them the `*.playit.gg:PORT` address. They need: - Minecraft Bedrock Edition (any platform — mobile, PC, Xbox, PlayStation, Switch) - Add Server → paste address → join ### Adding Friends to Allowlist (optional) If you want only specific people to join: 1. Set `white-list=true` in `server.properties` 2. Edit `allowlist.json` to add their gamertags and XUIDs 3. Re-upload both files and restart the Space --- ## Troubleshooting ### Space shows "Paused" - Click the Space → click **Run** or **Restart** - Make sure `SECRET_KEY` is set in secrets - The status dashboard on port 7860 should prevent future pausing ### "Tunnel not found" / no address shown - Check that `SECRET_KEY` is correct (regenerate on playit.gg if needed) - Open Space logs → look for playit errors - If you see a claim URL → click it and accept the tunnel on playit.gg website ### Build fails (Docker build error) - Check that ALL files listed in Step 1 are uploaded - The most common cause: a file is missing so `COPY` fails - Check the build logs for which `COPY` line failed ### Server starts but nobody can join - Make sure you're using the playit.gg address (NOT the HuggingFace URL) - The HF URL is HTTP only — Minecraft needs the playit.gg address - Check `online-mode` in server.properties — if `true`, players need a valid Microsoft account ### Minecraft crashes (server goes offline) - `health_check.sh` should auto-restart it within 30 seconds - Check `/data/logs/minecraft.log` for the crash reason - Common causes: out of RAM (HF free tier has limited RAM), corrupted world ### Google Drive backup fails - Check that `GDRIVE_SA_KEY` is set in HF Secrets - Verify the Drive folder is named exactly `Minecraft-Bedrock-Backups` - Verify the folder is shared with the service account email - Check `/data/logs/backup.log` for the specific error message ### Dashboard not loading / Space gets paused - `status_server.py` might have crashed - It should auto-recover but if not, restart the Space - Check `/data/logs/status_server.log` for Python errors --- ## FAQ **Q: Is this free?** A: Yes! HuggingFace Spaces (free tier) + playit.gg (free tier) = $0/month. The limitation is HF's free tier has limited RAM (~16GB shared) and CPU. **Q: Will the world be lost if the Space restarts?** A: No! HuggingFace persistent storage keeps `/data` between restarts. Your world is safe. Backups are extra insurance. **Q: How many players can join?** A: Up to 20 (set in server.properties). The actual limit depends on the HF server's available RAM — more players = more RAM. **Q: Can I use mods / behaviour packs?** A: Yes! Upload your pack files to the Space and place them in the correct Minecraft Bedrock folder under `/data/bedrock-server/`. This requires a bit of manual setup. **Q: How do I update the Minecraft server version?** A: Rebuild the Space (Settings → Factory reboot). `prepare.sh` always downloads the latest version from Minecraft.net. **Q: Can I change the world seed?** A: Yes — set `level-seed=` in `server.properties` to any number before the world is first created. Once a world exists, changing the seed has no effect. **Q: How do I give myself operator (admin) permissions?** A: Edit `permissions.json` with your XUID and set `"permission": "operator"`. Alternatively, if you're the first person to join, type your gamertag in the server console — but there's no easy console access on HF. **Q: The playit address changes every restart — how do I get a permanent address?** A: Upgrade to playit.gg Pro ($3/month) for a permanent subdomain. On the free tier the address changes each time. --- *Alpha MC Setup Guide — All files written and debugged for HuggingFace Spaces + playit.gg*