Files
claude-timemachine d73c1c9537 minecraft_protocol: foundation + per-version protocol docs 1.7.10->26.2
8 topical docs (overview, data types, lifecycle, handshake, status/ping,
login+encryption, configuration, version-differences) + proxy-forwarding set
+ 16 per-version release-line docs, sourced from minecraft.wiki, ViaVersion
(source + commits), minecraft-data, node-minecraft-protocol, Velocity, BungeeCord.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 14:15:32 +02:00

67 lines
5.8 KiB
Markdown

# Proxy Forwarding Modes
How a Minecraft proxy moves a player between backend servers — and how it securely tells each backend *who the player is*.
This is the most load-bearing section of the reference. Get forwarding wrong and you either (a) break logins, or (b) open your network to anyone connecting as anyone.
## What a proxy does
A Minecraft proxy (BungeeCord, Waterfall, [Velocity](https://github.com/PaperMC/Velocity)) sits in front of *N* backend servers (lobby, survival, minigames, modded, …). The player's client connects **once** to the proxy. The proxy speaks the full client-facing protocol — handshake, login, encryption, online-mode auth against Mojang — and then opens its *own* connection to a backend server and pumps packets between the two. When the player runs `/server survival`, the proxy silently tears down the backend connection and opens a new one to a different backend, all without the client reconnecting.
```mermaid
sequenceDiagram
autonumber
actor C as "Client (player)"
participant P as "Proxy (Velocity/BungeeCord)"
participant L as "Backend: lobby (offline-mode)"
participant S as "Backend: survival (offline-mode)"
C->>P: "connect once (online-mode auth here)"
P->>L: "open backend conn + forward identity"
L-->>C: "play (via proxy relay)"
Note over C,S: "player runs /server survival"
P->>S: "open new backend conn + forward identity"
S-->>C: "play (via proxy relay)"
```
## Why forwarding exists
The proxy already authenticated the player against Mojang. The **backends must not** repeat that — they run in **offline mode** (`online-mode=false`), because:
- A backend in online mode would demand its *own* Mojang session handshake from the connecting party (the proxy), which the proxy can't satisfy on the player's behalf.
- Running backends offline lets the proxy own a single client connection and freely re-point it.
But an offline-mode server, by itself, knows nothing real about who connected. It only sees a username string in `LoginStart`, and it derives an **offline UUID** from that name (see [online-offline-modes.md](online-offline-modes.md)). So the proxy must *forward* the player's real identity to the backend:
- real **client IP** (so the backend sees the player, not the proxy)
- real **UUID** (the Mojang account UUID for premium players)
- **username**
- **game-profile properties** — the `textures` property (skin/cape) and, on newer versions, the player's signature/public key
And — critically — the backend must be able to **trust** that this forwarded identity actually came from the proxy and not from an attacker who found the backend's port. That trust mechanism is what distinguishes the modes.
## The menu of modes
| Mode | Doc | One-line |
|---|---|---|
| **none** | [online-offline-modes.md](online-offline-modes.md) | No forwarding. Backend uses the raw `LoginStart` name → offline UUID. Only safe if the backend is the edge. |
| **legacy / bungeecord** | [bungeecord-legacy.md](bungeecord-legacy.md) | Proxy stuffs `ip\0uuid\0properties` into the handshake address field. **No crypto.** |
| **bungeeguard** | [bungeeguard.md](bungeeguard.md) | Legacy + a shared secret token smuggled in the forwarded properties. Third-party. |
| **modern / velocity** | [velocity-modern.md](velocity-modern.md) | Backend requests identity via a Login Plugin message; proxy replies with an **HMAC-SHA256-signed** payload. Gold standard. |
## Comparison
| Mode | Crypto? | Backend support needed | Spoofable if backend port exposed? | Forge-friendly |
|---|---|---|---|---|
| **none** | — | none (default offline behavior) | **Yes** — anyone can claim any name | n/a |
| **legacy (BungeeCord)** | None | Spigot/Paper `settings.bungeecord: true` (or Fabric equiv.) | **Yes** — forge the `\0`-delimited string | Yes — `\0FML\0` marker rides in the handshake (see [forge-fml.md](forge-fml.md)) |
| **bungeeguard** | Shared secret (plaintext token, compared by the backend plugin) | Legacy forwarding **+** BungeeGuard plugin on the backend | **No** (attacker lacks the token), *but* the token travels in plaintext inside the connection | Yes — same handshake-field transport as legacy |
| **modern (Velocity)** | **HMAC-SHA256** over the payload, keyed by a shared secret | Paper `velocity.enabled`+`velocity.secret` (or Fabric/Forge mod that implements it) | **No** — attacker can't produce a valid HMAC without the secret | Needs care — see [forge-fml.md](forge-fml.md) (the FML handshake competes with the login-plugin channel) |
**Rule of thumb**: use **modern/Velocity** when every backend supports it; fall back to **bungeeguard** when a backend only speaks legacy; use bare **legacy** only inside a network where the backend ports are firewalled so *only the proxy* can reach them; use **none** only when the server is itself the internet edge in online mode.
> The "exposed port" risk is the whole point. With legacy and none, your only defense is the firewall — bind backends to localhost / a private interface and let only the proxy connect. With bungeeguard and modern, the protocol itself rejects forged identities. See [online-offline-modes.md](online-offline-modes.md#security-model) for why offline backends are open by default.
## Mapping to the automc platform
In the automc stack, each backend Minecraft server runs with a **Velocity sidecar** managed by `mc-wrapper` (the wrapper runs the proxy alongside the MC server in the same pod). `mc-wrapper`'s `PROXY_MODE` concept selects which of these forwarding modes the sidecar↔server pair uses — practically that means **modern/Velocity forwarding** (the [velocity-modern.md](velocity-modern.md) path) with a shared secret, since proxy and server are co-located and the wrapper provisions the secret. This doc set is the protocol-level reference behind that knob; the automc-specific wiring lives in the `mc-wrapper` repo, not here.