NetherNet
NetherNet is the networking transport used by Bedrock Edition to connect multiplayer peers through WebRTC. It establishes a connection between the client and the host, then carries Bedrock game data over two data channels with different delivery guarantees.
In the HTTP signaling workflow, a client first contacts a server endpoint to check compatibility and exchange connection details. Once the WebRTC connection is ready, gameplay traffic travels over the data channels. HTTP is used for setup rather than for sending each game packet. [1]
Use in Bedrock Edition
NetherNet became the default transport for Bedrock Dedicated Server in 26.50. RakNet, the earlier transport, was deprecated in Preview 26.60.22.
Changing the transport does not replace the Bedrock game protocol. NetherNet handles how peers connect and exchange messages; the game protocol still defines what those messages mean, including login, world updates, and player actions. A server's advertised game protocol version therefore remains relevant when checking client compatibility.
How it works
NetherNet uses several parts of the WebRTC networking stack. Each has a separate role:
| Component | Role |
|---|---|
| Signaling | Exchanges the information needed to start a connection. Mojang documents an HTTP-based workflow for server onboarding. |
| ICE | Gathers candidate addresses and checks which network path can connect the peers. |
| DTLS | Establishes the encrypted transport and authenticates the certificate fingerprints exchanged during setup. |
| SCTP | Carries messages through the WebRTC data channels, with reliability and ordering configured per channel. |
| Game Protocol | Defines the game data carried inside the transport. |
WebRTC data channels are message-oriented: applications send and receive messages rather than a continuous byte stream. NetherNet uses data channels without audio or video tracks. [2]
Signaling paths
Signaling is the exchange that prepares a connection. The HTTP workflow below is documented by Mojang for server onboarding. Community implementations also document LAN discovery and signaling, which use a different exchange. Those LAN messages should not be treated as additional steps in the HTTP handshake. [3]
HTTP signaling
The same join endpoint supports a capability check and a connection offer. Their response formats differ:
| Request | Purpose | Successful response |
|---|---|---|
GET /v1/join | Retrieve server information and check support. | A JSON object with server metadata. |
POST /v1/join/{networkId} | Submit the client's SDP offer. | The host's SDP answer. |
Capability check
The client sends GET /v1/join before attempting the connection. A successful response has a 2xx HTTP status, the content type application/json, and the following fields:
| Field | Type | Description |
|---|---|---|
name | String | Display name of the server. |
protocol | Number | Bedrock game protocol version supported by the server. |
version | String | Advertised game version. |
level | String | World name. |
players | Number | Current player count. |
maxPlayers | Number | Maximum player count. |
gameType | Number | Game mode: 0 for Survival, 1 for Creative, or 2 for Adventure. |
A non-success response ends this capability check; the client does not proceed with a WebRTC connection through that endpoint.
Offer and answer
The client sends its offer to POST /v1/join/{networkId} with the content type application/sdp. The request body is the raw UTF-8 SDP offer. The successful response uses the same content type and contains the raw SDP answer.
SDP describes the proposed connection, including candidate addresses and certificate fingerprints. The networkId in the URL identifies the client within the signaling exchange; it is an opaque identifier, rather than a game protocol version or an account name.
This workflow uses full ICE gathering. Each peer finishes gathering its candidates before sending its offer or answer. Candidates are included in that exchange rather than sent later through trickle ICE. There is one offer POST per connection attempt, and a non-success response fails that attempt.
Connection sequence
- Check the server. The client requests the server metadata from
GET /v1/join. - Prepare WebRTC. The client creates its peer connection and the reliable and unreliable data channels.
- Send an offer. After candidate gathering finishes, the client posts its SDP offer to the join endpoint.
- Reach the host. The signaling service delivers the offer to the host.
- Return an answer. The host prepares an SDP answer, completes candidate gathering, and returns it through the HTTP response.
- Establish the transport. The client applies the answer. ICE selects a working path, DTLS establishes security, and SCTP provides the data channels.
- Exchange game data. The peers send Bedrock messages through the open channels.
Completing the signaling request does not itself complete a Bedrock login. The game still performs its own protocol exchanges over the established connection.
Identity and trust
An SDP offer or answer can describe a network path, but the client also needs to know whose connection it is accepting. NetherNet's HTTP workflow includes an a=identity attribute in both descriptions. Its assertion binds identity information to the DTLS certificate fingerprints used by the connection.
The client assertion carries authenticated player information for the server to validate. The server assertion identifies an operator key. That key identifies the operator rather than merely the hostname, address, or temporary networkId.
| Signaling connection | Server trust |
|---|---|
| HTTPS | A valid TLS certificate provides the trust anchor for the signaling endpoint. A first-use operator prompt is not required. |
| Plain HTTP | Trust on first use: an unfamiliar operator key requires confirmation, and the accepted key can be remembered for later connections. |
The server identity assertion is required in the answer even when signaling uses HTTPS. Missing or malformed identity data causes the connection to be rejected. WebRTC identity assertions associate an asserted identity with the connection's certificate fingerprints. [4]
Data channels
NetherNet uses two channels. The labels below are literal protocol values:
| Label | Delivery | Ordering | Retransmission |
|---|---|---|---|
ReliableDataChannel | Reliable | Ordered | Uses SCTP's reliable delivery. |
UnreliableDataChannel | Unreliable | Unordered | maxRetransmits = 0. Lost messages are not retransmitted. |
Reliable delivery suits messages that must arrive in sequence. Unreliable delivery allows data to be lost rather than delaying newer information through retransmission. Choosing a channel does not change the meaning of the Bedrock packet inside it.
Both peers can send and receive on the channels. The reliable channel also supports NetherNet's fragmentation format for messages larger than a single channel message can carry. [5]
Message framing
Each data-channel message starts with a one-byte NetherNet header, followed by payload bytes. The header tells the receiver how many fragments remain after the current message.
| Header value | Meaning |
|---|---|
0 | A complete message, or the final fragment of a split message. |
N > 0 | The current fragment has N more fragments following it. |
Reliable fragmentation
When a reliable payload needs to be split, its fragments arrive in order and count down to zero. For example, a payload split into four fragments has these headers:
03 [first fragment]
02 [second fragment]
01 [third fragment]
00 [final fragment]
The receiver removes each header and joins the fragment payloads. A zero header with no unfinished fragment sequence represents a complete, unsplit payload.
Fragment size depends on the negotiated SCTP message limit. The one-byte header occupies part of that limit, so the whole limit is not available for payload data.
Unreliable messages
An unreliable message always uses a zero header. NetherNet does not split these messages into multiple application fragments. A payload that exceeds the available message size is dropped rather than fragmented.
This NetherNet header is separate from SCTP's own internal handling. An implementation must still parse the header after receiving a data-channel message.
Game data
After transport framing and any reliable fragment assembly, the remaining payload belongs to the Bedrock game protocol. Packet decoding, compression, and game-level encryption must be handled according to that protocol and the connection's current state.
RakNet frame-set headers, ACK/NACK records, and split-packet fields are not NetherNet headers. A decoder written for RakNet therefore needs a different transport layer before it can process NetherNet traffic.
Comparison with RakNet
| Area | NetherNet | RakNet |
|---|---|---|
| Connection setup | WebRTC negotiation; Mojang documents HTTP signaling. | RakNet's open-connection handshake. |
| Message delivery | SCTP data channels configured for reliable or unreliable delivery. | Reliability modes carried in RakNet frames. |
| Application fragmentation | Countdown header on the reliable channel. | Split-packet metadata, including a split identifier and fragment index. |
| Game data | Carries the Bedrock game protocol. | Also carries the Bedrock game protocol. |
Implementations
The following projects provide implementation details alongside the protocol documentation. Support may differ between releases, particularly for signaling and identity handling.
| Project | Language | Focus |
|---|---|---|
| go-nethernet | Go | NetherNet networking implementation. |
| nethernet-python | Python | Implementation with a documented protocol specification. |
References
- ↑ "NetherNet HTTP Signaling — Partner Onboarding Guide" - Mojang
- ↑ "WebRTC Data Channels — RFC 8831" - IETF
- ↑ "NetherNet implementation specification" - EndstoneMC
- ↑ "WebRTC Security Architecture — RFC 8827" - IETF
- ↑ "NetherNet protocol specification" - df-mc
