aller au contenu
FRFlo
Table des matières

In multiplayer Minecraft hosting, multi-server networks have been the architectural standard for over a decade. To link disparate gamemodes (survival, creative, minigames, hubs) behind a single public IP address without disconnecting players between transitions, a packet-level reverse proxy sits at the network edge.

Historically, this tier has been dominated by JVM-based software such as BungeeCord and Velocity. While mature and feature-rich, Java proxies impose a heavy Java Virtual Machine runtime overhead, regularly demanding 512 MB to 1 GB of memory solely to route TCP packets, alongside garbage collection pauses during sudden connection spikes. Furthermore, orchestrating backend server lifecycles—spinning up instances only when players attempt to connect and shutting them down when idle to conserve hosting resources—traditionally requires brittle custom daemon scripts.

To create an ultra-lightweight, self-contained, and deeply integrated gateway for my self-hosted stack, I developed gate-plugged (FRFlo/gate-plugged). Built on top of the modern Go-based Minekube Gate proxy framework, it bundles modular extensions: on-demand server scaling via the Pelican Panel API, deep client and mod inspection (Forge, NeoForge, Lunar Client via Protobuf, Bedrock/Geyser), and centralized administration without requiring plugins on backend game instances.

Here is the architectural deep dive into this high-performance game proxy.


Architecture Overview

gate-plugged serves as the sole public gateway for the Minecraft network. It terminates player TCP connections, negotiates protocol configuration handshakes, and communicates with the Pelican Panel daemon to scale backend game containers:

flowchart TB
    subgraph Players["Minecraft Players"]
        JavaClient["Standard Java Client"]
        LunarClient["Lunar Client (Protobuf)"]
        ModdedClient["Forge / NeoForge (Mods)"]
        BedrockClient["Bedrock / Geyser"]
    end

    subgraph GateProxy["gate-plugged (Native Go Binary)"]
        TCPListener["TCP Listener (:25565)<br>Velocity Modern Forwarding"]
        PluginRouter["Minekube Gate Plugin Engine"]

        subgraph Plugins["Internal Plugins"]
            Detection["plugins/detection<br>(Forge, Lunar PB, Bedrock)"]
            PelicanPlugin["plugins/pelican<br>(Auto-Start & Auto-Stop)"]
            Vanish["plugins/vanish<br>(Tablist & Packet Filtering)"]
            Commands["plugins/commands<br>(F3 Brand Spoofing)"]
        end
    end

    subgraph Infrastructure["Backend Infrastructure (Pelican / Docker)"]
        PelicanAPI["Pelican Panel API<br>(/api/client/servers/{id}/power)"]
        LimboServer["Limbo Server (:25566)<br>(Ultra-lightweight holding world)"]
        GameServerA["Survival Server (Spigot/Paper)"]
        GameServerB["Modded Server (Forge/Fabric)"]
    end

    Players -->|TCP Connection :25565| TCPListener
    TCPListener --> PluginRouter
    PluginRouter --> Detection
    PluginRouter --> PelicanPlugin
    PluginRouter --> Vanish
    PluginRouter --> Commands

    PelicanPlugin -->|"REST API Power Signal"| PelicanAPI
    PluginRouter -->|Holding player during container boot| LimboServer
    PluginRouter -->|Route when ready| GameServerA
    PluginRouter -->|Direct routing| GameServerB

1. Why Gate (Go) Over a JVM Proxy?

One of the foremost challenges when hosting multiple game workloads on a shared VPS alongside databases, RAG sidecars, and AI agent services is memory contention. Minimizing baseline daemon footprints is paramount.

Minekube Gate is a clean-room Go implementation of the Minecraft protocol (framing, zlib compression, AES/CFB8 encryption, and Velocity modern player forwarding):

  • Sub-30 MB Memory Footprint: Where Velocity typically demands 512 MB to 1 GB of heap space, gate-plugged operates comfortably within a ~25 MB memory budget.
  • Lightweight Goroutines over OS Threads: Every connecting client is managed by concurrent Go goroutines without the memory overhead of JVM thread stacks.
  • Instant Cold Boot (< 50 ms): As a compiled static binary in a container, cold starts are instantaneous, completely eliminating JVM JIT warm-up time.

Security via Velocity Modern Forwarding

To forward player IPs, Mojang UUIDs, and skin properties to backend servers without permitting header spoofing, gate-plugged implements Velocity’s modern forwarding protocol.

Every backend connection packet is signed with an HMAC-SHA256 digest keyed with a shared secret passed via an environment variable (GATE_VELOCITY_SECRET):

forwarding:
mode: velocity
velocity:
secret: "${GATE_VELOCITY_SECRET}"

2. Pelican Integration: On-Demand Scaling

In traditional multi-server setups, running idle modded or minigame servers around the clock wastes significant RAM.

The plugins/pelican extension connects gate-plugged to the REST API of Pelican Panel (the modern Go/PHP successor to Pterodactyl), implementing automated two-way lifecycle management:

