Bedrock clients cannot join through UDP tunnel (v1.0.9: Unable to connect, v1.0.10: client crashes) while Java Edition works normally

Environment

Host OS

  • Windows 11 (also reproduced on a friend’s Linux PC)

Playit Agent

  • v1.0.10

  • v1.0.9

Server

  • Paper

  • Geyser-Spigot v2.11.0-SNAPSHOT

  • Floodgate

  • ViaVersion

  • ViaBackwards

Ports

  • Java: TCP 25565

  • Bedrock (Geyser): UDP 19132


Tunnel Configuration

UDP Tunnel


Public UDP Port
    ↓
Playit
    ↓
Local UDP 19132 (Geyser)

I tested both:

  • Proxy Protocol v2 = Enabled

  • Proxy Protocol v2 = Disabled


Expected Behavior

A Bedrock client should be able to connect through the Playit UDP tunnel in the same way it can through a direct connection, ZeroTier, or OpenVPN.


Actual Behavior

Playit Agent v1.0.10

  • Server appears in Bedrock server list.

  • Ping succeeds.

  • Pressing Join causes Minecraft Bedrock (Android) to crash.

  • Geyser never logs a Bedrock connection attempt.


Playit Agent v1.0.9

Proxy Protocol disabled:

  • Server appears online.

  • Ping succeeds.

  • Joining returns:

    • “Unable to connect to world.”
  • Geyser receives no login attempt.

Proxy Protocol enabled:

  • Server no longer responds to ping.

Comparison

Exactly the same server, plugins, and configuration were tested with other networking solutions.

Method Java Bedrock
Direct LAN :white_check_mark: :white_check_mark:
ZeroTier :white_check_mark: :white_check_mark:
OpenVPN :white_check_mark: :white_check_mark:
Playit v1.0.9 :white_check_mark: :cross_mark:
Playit v1.0.10 :white_check_mark: :cross_mark:

Java Edition works correctly through Playit.

The issue only affects Bedrock traffic.


Packet Capture

Wireshark captures show:

  • Unconnected Ping

  • Unconnected Pong

However, the RakNet connection handshake never reaches Geyser.

Packets such as:

  • Open Connection Request 1

  • Open Connection Request 2

  • Connection Request

do not appear to reach the local server during the failed connection attempts.


Additional Notes

  • Reproduced on Windows and Linux hosts.

  • Same behavior with different computers.

  • Same Bedrock client successfully connects over ZeroTier and OpenVPN.

  • Firewall is not the cause since other tunnel providers work.

  • Geyser configuration has been verified and functions correctly through other networking methods.

  • Java Edition works normally through Playit.


Question

Is there any known incompatibility between Playit’s UDP forwarding and RakNet/Geyser traffic, or any additional configuration required for Geyser Bedrock servers?

well all the text above is ai generated i hope it’s not a problem for anyone so basically the only thing i can do with playit tunnel is get ping notification on server log and when i try to join it crashes no logs nothing im in my personal computer as well not in a dedicated server

1 Like

should work fine on both 1.0.9 and 1.0.10 though I suggest using 1.0.10

I suggest reverting everything to defaults before starting

for geyser make a tunnel
type udp
port count 1
local port match public

on geyser config
set port (bedrock) to match playit tunnel public facing port

on playit tunnel
set local port to match playit tunnel’s public facing port

match ports end to end starting from the tunnel’s public facing port, also allow ports and connections thru security

make sure you’ve configured floodgate as well

I’m having the same problem; is there a solution?

1 Like

This took me an entire day to work out, so I’m writing it up in case it saves someone else the same pain.

Short version: if you run Bedrock behind playit.gg and the 1.26.51 update locked everyone out, you need a TCP tunnel for the handshake and a UDP tunnel for gameplay, and the UDP port numbers on both sides have to be identical or the server silently refuses to listen. That last part is a bug, and it’s what cost me most of the day.

Everything below is confirmed working from outside the network, with no router port forwarding.

After updating, the console threw this:

Your current connection type is not set to NetherNet.
In this release, NetherNet is the only supported transport type.
Players will not be able to connect to your game without NetherNet.

1.26.51.1 dropped RakNet entirely. RakNet was UDP on 19132, which is what a standard playit “Minecraft Bedrock” tunnel forwards.

NetherNet works completely differently.

The handshake is HTTP over TCP on 19132. It’s also what answers the server status and MOTD query. GET /v1/join returns JSON.

