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
}
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 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.