# Quilkin: a UDP proxy that hides your game servers behind a token

> Quilkin is a non-transparent UDP proxy from Embark Studios, built for large scale multiplayer deployments so clients never see a real server address. It is beta, its Rust API is explicitly not a stable interface, and the release surface is the CLI, environment variables and config schema.

**EmbarkStudios/quilkin** — Quilkin is a non-transparent UDP proxy specifically designed for use with large scale multiplayer dedicated game server deployments, to ensure security, access control, telemetry data, metrics and more.

- Repository: https://github.com/EmbarkStudios/quilkin
- Stars: 1,597 · Forks: 124
- Language: Rust
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/embarkstudios-quilkin

## What non-transparent means, and why it is the whole point

Quilkin is described in the repository description as a non-transparent UDP proxy for large scale multiplayer dedicated game server deployments, providing security, access control, telemetry data and metrics.

The final clause of that description is the design goal: all of this is delivered without the end user having to custom build and integrate the functionality into their game clients and servers directly. That is the difference between Quilkin and a general purpose proxy. A conventional reverse proxy terminates a protocol it understands. Quilkin relays opaque UDP datagrams and treats the connection as something to be forwarded based on metadata rather than parsed.

Because it sits in front of your servers, it also changes what your players see. They connect to the proxy, not to a game server, and the proxy decides which backend receives the traffic. That is what makes access control possible at all when the game protocol carries no authentication of its own.

Two announcements in the README place it in context: a post from Embark Studios introducing it as an open source UDP proxy, and a Google Cloud post on open source UDP proxies for game server communication. The concept and many architectural decisions are credited to Envoy Proxy, with explicit thanks to that team.

## Routing by token metadata, taken from the justfile

The `justfile` in the repository root contains the clearest configuration example available, and it is worth reading in full because it shows the token mechanism without any prose.

```yaml
clusters: # grouping of clusters
  - endpoints: # array of potential endpoints to send on traffic to
    - address: 127.0.0.1:26000
      metadata: # Metadata associated with the endpoint
        quilkin.dev:
          tokens:
            - MXg3aWp5Ng== # the connection byte array to route to, encoded as base64 (string value: 1x7ijy6)
            - OGdqM3YyaQ== # (string value: 8gj3v2i)
```

A cluster groups endpoints, each endpoint has an address, and the address carries metadata. Inside `quilkin.dev` there is a list of tokens, each a base64 encoded byte array. The comment on the first token spells out what the encoding is for: it is the byte array the connection uses to route to that endpoint.

So routing is not based on port mapping. A client sends bytes containing one of these tokens, the proxy matches it to an endpoint, and the traffic is forwarded. Change the token and the endpoint behind it changes with no client update. That is the property that makes a proxy in front of live game servers worth running.

The token example is also a security note. Base64 is encoding, not encryption, and a static token in a config file is a shared secret. Anyone who can read the configuration can send traffic to your backends, and the README does not document rotation.

## Three roles on namespaced ports for local development

Quilkin has at least three runtime roles, and the local development recipe makes them explicit. The `_helptext` block in the `justfile` says the ports are namespaced by an id to avoid collisions when running more than one system: relay on `1XXXY`, proxy on `2XXXY` and agent on `3XXXY`. With an id of 1, an agent serves metrics under `127.0.0.1:38001/metrics`.

The recipes to bring up a complete local system are named `start_relay`, `start_proxy` and `start_agent`, each intended for its own shell, and a second system on the same machine is started by passing a different id such as `just id=1 start_relay`.

```bash
just id=1 start_relay
just id=1 start_proxy 1
just id=1 start_agent 1
```

The `justfile` also generates a default agent config on first run, writing a file named after the id, which is why the id variable has to be set before the first agent recipe. That is a small convenience that makes the difference between a working local setup and a confusing one.

The role split matters beyond local development. A relay, a proxy and an agent are separate processes with separate jobs, and an agent that exposes metrics under `/metrics` is the piece that fits into an existing Prometheus-style scrape. The project also ships a Compose example at `examples/compose.yaml` and proxy configuration at `examples/proxy.yaml`.

## Beta status, and an API you are not supposed to use

The Project State section is short and should be quoted mentally before anything else. Quilkin is in beta status, meaning it is being actively developed and used in production systems, but the API may break and functionality may be changed or removed between releases.

The `Cargo.toml` makes the second half concrete. The package sets `publish = false` with a comment explaining that the Rust API is not a stable interface and that Quilkin ships as a container image whose release surface is the CLI, env vars and config schema.

That is an unusually explicit contract, and it changes how you should evaluate the project. You are not adopting a crate. You are adopting a binary and its configuration format. If you plan to link against it from Rust, or to depend on its YAML shape, you are outside what the maintainers have committed to. If you plan to run the container image and write config against the documented schema, you are inside it.

