Minecraft Worlds
Quickstart: Bring a World Up
-
Allocate IP, SNI Route, and DNS:
sudo ipctl create <name> --dns(Or
/data/minecraft/ipctl create <name> --dns. Allocates backend IPv6fd77:7777:5010::1337:3c:d00d:<hex>/64, configures HAProxy SNI routing, adds<name>.drheck.devin Unbound ondanknasty, and syncs public A/AAAA records to deSEC). -
Configure the backend server: In your backend server's
server.properties:server-ip=fd77:7777:5010::1337:3c:d00d:<hex> server-port=25565 online-mode=true(Backend servers run stock vanilla Minecraft,
online-mode=true, listening on standard port25565). -
Start the server: Launch your Minecraft server on UL. It binds to its dedicated IPv6 address.
-
Connect: Players connect using
<name>.drheck.dev(standard port 25565). Microsoft account authentication takes place directly between the client and your backend server.
Quickstart: Take a World Down
-
Stop the backend server: Run
stopin the Minecraft server console or terminate its process. -
What Players See When Offline: HAProxy monitors backend health checks. If the server process is stopped:
- In the Multiplayer Server List: The ping MOTD displays:
[Server Name] is currently offline. Ping Luke - When Clicking "Join Server": The client immediately disconnects with a clean red Minecraft disconnect screen: "[Server Name] is currently offline. Ping Luke" (No connection timeouts, hanging, or generic connection refused errors).
- In the Multiplayer Server List: The ping MOTD displays:
-
Disable or remove router mapping & DNS (Teardown):
- Temporary takedown (disable in router only):
sudo ipctl route disable <name> - Complete teardown (release IP, remove HAProxy route, purge DNS):
sudo ipctl delete <name> --dns
- Temporary takedown (disable in router only):
Architecture & Design Details
1. Unified Endpoint Model
All public and LAN client connections resolve to the single Minecraft Router endpoint pair:
- IPv4:
10.0.0.113 - IPv6:
fd77:7777:5010::1337:f1ac:d00d:3c
Whether connecting via pokelovers.drheck.dev or any other server subdomain, players connect to this exact IP pair on standard port 25565.
2. Transparent TCP SNI Handshake Routing & Offline Fallback (HAProxy)
Rather than using an application-level proxy (which breaks vanilla Diffie-Hellman encryption and forces online-mode=false), HAProxy performs transparent pre-handshake packet inspection:
- HAProxy listens dual-stack on
10.0.0.113:25565and[fd77:7777:5010::1337:f1ac:d00d:3c]:25565. - When a player connects, HAProxy peeks at the initial unencrypted Minecraft handshake packet (
0x00) via/etc/haproxy/minecraft.luaand extracts the requested hostname (e.g.pokelovers.drheck.dev) and connection state (Status vs Login). - If the backend server is UP: It splices the raw TCP stream directly to that server's dedicated internal IPv6 address on port
25565. The client and backend perform native Microsoft/Mojangonline-mode=trueauthentication directly over the spliced TCP connection. - If the backend server is DOWN: HAProxy immediately handles the stream with Lua applet
mc_offlinewhich crafts and sends a valid Minecraft protocol packet:- Status Ping: JSON MOTD with red text:
<name> is currently offline. Ping Luke - Login Join: Disconnect packet
0x00rendering a red bold error screen:<name> is currently offline. Ping Luke
- Status Ping: JSON MOTD with red text:
3. Backend IPv6 Address Scheme
Each backend Minecraft server is isolated on a dedicated Unique Local Address (ULA) on interface eth77 of ul:
- Prefix:
fd77:7777:5010::1337:3c:d00d:<hex>/64 - Port: Each server binds to standard port
25565on its assigned IPv6 address. - Security: Backend IPv6 addresses are completely internal and hidden behind the proxy router.
4. Web Map (BlueMap) & Authentik Gated HTTPS
Interactive 3D web mapping for Minecraft 26.3 is powered by BlueMap running in standalone watch mode:
- Service:
bluemap-pokelovers.servicerunning from/data/minecraft/poke lovers/bluemap.- Automatically updates the rendered 3D map as chunks change in
/data/minecraft/poke lovers/world. - Serves live map data & Server-Sent Events (SSE) updates on internal port 8100.
- Automatically updates the rendered 3D map as chunks change in
- Reverse Proxy & Authentication: NGINX terminates SSL on port 443 at
/etc/nginx/sites-available/pokeloversand gates access behind Authentik ForwardAuth (/outpost.goauthentik.io/auth/nginx).- Serves directly at
https://pokelovers.drheck.dev. - Unauthenticated visitors are automatically redirected to
auth.drheck.devto log in before viewing the 3D map.
- Serves directly at
5. Network & DNS Automation (ipctl)
The tool /data/minecraft/ipctl (symlinked in /home/luke/bin/ipctl) automates the entire lifecycle:
- Local Network (
ul): Appends or removes# <name>andAddress=fd77:7777:5010::1337:3c:d00d:<hex>/64in/etc/systemd/network/20-wired.networkand triggersnetworkctl reload. - Router Configuration (
ul): Updates/etc/haproxy/minecraft_hosts.mapand backend stanzas (with health checks and offline responder) in/etc/haproxy/haproxy.cfg, then reloadshaproxy.service. - SSH Key Verification:
Verifies that key
SHA256:7Xr0vCxgfpPhbKE3hN9fE2IC9y4x3Kj+kYmXwzgJY3s(ultra-arikui) is loaded in the agent before running remote router commands. - Router DNS (
danknasty): When--dnsis passed:- Updates the git working tree at
/home/luke/git/router_config/unbound.conf. - Verifies syntax using
doas unbound-checkconf. - Deploys the configuration to
/var/unbound/etc/unbound.conf. - Restarts Unbound via
doas rcctl restart unbound. - Verifies local resolution via
dig @10.0.0.1. - Executes
python3 /home/luke/git/router_config/dns_danger_sync.py --forceto synchronize public A and AAAA records on deSEC.io.
- Updates the git working tree at
Backups & Disaster Recovery
The router configurations, Lua scripts, mapping tables, network configurations, and the ipctl tool are integrated into the automated backup infrastructure:
- Backup Script:
/home/luke/git/backups/ul/scripts/backup/minecraft_router- Creates timestamped, ACL/xattr-preserved,
par2-verified archives in/data/backups/services/current/minecraft_router/. - Automatically invoked during the global daily backup run (
run_all_backups).
- Creates timestamped, ACL/xattr-preserved,
- Restore Script:
/home/luke/git/backups/ul/scripts/restore/minecraft_router [timestamp]- Verifies PAR2 checksums/parity.
- Extracts configurations to
/and triggers live reloads ofsystemd-networkdandhaproxy.
6. Minecraft Server Manager & On-Demand Architecture (Design Specification)
Design Goal: Provide a unified web control plane (https://mc.drheck.dev, gated by Authentik) and daemon that formalizes what a Minecraft server is on ul, automates ipctl networking and systemd lifecycle management, wakes sleeping servers on-demand via HAProxy when players join, and provides an interactive seed-preview and modpack studio when creating new worlds.
6.1 Canonical Definition of a "Server"
Every managed Minecraft world on ul is a self-contained unit consisting of five standardized components:
$$\text{Server}(\text{slug}) = \left\lbrace\text{Directory}, \quad \text{Manifest } (\texttt{server.json}), \quad \text{Network } (\texttt{ipctl}), \quad \text{Units } (\texttt{systemd}), \quad \text{Lifecycle Policy}\right\rbrace$$
| Component | Path / Identifier | Description |
|---|---|---|
| 1. Dedicated Directory | /data/minecraft/<dir_name>/ |
Holds server.json, server .jar / libraries, mods/ or plugins/, server.properties, whitelist.json, ops.json, world/, and optional bluemap/. Existing worlds in /data/minecraft/* are adopted in-place without moving files. |
| 2. Declarative Manifest | /data/minecraft/<dir_name>/server.json |
Stores the human display name, DNS slug (<slug>), loader type (paper, vanilla, fabric, neoforge, forge, custom), Minecraft version, JVM path (/usr/lib/jvm/java-26-openjdk/bin/java), heap size (-Xms/-Xmx), custom modpack reference, seed, and lifecycle mode (manual, ondemand, always). |
3. Network & DNS (ipctl) |
fd77:7777:5010::1337:3c:d00d:<hex>/64 |
Dedicated internal IPv6 address on eth77, bound in server.properties (server-ip= and server-port=25565, plus internal RCON on port 25575), mapped in /etc/haproxy/minecraft_hosts.map, and published as <slug>.drheck.dev on danknasty Unbound and deSEC.io. |
4. Dedicated systemd Service |
minecraft@<slug>.service (+ optional bluemap@<slug>.service) |
Runs the server under systemd via /usr/local/bin/mc-launch <slug>. Selects the per-server JVM binary directly (never mutating the global archlinux-java symlink) and performs graceful RCON save-all + stop on shutdown. |
| 5. Lifecycle Policy | manual | ondemand | always |
Controls when the server consumes RAM on ul (see Section 6.2). |
Click to expand example /data/minecraft/poke lovers/server.json manifest
{
"name": "Poke Lovers",
"slug": "pokelovers",
"directory": "/data/minecraft/poke lovers",
"domain": "pokelovers.drheck.dev",
"bind_ipv6": "fd77:7777:5010::1337:3c:d00d:1",
"game_port": 25565,
"rcon_port": 25575,
"loader": "vanilla",
"mc_version": "26.3",
"jar_file": "server_26.3.jar",
"java_bin": "/usr/lib/jvm/java-26-openjdk/bin/java",
"memory_min_gb": 20,
"memory_max_gb": 20,
"use_aikars_flags": true,
"modpack": null,
"seed": "-41829401829401",
"lifecycle_mode": "ondemand",
"idle_shutdown_minutes": 20,
"bluemap_enabled": true,
"bluemap_port": 8100,
"owner": "luke",
"admins": ["luke", "ikura"],
"sync_ingame_ops": true
}
6.2 Resource Management & Server Lifecycle Modes
Because each active Minecraft JVM allocates $8\text{--}20\text{ GiB}$ of pinned heap memory (-Xms = -Xmx with +AlwaysPreTouch), running all $25+$ worlds in /data/minecraft simultaneously is impossible. Each server is assigned one of three lifecycle modes:
manual(Cold / Archived):minecraft@<slug>.serviceis disabled and stopped ($0\text{ GiB}$ RAM).- Only starts when explicitly clicked in the Web UI.
- When stopped, HAProxy returns:
<name> is currently offline. Ping Luke.
ondemand(Wake-on-Join + Idle Auto-Stop):- Stopped by default ($0\text{ GiB}$ RAM).
- Automatically started when a player clicks Join Server in Minecraft (intercepted by HAProxy Lua).
- Automatically stopped (
save-all$\longrightarrow$stop) once $0$ players have been online continuously for $T_{\text{idle}}$ minutes (default $20\text{ min}$).
always(Pinned Production):minecraft@<slug>.serviceis enabled and active across host reboots (systemctl enable --now).- Used for primary worlds that should remain online $24/7$ regardless of player count.
6.3 HAProxy On-Demand Wake-on-Join Architecture
The Minecraft protocol sends a Handshake packet (0x00) at the start of every TCP connection containing a Next State VarInt:
- $\text{Next State} = 1$ (Status Ping): Sent when a client refreshes their Multiplayer Server List (or when internet bots scan port
25565). - $\text{Next State} = 2$ (Login Join): Sent only when a player clicks Join Server.
/etc/haproxy/minecraft.lua already extracts both txn.mc_host and txn.mc_state. Extending mc_offline enables zero-overhead on-demand activation without waking servers on server-list pings:
$$\text{Client Packet } (\texttt{0x00}) \longrightarrow \begin{cases} \text{state} = 1 \text{ (Status Ping)} & \longrightarrow \text{Return JSON MOTD } (\text{Sleeping / Starting / Offline}) \text{ without waking} \\ \text{state} = 2 \text{ (Login Join)} & \longrightarrow \text{If } \texttt{ondemand}\text{: trigger } \texttt{mc-manager} \text{ wake socket + return countdown packet} \end{cases}$$
State Machine for ondemand Worlds
| Server State | Multiplayer List Ping (state = 1) MOTD |
Player Clicks "Join Server" (state = 2) |
|---|---|---|
SLEEPING |
§e⚡ <name> is sleeping (On-Demand) §7— §aClick Join to wake! |
HAProxy Lua sends WAKE <slug> to /run/mc-manager/wake.sock, transitions server to STARTING, and disconnects client with: "⚡ Waking up <name>... Server will be ready in ~20 seconds!" |
STARTING |
§6⏳ <name> is booting up... §7Please wait ~15s |
Disconnects client with live elapsed timer: "⏳ <name> is currently booting (12s elapsed)... Rejoin in a few seconds!" |
ONLINE |
Native backend MOTD + live player count (spliced directly to backend JVM) | Native TCP splice to [fd77:7777:5010::1337:3c:d00d:<hex>]:25565 with full Microsoft online-mode=true auth |
OFFLINE (manual) |
§c<name> is currently offline. Ping Luke |
Disconnects client with: "<name> is currently offline. Ping Luke" |
Idle Shutdown Timer
For any running server in ondemand mode, mc-manager tracks the time since the last player disconnected ($N_{\text{players}} = 0$) after an initial post-boot grace period ($T_{\text{grace}} = 5\text{ min}$ so players have plenty of time to connect after waking the server). When:
$$t_{\text{empty}} \ge T_{\text{idle}} \quad (\text{default } 20\text{ min})$$
mc-manager issues save-all and stop via RCON and stops minecraft@<slug>.service, freeing the JVM heap until the next join request.
6.4 Web Control Plane (https://mc.drheck.dev)
The web frontend is served over HTTPS behind Nginx + Authentik ForwardAuth and provides two primary workspaces:
1. Existing Servers Dashboard
- Server Fleet Cards:
- Displays every registered server with its live state badge (
ONLINE,STARTING,SLEEPING (ON-DEMAND),OFFLINE), online player list, RAM/CPU usage, Minecraft version, loader type (Paper,Vanilla,Fabric,Forge), and<slug>.drheck.devendpoint. - One-Click Controls:
Start,Stop,Restart, and a dropdown to switch the server betweenManual,On-Demand, andAlways On. - Live Console & Config Drawer: WebSocket log stream (
journalctl -u minecraft@<slug>.service -f) with RCON command input, visualserver.properties/whitelist.json/ops.jsoneditor, and BlueMap 3D map toggle.
- Displays every registered server with its live state badge (
- Legacy Directory Adoption:
- Scans
/data/minecraft/*for directories without aserver.jsonmanifest (e.g.,kochan 26.2,hermitcraft 9,Project Sekai,superworld 1.20.1) and provides a one-click Adopt & Productionize wizard that generatesserver.json, provisions anipctlIPv6 route + DNS entry, and wires upminecraft@<slug>.service.
- Scans
2. Create New Server Studio
Creating a new world follows a 3-step guided workflow in the Web UI:
- Step 1 — Identity, Networking & Resource Profile:
- Display Name & Subdomain: Entering
Create Worldauto-suggests slugcreateworld(createworld.drheck.dev). - Lifecycle Policy: Select
On-Demand(default),Always On, orManual, plus heap size (4 GiB–24 GiB) and optional BlueMap 3D Web Map provisioning.
- Display Name & Subdomain: Entering
- Step 2 — Server Binary & Custom Modpacks:
- Server Engine Selector:
- Paper / Purpur / Vanilla / Fabric / NeoForge / Forge: Queries live upstream release APIs (or local cached jars in
/data/minecraft/jars/) so you can pick the exact Minecraft version and build from a dropdown. - Automatically pairs the required JVM runtime (
/usr/lib/jvm/java-26-openjdk,java-21-openjdk,java-17-openjdk, orjava-8-openjdk).
- Paper / Purpur / Vanilla / Fabric / NeoForge / Forge: Queries live upstream release APIs (or local cached jars in
- Custom Modpack & Mod Library:
- Local Custom Modpacks (
/data/minecraft/modpacks/): Choose from your curated custom modpacks (.zipserver packs,.mrpackModrinth packs, or reusablemods/+config/bundles) or upload a new custom pack directly in the browser. - Individual Mods & Plugins: Upload
.jarfiles or search Modrinth / Paper Hangar filtered by the selected Minecraft version and loader to drop mods/plugins straight intomods/orplugins/.
- Local Custom Modpacks (
- Server Engine Selector:
- Step 3 — Interactive Seed Preview & Reroll Studio:
- Seed Input or Reroll:
- Enter a specific seed (integer or text string, converted using standard Java
String.hashCode()rules) or click 🎲 Roll Random Seed to cycle through candidate seeds.
- Enter a specific seed (integer or text string, converted using standard Java
- Instant 2D Biome & Structure Map Preview (
cubiomesEngine):- Uses a headless native
cubiomesC renderer onulto generate a high-resolution 2D biome colour map ($\pm 2048$ blocks around $(0,0)$) in $< 50\text{ ms}$ per seed, overlaid with exact structure icons (Spawn point, Villages, Ancient Cities, Woodland Mansions, Ocean Monuments, Pillager Outposts, Strongholds, and Nether Fortresses/Bastions). - Lets you click 🎲 Roll Random Seed repeatedly until you spot an ideal spawn island, continent, or structure cluster, or bookmark candidate seeds side-by-side before creating the server.
- Uses a headless native
- Post-Creation Seed Swap ("Reroll World"):
- On any newly created server (for example, if you log in or check its 3D BlueMap render and want a different terrain layout), clicking Swap Seed & Regenerate World in the server dashboard stops
minecraft@<slug>.service, writes the newlevel-seedtoserver.propertiesandserver.json, clearsworld/,world_nether/, andworld_the_end/, and restarts the server on the new seed.
- On any newly created server (for example, if you log in or check its 3D BlueMap render and want a different terrain layout), clicking Swap Seed & Regenerate World in the server dashboard stops
- Seed Input or Reroll:
6.5 Authentik Gate, OIDC Role-Based Access Control (RBAC) & In-Game /op Sync
Access to https://mc.drheck.dev is protected by a two-layer Authentik security model that gates the entire web interface at the Nginx perimeter while using native OpenID Connect (OAuth2Provider) claims to grant granular Server Admin privileges both in the web UI and inside the Minecraft servers themselves.
$$ ext{\text{Authentik SSO } ( exttt{\texttt{auth.drheck.dev}) \longrightarrow egin{\begin{cases} ext{\text{Layer 1: Nginx ForwardAuth } ( exttt{\texttt{ProxyProvider}) & \longrightarrow ext{\text{Blocks unauthenticated requests at perimeter} \\ ext{\text{Layer 2: OIDC JWT + Scopes } ( exttt{\texttt{OAuth2Provider}) & \longrightarrow ext{\text{Maps } exttt{\texttt{groups} ext{\text{ &and } exttt{\texttt{entitlements} ext{\text{ to RBAC + RCON } exttt{\texttt{/op} \end{cases}$$
1. Authentik OIDC Scopes & Claim Evaluation
mc-manager authenticates users via OIDC Authorization Code Flow with PKCE against https://auth.drheck.dev/application/o/mc/ (verifying RS256 JWT tokens against https://auth.drheck.dev/application/o/mc/jwks/) and inspects three identity sources on every HTTP request and WebSocket frame:
profileScope (groupsclaim): Reads Authentik group memberships (["mc_admins", "mc_server_admins", "ul_ssh", ...]).entitlementsScope (rolesclaim): Reads application-scoped entitlements attached to themcAuthentik Application (e.g.,admin:pokelovers,admin:all,creator).- Per-Server
server.jsonACLs (owner&admins): Allows a Super Admin (or the creator of a server) to grant specific Authentik usernames ("admins": ["ikura", "haruka"]) full admin privileges on an individual server directly from the web UI.
2. Three-Tier Privilege Matrix
| Role Tier | Authentik Group / Entitlement Match | Web UI & Infrastructure Capabilities | In-Game Minecraft Privileges |
|---|---|---|---|
| 1. Super Admin | Group authentik Admins or mc_admins (e.g., luke) |
Full Control Plane Access: Create/delete any server, run ipctl --dns, adopt legacy /data/minecraft/* folders, configure any heap size or always mode, access all live RCON consoles, and assign per-server admins. |
Automatic Level 4 Operator (/op) + bypassesPlayerLimit: true on all servers with sync_ingame_ops: true. |
| 2. Server Admin | Group mc_server_admins, Entitlement admin:<slug>, or username listed in server.json admins |
Delegated Server Administration: Can start/stop/restart assigned servers, switch between manual and ondemand, use the Live RCON Console & Log Stream, edit server.properties / whitelist.json, upload/toggle mods, and create new ondemand servers in the Create New Server Studio (capped at 12 GiB heap). |
Automatic Level 4 Operator (/op) on every server where they hold Server Admin rights. |
| 3. Player / Viewer | Any authenticated drheck.dev user |
Dashboard & Wake Access: View live server status, online players, seeds, and BlueMap 3D maps; click Wake Server on ondemand worlds; download client .mrpack / .zip modpack bundles. Cannot stop servers, view RCON consoles, or alter configs. |
Standard player (automatically added to whitelist.json if account is linked). |
3. Automatic OIDC-to-Minecraft /op (ops.json) Synchronization
Each authenticated user can link their Minecraft Java Edition username once in the mc.drheck.dev profile bar (stored in Authentik user attributes user.attributes.mc_username and resolved to an immutable Mojang UUID via https://api.mojang.com/users/profiles/minecraft/<username>):
- Granting Admin: When a user is added to
mc_admins,mc_server_admins, or a server'sadminslist inserver.json,mc-managerautomatically writes their UUID and username into/data/minecraft/<dir>/ops.json("level": 4,"bypassesPlayerLimit": true) andwhitelist.json. If the server is currentlyONLINE,mc-managerimmediately sendswhitelist add <mc_user>andop <mc_user>over the internal ULA IPv6 RCON socket (25575) so they receive operator privileges in-game without a server restart. - Revoking Admin: Removing a user from the Authentik group or the server's
adminslist immediately removes their entry fromops.jsonand dispatchesdeop <mc_user>over RCON.
6.6 End-to-End Automated Provisioning Pipeline
When Create Server is clicked in the Web UI, the backend executes the following atomic pipeline:
- Directory & Manifest Creation: Creates
/data/minecraft/<slug>/, writesserver.jsonandeula.txt(eula=true), downloads the selected Paper/Vanilla/Fabric/Forge binary, and extracts any selected custom modpack intomods/,plugins/, andconfig/. - Network & DNS Allocation (
ipctl): Callsipctl create <slug> --dnsto assign the next availablefd77:7777:5010::1337:3c:d00d:<hex>/64address oneth77, register the HAProxy SNI backend (withmc_offlineon-demand wake support), and publish<slug>.drheck.devondanknastyUnbound and deSEC.io. server.propertiesGeneration: Writesserver-ip=fd77:7777:5010::1337:3c:d00d:<hex>,server-port=25565,level-seed=<seed>,online-mode=true, and RCON credentials bound exclusively to the internal ULA IPv6 address.- Systemd Activation: Registers
minecraft@<slug>.service(andbluemap@<slug>.serviceif enabled) and either starts the server immediately or places it intoSLEEPING (ON-DEMAND)ready for the first player join.