sequenceDiagram
    autonumber
    actor Player as Player
    participant Proxy as gate-plugged
    participant Limbo as Limbo Server
    participant Pelican as Pelican Panel API
    participant Backend as Survival Server (Paper)

    Player->>Proxy: Connect (/server survival)
    Proxy->>Pelican: GET /servers/{id} (Check State)
    alt Server Offline
        Proxy->>Pelican: POST /servers/{id}/power (signal: start)
        Proxy->>Player: Route to Limbo holding room
        Player->>Limbo: Waiting in empty void world (0 load)
        loop Availability Polling
            Proxy->>Backend: TCP Ping & Protocol Handshake
        end
        Backend-->>Proxy: Server Ready & Accepting Connections
        Proxy->>Player: Seamless transfer to Survival Server
    else Server Running
        Proxy->>Player: Direct connection
    end

The Role of the Limbo Server

When a player requests an offline server, gate-plugged does not disconnect them with a generic error. Instead, it routes them to an internal Limbo instance (limbo:25566).

Limbo is a mock Minecraft server that loads neither terrain nor world entities, idling at under 10 MB of RAM. The player waits safely in a void world with real-time boot status messages presented in the boss bar or chat, while the pelican plugin monitors container initialization and performs the handoff once the target server is ready.

Intelligent Auto-Stop

Conversely, the autostop.go worker monitors backend world populations. When a backend server reports 0 players for a configurable duration (such as 10 minutes), gate-plugged issues a graceful shutdown request (signal: stop) to the Pelican API, immediately reclaiming host resources for the rest of the VPS.


3. Advanced Mod & Client Detection (plugins/detection)

Maintaining server integrity requires auditing client modpacks and client identities during login. Traditionally, this is fragmented across multiple heavy Bukkit plugins or third-party anti-cheat modules.

gate-plugged consolidates this inspection directly at the proxy layer by parsing Plugin Messaging Channels during the protocol configuration phase:

flowchart LR
    Client["Minecraft Client"] -->|Plugin Channel Handshake| Proxy["gate-plugged Listener"]

    Proxy --> ChannelRouter{"Channel Detected?"}
    ChannelRouter -->|fml:handshake / fml:login| ForgeParser["Forge / NeoForge Mod Parser<br>(Extract mod IDs & versions)"]
    ChannelRouter -->|lunarclient:pm / lunar:message| LunarParser["Protobuf Lunar Decoder<br>(Extract ID, version, settings)"]
    ChannelRouter -->|minecraft:brand| BrandParser["Brand Filter<br>(Fabric, Vanilla, Cheat Clients)"]

    ForgeParser --> PolicyEngine["Action Policy Engine (actions.go)"]
    LunarParser --> PolicyEngine
    BrandParser --> PolicyEngine

    PolicyEngine -->|Compliant| Allow["Permit Connection & Log Metadata"]
    PolicyEngine -->|Non-Compliant| Kick["Immediate Kick with Custom Reason"]

Forge & NeoForge Mod Inspection (forge.go)

Forge clients negotiate installed mod lists with the server over custom messaging channels (fml:handshake on legacy releases, fml:login on modern versions).

gate-plugged decodes this binary handshake directly:

  • Extracts full mod IDs and semantic versions installed on the client machine.
  • Validates the list against custom blacklists or whitelists in plugged.yml.
  • Rejects prohibited utility mods or cheat injectors before the player reaches backend game worlds.

Protobuf Decoding for Lunar Client (lunar.go)

For users connecting via Lunar Client, data exchange utilizes Protocol Buffers (Protobuf) across the lunarclient:pm channel.

The embedded lunar_pb package compiles Protobuf definitions into the Go proxy binary, enabling gate-plugged to:

  • Authenticate valid Lunar Client sessions.
  • Enforce allowed visual toggles (disabling wall player nametags, configuring custom crosshairs, etc.).
  • Log client build signatures for auditing.

4. Network-Level Vanish (plugins/vanish)

Hiding staff members (/vanish) across multi-server networks often introduces synchronization bugs: player list updates (Tablist / PlayerInfo) and switch announcements must be propagated manually across backend nodes.

gate-plugged’s plugins/vanish module solves this by operating above the game servers:

  • PlayerInfoUpdate Packet Filtering: When staff members toggle /vanish, the proxy rewrites Tablist update packets directed to standard players, wiping all references to the staff member’s UUID and nametag.
  • Suppression of Switch Announcements: Global server connection notifications (ServerConnectedEvent) are intercepted, preventing accidental staff join alerts in public chat.
  • Universal Backend Compatibility: Because filtering occurs in the proxy pipeline, vanish works transparently across Paper 1.21, Forge 1.20, and isolated standalone minigame servers alike.

Conclusion

By swapping out traditional JVM proxies for a compiled Go gateway, gate-plugged shrinks memory consumption tenfold while delivering sub-millisecond packet routing.

Pairing Minekube Gate with the Pelican Panel API achieves a serverless-style gaming infrastructure: secondary game worlds consume CPU cycles and memory only when players are actively online.

The project is open source on GitHub: github.com/FRFlo/gate-plugged.