6.4 KiB
Admin guide
Deploying the panel
cp .env.example .env # set ADMIN_PASSWORD
docker compose up -d --build
docker compose logs -f panel # first start prints the admin account
Everything the panel stores lives in the panel-data volume (/data):
| Path | What |
|---|---|
panel.db |
SQLite database (users, instances, settings, stats) |
files/<instance>/ |
Configs and uploads hosted for launchers |
uploads/ |
Logos, backgrounds, icons |
jwt.secret |
Token signing key (unless JWT_SECRET is set) |
Backups: stop the container (or use sqlite3 panel.db ".backup backup.db") and copy the volume.
Updating this checkout: docker compose up -d --build. Database migrations run automatically.
HTTPS
Launchers talk to the panel over the internet, so serve it over HTTPS. Example with Caddy:
panel.example.com {
reverse_proxy localhost:8080
}
Large modpack uploads go through the proxy — raise its body-size limit if needed (nginx: client_max_body_size 2g;).
Instances
An instance = one playable profile: a Minecraft version, an optional mod loader, files (mods, configs…) and an optional server.
- Version — choose any Minecraft version and Vanilla / Fabric / Quilt / Forge / NeoForge. Leave the loader version empty for the latest recommended build (it's pinned when you save).
- Modrinth — search, pick a version, Use. Mods are downloaded by players straight from Modrinth's CDN; configs (
overrides/) are hosted by the panel. - CurseForge — needs a free API key from console.curseforge.com (Settings → Integrations, or
CURSEFORGE_API_KEY). Some authors block third-party downloads; those files show up under Files with a link — download them yourself and upload them into the same folder. - Upload .zip — a
.mrpack, a CurseForge export, or any zipped instance folder (withmods/,config/, … or a.minecraft/inside). For plain zips, pick the Minecraft version and loader. - Files — add or remove individual files at any time. Files players add themselves are never touched; files you remove are deleted from players' instances on their next launch.
Every save bumps the instance revision; launchers re-verify files when it changes, otherwise launching is instant.
Built-in server
On the Server tab: name, address, port.
- Add to multiplayer list writes the server into
servers.dat(keeping servers players added). - Join automatically connects on start (Quick Play on 1.20+,
--serveron older versions).
Official servers use online-mode=true, authlib-injector and the SCOPENET server integration. See server setup for the startup flag, tokens and supported versions.
Access
- Everyone — any launcher, including local offline accounts.
- Signed-in players — any panel account.
- Specific groups — members of the selected groups (create groups on the Players page). Admins see everything.
Players
- Sign-ups: Settings → Closed (admins create accounts), Needs approval, or Open.
- Each account has a permanent UUID. New accounts receive a random UUID; existing accounts keep theirs. Username changes preserve inventory and reserve prior names. Players change username, skin and permitted capes from the launcher.
- Disabling an account signs it out everywhere on the next request.
- Ten failed logins lock an account for five minutes.
- Username blacklist: Settings → Username blacklist. Each entry matches a complete name; wrap it as
*word*to block it inside longer names. The short starter list covers obvious offensive terms and can be edited. New registrations, admin-created accounts, Discord-created accounts, and username changes all use it.
Discord and password reset email
Set Settings → Auth server → Public address to the HTTPS URL players use. In Settings → Discord, save the application client ID and client secret, and add https://your-panel.example/api/v1/auth/discord/callback to the Discord application's OAuth2 redirect URLs. Players can sign in with Discord in the launcher or connect an existing account under Accounts → Connections → Discord. With registration closed, Discord sign-in works for linked accounts only; open or approval mode can create new player accounts.
In Settings → Resend SMTP, save a Resend API key and a sender email from a verified domain. The panel sends password reset links through smtp.resend.com over TLS. A reset link expires after 30 minutes and works once. Use Send a test email and check the destination inbox and Resend activity log: SMTP acceptance confirms submission, while the inbox confirms delivery. Credentials are stored in the panel data volume and are not returned to the browser after saving; protect the volume and restrict access to the Admin Panel.
Launcher design
Everything on this page is pushed to launchers when they start or refresh — no reinstall. The Features tab lets you allow or block players from changing the theme or Java settings. Custom CSS is injected last; handy variables are --accent, --accent-2, --surface, --radius.
Releasing the launcher
See the README's Build your branded launcher. Players get updates automatically: the launcher checks Gitea Releases on start and offers the new installer.
Code signing: unsigned installers trigger a Windows SmartScreen warning ("More info → Run anyway"). To avoid it, sign the installer with a code-signing certificate (e.g. Azure Trusted Signing) — Tauri supports this via bundle.windows.signCommand.
Progression (quests, XP, levels)
Progression in the sidebar controls how players advance:
- Quest limits – how many daily and weekly quests each player is given (0 = every enabled quest), and whether everyone draws their own set or shares one. Pin quests on the Quests page to always include them. A player's set is stored when they first open their quests for the period, so edits never swap out quests they've started.
- XP & levels – the level curve (
round(base × L^exponent), optional max level), XP per playtime hour / kill / block / message, and panel-wide multipliers that stack with each server's own. Saving a new curve recalculates stored levels; nobody loses XP. - Players – search a player, then give, take, set or reset XP (global or per server) or set their level. Changes are recorded in the Activity log with your reason.