Release cadence suggests active work rather than abandonment. v2026.10.0 was published on 2026-10-14, and the last push was on 2026-10-15, the day after. The `quilkin-xds-v0.10.1` and `quilkin-types-v0.10.1` tags from 2026-05-26 indicate separately versioned crates within the workspace, so the monorepo contains independently released components.

## How the project is built, and what the image contains

The `Dockerfile` is a multi-stage build on `debian:bookworm` with a `chef` base stage that installs `build-essential`, `ca-certificates`, `curl`, `git`, `pkg-config`, `protobuf-compiler`, `wget` and `zip`. Protobuf being a build dependency is the hint that gRPC or xDS interfaces are compiled in.

Toolchain management goes through mise, with `MISE_DATA_DIR`, `MISE_CONFIG_DIR`, `MISE_CACHE_DIR` and `MISE_INSTALL_PATH` set, and `PATH` prefixed with `/mise/shims`. The Dockerfile states that `rust-toolchain.toml` is the single source of truth for the toolchain version, and it extracts the `channel` value from that file and passes it to mise explicitly, so the pin is applied before the workspace is copied. There is a comment explaining why the file is copied alone in that stage: copying only the pin keeps the layer from being invalidated by unrelated source changes.

`cargo chef` handles dependency caching with a separate `planner` stage that runs `cargo chef prepare --recipe-path recipe.json`. `cargo-about` is installed alongside it, which explains the `about.toml` and `license.csv.hbs` and `license.html.hbs` templates at the root for generating licence reports.

The release profile is tuned hard: the `[profile.lto]` section inherits release, sets `opt-level = 3`, `codegen-units = 1` and `lto = "fat"`. Allocator selection is a Cargo feature, with `default = ["jemalloc"]` and a `mimalloc` alternative, plus `heap-stats` pulling in `crossbeam-utils`. A data plane proxy competing on latency would not choose these settings lightly.

## Against game server firewalls, and against a general purpose proxy

There are three alternatives and each fails in a different place.

The first is doing it in the network layer: security groups, a load balancer, a VPN. Quilkin provides access control without clients and servers integrating that functionality directly. 

The second is building the routing into the game. This is what most studios do first and it is the thing Quilkin exists to avoid. It means a matchmaking protocol, a token system, a routing layer in both client and server, and telemetry plumbing that has to be written, tested and kept compatible across game versions. Quilkin's stated purpose is that none of that has to be written, and the price is a process between your players and your servers.

The third is a general purpose proxy. Quilkin's ancestry makes the comparison unavoidable: it credits Envoy Proxy for concepts and architectural decisions. Quilkin is a non-transparent UDP proxy specifically designed for game server deployments. The `sdks/`, `proto/` and `fuzz/` directories at the root, plus the Agones integration examples under `examples/agones-xonotic-relay/`, `sidecar/` and `xds/`, show how far Quilkin is willing to go in either direction.

## Conclusion

Adopt Quilkin if you operate game servers behind a matchmaking layer and want address hiding, access control and telemetry without touching your game code, since it is built precisely so clients and servers do not have to integrate this themselves. Do not adopt it if you need a stable library API, because `Cargo.toml` sets `publish = false` with a comment saying the Rust API is not a stable interface. Verify first that you can accept the beta status, where functionality may be removed between releases.

## FAQ

### What is Quilkin used for?

Quilkin is a non-transparent UDP proxy for large scale multiplayer dedicated game server deployments, providing security, access control, telemetry and metrics without the end user building and integrating that into game clients and servers directly.

### How does Quilkin route traffic to a game server?

Endpoints in a cluster carry metadata under `quilkin.dev` containing tokens, each a base64 encoded byte array used as the connection byte array to route to that endpoint. A token identifies which backend a connection belongs to.

### Is Quilkin stable enough for production?

The README states the project is in beta status: it is actively developed and used in production systems, but the API may break and functionality may be changed or removed between releases. `Cargo.toml` also sets `publish = false`, stating the Rust API is not a stable interface and the release surface is the CLI, env vars and config schema.

### How do I run Quilkin locally for development?

The `justfile` documents three recipes run in separate shells, `just start_relay`, `just start_proxy` and `just start_agent`, with ports namespaced by an id such as 1, where an agent with id 1 serves metrics under `127.0.0.1:38001/metrics`. Running a second system means passing a different id, for example `just id=1 start_relay`.

### Which projects inspired Quilkin's architecture?

The README credits Envoy Proxy, saying many concepts and architectural decisions were initially inspired by it. The container image is published at `ghcr.io/embarkstudios/quilkin` and the licence is Apache 2.0.

## Sources

- [EmbarkStudios/quilkin on GitHub](https://github.com/EmbarkStudios/quilkin)
- [Issues](https://github.com/EmbarkStudios/quilkin/issues)
- [License: Apache-2.0](https://github.com/EmbarkStudios/quilkin/blob/main/LICENSE)
- [README](https://github.com/EmbarkStudios/quilkin/blob/main/README.md)
- [Releases](https://github.com/EmbarkStudios/quilkin/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/embarkstudios-quilkin
