minecraft-gateway routes Minecraft Java Edition connections to game servers using a three-layer architecture built on Kubernetes and Envoy.
The three layers
Minecraft client
│ TCP :25565
▼
┌─────────────────────┐
│ Edge Proxy │ Envoy DaemonSet + Rust dynamic module
│ (per node) │ Parses handshake, matches hostname
└─────────┬───────────┘
│ TCP (hostname-routed)
▼
┌─────────────────────┐
│ Network Proxy │ Proxy integration (e.g. Velocity)
│ (per listener) │ Applies join/fallback rules
└─────────┬───────────┘
│ TCP
▼
┌─────────────────────┐
│ Game Server │ Your Paper/Fabric/etc. server
└─────────────────────┘
Edge proxy
The edge layer runs as an Envoy DaemonSet with a Rust dynamic module (minefleet-edge). When a client connects:
- The Rust listener filter reads the first bytes of the TCP stream and parses the Minecraft Java Edition handshake packet.
- It extracts the
server_address field (what the client typed as the server address).
- It looks up the address in a hostname-to-cluster map pushed by the controller via xDS.
- It writes the resolved cluster name into Envoy dynamic metadata.
- Envoy’s
tcp_proxy reads that metadata and forwards the connection to the correct network proxy.
The edge proxy operates at layer 4 — it does not terminate the Minecraft protocol.
Network proxy
Each Gateway listener gets a dedicated network proxy Deployment and Service. The network proxy:
- Accepts the Minecraft connection from the edge layer.
- Queries the controller’s network xDS endpoint to get its routing configuration.
- Applies join and fallback rules to decide which game server to forward the player to.
- Forwards the connection to the selected game server, optionally using player identity forwarding (e.g. Velocity modern forwarding).
The built-in integration uses Velocity, but you can implement the network integration API to use any proxy. The network proxy is the component that understands join routes, fallback routes, priorities, and distribution strategies.
Kubernetes controller
The Go controller watches CRDs and reconciles the desired state:
- GatewayClass — marks the controller as the owner.
- Gateway — creates/updates the edge xDS snapshot and the network proxy Deployment + Service per listener.
- NetworkInfrastructure — discovers game server Services and writes their endpoints into status.
- MinecraftJoinRoute / MinecraftFallbackRoute — attach to a Gateway and define routing rules.
The controller pushes configuration to the edge proxy via an xDS gRPC server on port 18000 and to the network proxies via a separate xDS server on port 19000.
How a connection flows
- A player connects to your cluster on port 25565.
- The Envoy DaemonSet on that node accepts the TCP connection.
- The
minefleet-edge Rust filter reads the Minecraft handshake and extracts the server_address (e.g. play.example.com).
- The filter looks up
play.example.com in the domain map. An exact match is tried first, then a wildcard match (e.g. *.example.com).
- The matching cluster name is written to Envoy dynamic metadata.
tcp_proxy forwards to the network proxy Service for that cluster.
- The network proxy looks up the player’s destination using its xDS snapshot.
MinecraftJoinRoute rules are evaluated in priority order; MinecraftFallbackRoute rules apply when the primary server is unavailable.
- The network proxy forwards the player to the selected game server.
Key design decisions
Layer 4 edge routing — The edge proxy never buffers or proxies the full Minecraft protocol. It reads just enough bytes to extract the hostname (capped at 1024 bytes), then gets out of the way. This keeps latency minimal and the edge stateless.
Separation of edge and network concerns — Hostname-based routing (which cluster?) is an edge concern. Game-logic routing (which server within a cluster?) is a network concern. The two layers have separate xDS APIs and separate configuration paths.
Kubernetes-native — Configuration lives entirely in Kubernetes CRDs. There are no sidecars, no external databases, and no out-of-band configuration files to manage. Last modified on April 19, 2026