Skip to main content
minecraft-gateway separates edge routing (hostname matching) from network routing (join/fallback logic). The network proxy is the component responsible for the latter, and the controller exposes a gRPC API — NetworkXDS — that any proxy can call to receive its routing configuration. The built-in integration uses Velocity. This guide explains how to implement your own.

Prerequisites

  • Your proxy runs as a Kubernetes Deployment managed by the controller (via networkTemplate)
  • Your proxy can make gRPC calls to the controller’s network xDS server

How it works

When a Gateway listener is reconciled, the controller:
  1. Creates a Deployment and Service for your proxy using the image and configuration from networkTemplate.
  2. Injects environment variables your proxy uses to identify itself to the xDS server.
  3. Keeps a snapshot of all routes and backends for that listener up to date.
Your proxy calls NetworkXDS.GetSnapshot with an infinite timer to retrieve its snapshot, then uses the snapshot to make routing decisions.

Environment variables

The controller injects these environment variables into every network proxy container:

The NetworkXDS API

The API is defined as a single unary RPC:
Pass the three injected environment variables (NAMESPACE, GATEWAY_NAME, LISTENER_NAME) as the request fields. The server returns UNAVAILABLE if no snapshot has been built yet and NOT_FOUND if the gateway/listener combination does not exist.

The Snapshot message

current_generation is an opaque string that changes whenever the snapshot changes. Poll the endpoint periodically and re-apply configuration when the generation changes.

ManagedService

Each ManagedService represents a Kubernetes Service that was discovered as a backend. servers lists the live endpoints; routes lists the join and fallback rules that point to this service.

ManagedServer

max_players and current_players are populated when the controller can read them from the game server. Use them together with distribution_strategy to implement LEAST_PLAYERS routing.

Route

Join routes (is_join = true) route a player’s initial connection. Fallback routes (is_fallback = true) activate when a primary backend is unavailable. Evaluate routes in descending priority order.

Routing algorithm

A minimal correct implementation:
  1. On connect: find all join routes across all services whose rules match the player (domain, permission). Take the highest-priority match. Select a server from that service using distribution_strategy.
  2. On failure: if the selected server is unavailable or full, find fallback routes whose fallback_for matches the failed service’s namespaced_name and whose other rules match the player. Take the highest-priority match.
  3. Generation polling: re-fetch the snapshot when current_generation changes. Apply the new routing table without disconnecting existing players.

Deploying your proxy

Use networkTemplate in NetworkInfrastructure to deploy your proxy image:
The controller creates one Deployment per listener and injects the environment variables above. Your image should read them at startup to connect to the xDS server. See Customizing the Network Proxy for additional networkTemplate options such as mounting secrets and setting resource limits.

Using the Java integration-api

If you are writing a JVM-based proxy plugin, the integration-api library wraps the raw gRPC API and handles polling, diffing, and retries for you. The Velocity built-in integration is implemented using it.

Add the dependency

Replace VERSION with the latest version from Maven Central.

Implement ServerRegistrar

ServerRegistrar is called by the API whenever backend servers appear, update, or disappear in the snapshot. Use server.name() as the stable key in your proxy’s server registry.
Throw ServerRegistrarException to signal a failure for a single server. The library retries failed servers up to retries times (default: 3), once per poll interval.

Implement NetworkPlayer

NetworkPlayer is a per-event wrapper. Create a new instance for each routing call.
connectedServer() must look up the player’s current server through your registrar’s internal map. The fallback routing rules match on parentNamespacedName, which is only available on ManagedServer objects tracked by the registrar — not raw proxy server objects.

Build and start NetworkGateway

Build one NetworkGateway at proxy startup. The builder reads the injected environment variables automatically.

Wire routing events

routeJoin evaluates MinecraftJoinRoute rules in priority order and calls player.connectToServer() on the first match. routeFallback evaluates MinecraftFallbackRoute rules. Both call player.kick() if no matching service is found.

ManagedServer field reference

NetworkGateway.Builder options

Last modified on April 19, 2026