# FMS Admin ![Dashboard](docs/img/dashboard.png) A self-hosted web panel for running several Minecraft servers on one Windows machine. Go backend (net/http + SQLite) serving a React SPA, sitting behind Caddy for TLS. ## Features - Login with username + password + TOTP (all required); admin and user roles, with per-server access grants - Multiple servers: each runs as its own NSSM service and has its own pages, metrics and command whitelist. Admins can register existing servers or create new ones (vanilla, Fabric, Paper, Purpur, Forge, NeoForge; any version) from the panel, which downloads the jar or runs the installer, writes `server.properties` and registers the service - Dashboard: status, uptime, RAM, CPU and player count with live charts, start/stop/restart, and per-session metric history - Console: live tail of `latest.log` plus a whitelisted RCON command input - Mods: list, enable/disable (`.jar` ↔ `.jar.disabled`), delete, drag-drop upload (`.jar`, max 100MB), bulk enable/disable, with a "restart required" prompt - Datapacks: list with live enabled state via RCON, enable/disable (`/datapack` + `/reload`, response shown), delete, drag-drop upload (`.zip`, max 50MB), bulk actions - Properties: typed editor for `server.properties` (toggles, numbers, dropdowns for gamemode/difficulty/level-type), per-key modified badges, save gated behind an acknowledgement, change diff plus restart prompt after saving - Backups: list/download/upload/restore/delete zipped world backups; create on demand (`save-all flush` → `save-off` → zip → `save-on`) with progress polling; restore stops the server and replaces the world; auto-prune backups past the retention window - Players: everyone seen on the server, with kick/ban/op/whitelist actions; actions taken while the server is offline are queued and sent on next start - Logs and crash reports: browse and read old logs and crash reports - Server settings (admin): JVM heap and arguments, ports, and a raw file editor - Inbox: messages between panel users - Audit log: every login attempt, server action, and destructive file operation ### Destructive-action safety Every destructive action goes through a confirmation modal with a red warning that states exactly what will happen. Delete and restore require typing the exact filename; bulk actions require typing the verb in caps (`ENABLE ALL` / `DISABLE ALL`); stop and restart require typing `STOP` / `RESTART`; restoring a backup also requires re-entering your password. Each is recorded in the audit log (who, when, what, source IP). ## Layout ``` backend/ Go server (build the exe here; config.yaml + static/ live next to it) frontend/ Vite + React + Tailwind SPA (builds into ../backend/static) config.example.yaml Caddyfile ``` ## Try it locally The panel builds and runs on macOS, Linux or Windows without a Minecraft server. Server control, RCON and the file pages report errors, but login, the dashboard, user management and the audit log all work. ```sh cd frontend && npm install && npm run build cd ../backend && go build -o fms-admin . cp ../config.example.yaml config.yaml ./fms-admin createadmin --username admin # prints a TOTP secret ./fms-admin ``` Add the TOTP secret to an authenticator app, then open http://127.0.0.1:8080. Chrome and Firefox keep the `Secure` session cookie on `127.0.0.1` and `localhost`, so plain HTTP works for local testing. ## Prerequisites - Go 1.23+ - Node.js 18+ (for building the frontend) - NSSM-managed Windows service for the Minecraft server (`MinecraftServer`) - RCON enabled in `server.properties` (`enable-rcon=true`, matching port/password) ## Build ### 1. Frontend (outputs to backend/static) ```powershell cd frontend npm install npm run build ``` ### 2. Backend ```powershell cd backend go mod tidy # populates go.sum and indirect deps go build -o fms-admin.exe . ``` ## Configure Copy the example config next to the exe and fill in the secrets: ```powershell Copy-Item ..\config.example.yaml .\config.yaml ``` Edit `backend\config.yaml`: - `minecraft.rcon_password` - must match `rcon.password` in server.properties - `minecraft.log_file` - path to latest.log (forward slashes are fine on Windows) - `security.session_secret` - any 64-char random string - `files.mods_dir` / `files.datapacks_dir` / `files.properties_file` / `files.backups_dir` - paths the file-management pages operate on (forward slashes) - `files.max_upload_mb` - upload cap (default 100); `files.backup_retention_days` - auto-delete backups older than this many days (default 30; set 0 to keep forever) - `provisioning.servers_root` / `java_path` / `nssm_path` - needed only for creating new servers from the panel; each one gets a folder under `servers_root` and a service named `mc-`. `default_min_ram` / `default_max_ram` and `base_server_port` / `base_rcon_port` set the defaults for new servers The `minecraft` and `files` blocks only seed the first server on first start. After that, servers are stored in the database and edited from the Servers page. ## Create the first admin ```powershell cd backend .\fms-admin.exe createadmin --username admin ``` You will be prompted for a password (no echo). The command prints a TOTP secret and an `otpauth://` URL. Paste the URL into a QR generator, or type the secret into an authenticator app (Google Authenticator, Aegis, 1Password, etc.). The secret is shown once only. Repeat for each admin (up to 5). ## Run ```powershell cd backend .\fms-admin.exe ``` It listens on `127.0.0.1:8080`. Run it from the `backend` folder so it finds `config.yaml`, `data.db`, and `static/` in the working directory. To run it as a service under NSSM, set the service's **AppDirectory** to the `backend` folder so relative paths resolve. The account running fms-admin needs permission to control the `MinecraftServer` service (via `nssm`/`sc`) and to read the Java process info (uptime/RAM) and the log file - run it with appropriate privileges, or as the same account that owns the Minecraft service. ## Deploy behind Caddy Point a domain (`admin.example.com` in the provided `Caddyfile`) at the host's public IP, with 443 (and 80 for the ACME challenge) forwarded to the Caddy host. Merge the provided `Caddyfile` block into your existing Caddy config and reload. Caddy terminates TLS and proxies to the Go app on localhost; it forwards `X-Forwarded-For`, which the app uses for audit IPs. Note: session cookies are flagged `Secure`, so from any address other than `127.0.0.1` or `localhost` login only works over HTTPS. For frontend work, run `npm run dev` in `frontend` (proxies `/api` to the backend). ## Security model - Passwords hashed with Argon2id (alexedwards/argon2id default params) - TOTP via pquerna/otp, secret generated at user creation - Server-side sessions in SQLite; token is 32 random bytes, base64url - Cookies: HttpOnly, Secure, SameSite=Strict, 24h expiry - CSRF: custom `X-CSRF-Token` header must equal the session token on every POST/DELETE (the SPA recovers it from `/api/me` after reload) - Login rate limit: 5 failures per username = 15 minute lockout (in-memory) - Response headers: HSTS, X-Frame-Options DENY, X-Content-Type-Options nosniff, CSP - RCON command whitelist; anything outside it is rejected with "command not allowed" ## License MIT