Gameplay is UDP, negotiated separately per player, and it does not go through the tunnel at all. It goes straight to your box.

So a UDP-only Bedrock tunnel is now forwarding nothing useful. That’s why everyone is locked out.

The thing I misread, which wasted hours

The Mojang docs bundled with the server say “only the signaling traffic on server-port needs to be forwarded through the proxy; the gameplay traffic flows directly between the client and the server.”

I read that as the UDP sorting itself out via NAT traversal and needing nothing from me.

It does not mean that.

It means the gameplay UDP bypasses the proxy. It still has to reach your machine somehow.

The symptom if you get this wrong is nasty because it looks like it half works. I could join fine because I’m on the same LAN as the server box and my traffic never crossed the router.

Anyone outside got all the way to seeing the world name in the server list and then died with:

InitialConnection-83   codeword: Door
Transport: NetherNet:2193

Seeing the world name means the handshake worked. Dying at InitialConnection means the UDP leg never connected.

If that’s your error, your TCP side is fine and your UDP side is the problem.

The big gotcha: server-udp-ports only works 1:1

server-udp-ports is supposed to let you publish a NAT mapping in the form:

ip:external:internal

In 1.26.51.1, it only works if the external port numbers are IDENTICAL to the internal ones.

Anything else and the server boots, logs Server started., and then never opens its listener.

No error. Nothing in the log. It just sits there dead and you have no idea why.

Value Result
19140-19155 (bind only) works
19140-19143:19140-19143 works
<playit-ip>:61226-61229:61226-61229 works
61226-61229:19140-19143 dead, no listener
<playit-ip>:61226-61229:19140-19143 dead, no listener

So whatever ports playit assigns you, the server has to use those exact same numbers locally.

Set your local port to match the tunnel, not the other way around.

Quick way to check if this is what’s biting you:

docker logs <container> | grep "Accepting clients"

If that line is missing, your server-udp-ports is bad.

Put it back to a plain range like 19140-19155 to get online again, then fix it properly.

Host networking is required

If you leave the container on the Docker bridge, the server gathers its network candidates from inside the container and advertises a useless private address.

It has to be:

network_mode: host

That changes what your tunnels point at.

TCP signaling binds *:19132, so 127.0.0.1 is fine for that tunnel.

UDP does not bind loopback, so that tunnel has to point at your actual LAN IP.

Also worth knowing: it binds UDP *:7551 regardless of what you configure. That’s a fixed NetherNet port, not something you set.

The working setup

services:
  minecraft:
    image: itzg/minecraft-bedrock-server:latest
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./minecraft-data:/data
    environment:
      EULA: "TRUE"
      GAMEMODE: "survival"
      DIFFICULTY: "normal"
      MAX_PLAYERS: "10"
      VERSION: "LATEST"
      TRANSPORT: "nethernet"
      SERVER_UDP_PORTS: "<playit-udp-tunnel-ip>:61226-61229:61226-61229"
    stdin_open: true
    tty: true

Swap in whatever IP and ports your UDP tunnel got.

Heads up that TRANSPORT, SERVER_UDP_PORTS, and SERVER_IP only exist in itzg images built 2026-09-17 or later (PR #675). On an older image, they’re silently ignored and you’ll be very confused.

That build also switches the healthcheck to hit /v1/join when TRANSPORT=nethernet.

Two tunnels on the playit side:

A TCP tunnel, port count 1, pointing at:

127.0.0.1:19132

This is the handshake, and it’s the address and port your players actually type in. Put your custom domain on this one.

A UDP tunnel, port count 4, pointing at:

<your-lan-ip>:61226

Where 61226 is whatever port playit assigned that tunnel.

This is gameplay. Players never type this address, but the server has to advertise it via server-udp-ports, and the local port has to equal the assigned port because of the 1:1 bug above.

Your old Bedrock/UDP tunnel is dead weight. Delete it once the new pair is confirmed working.

You can check the handshake from anywhere with curl, which is much faster than loading Minecraft every time:

curl http://<your-tunnel-domain>:<tcp-port>/v1/join

You should get something like:

{"name":"...","protocol":2193,"version":"1.26.51","level":"...","players":0,"maxPlayers":10,"gameType":0}

If that returns JSON, your TCP side is done.

If it times out, your TCP tunnel is wrong.

If it returns JSON but people still can’t join, it’s the UDP side.

The server also writes its own minecraft-data/backup-pre-<version> when it upgrades.