Minecraft Bedrock Tunnel after 1.26.51 update (NetherNet Transport)

Ubuntu Bedrock server: 1.26.51.1

Windows Bedrock client: v26.51

On LAN direct IP, it works.

Via playit.gg tunnel, it has stopped working since I updated the server to 1.26.51.1 and changed the server.properties transport=nethernet as stated in the server startup console messages.

What do I need to configure with this transport=nethernet change for the playit.gg tunnel to work again?

I spent most of a day chasing this down, so I’m documenting the setup that finally worked for me.

If you’re running Minecraft Bedrock through playit.gg and the 1.26.51 update suddenly stopped remote players from connecting, the old single UDP tunnel setup is no longer enough.

With NetherNet, you now need two separate paths:

  • TCP for the initial signaling/handshake

  • UDP for the actual game traffic

There’s also a nasty issue in 1.26.51.1 where the UDP ports advertised to players need to match the local UDP ports exactly. If they don’t, the server can start normally while never actually opening the expected listener.

This is currently working for me from outside the LAN without any router port forwarding.

After the update, I started seeing 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.

The important change is that RakNet is gone in 1.26.51.1.

Previously, Bedrock mainly used UDP 19132, and a normal playit.gg Bedrock tunnel handled that.

NetherNet changes the connection flow.

The first part of the connection happens over TCP on port 19132. The same endpoint is also used for the server information request. For example:

GET /v1/join

returns JSON containing the server information.

The actual gameplay traffic is then handled separately over UDP.

That UDP traffic does not use the same TCP tunnel. It needs to be able to reach the server independently.

This means the old UDP-only Bedrock tunnel is no longer sufficient by itself.

The documentation says that only signaling traffic on server-port needs to go through the proxy, while gameplay traffic travels directly between the client and server.

I initially interpreted that to mean the UDP portion would automatically work through NAT.

That wasn’t the case in my setup.

What it actually means is that the UDP gameplay traffic does not travel through the signaling proxy. It still needs a usable route to the server.

This made troubleshooting confusing because local connections worked perfectly.

A computer on the same LAN could connect because it didn’t need to cross the router.

Remote players could see the server name and information, but connecting failed with:

InitialConnection-83   codeword: Door
Transport: NetherNet:2193

If you can see the server in the list but fail during InitialConnection, your TCP signaling is probably working and the UDP gameplay path is what needs attention.

The biggest problem I ran into involved server-udp-ports.

The documented format allows mappings like:

ip:external:internal

However, with 1.26.51.1 I could only get it to work when the external and internal UDP port numbers were exactly the same.

These examples worked:

19140-19155

19140-19143:19140-19143

<playit-ip>:61226-61229:61226-61229

These did not:

61226-61229:19140-19143

<playit-ip>:61226-61229:19140-19143

When using different internal and external ports, the server still printed:

Server started.

but never opened the expected listener.

There was no useful error message.

So if playit gives you ports 61226-61229, configure the Minecraft server to use 61226-61229 locally as well.

In other words, make the server match the playit assignment instead of trying to translate the ports.

You can check whether the server actually opened the listener with:

docker logs <container> | grep "Accepting clients"

If nothing is returned, there’s a good chance the server-udp-ports value is preventing NetherNet from binding correctly.

As a quick sanity check, switching temporarily back to something simple like:

19140-19155

should allow the listener to come up again.

I also had to switch the container to host networking.

With standard Docker bridge networking, the Bedrock server was collecting network candidates from inside the container and advertising an internal container address that remote clients couldn’t use.

My compose file uses:

network_mode: host

The TCP and UDP sides behave slightly differently.

The TCP signaling service listens on:

*:19132

so the playit TCP tunnel can point to:

127.0.0.1:19132

The UDP side does not bind to loopback in the same way, so the UDP tunnel needs to point to the server’s actual LAN address.

I also noticed the server always opens UDP port 7551. That appears to be a fixed NetherNet port and is separate from the configurable UDP range.

This is the configuration that worked for me:

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

Replace the example IP and UDP range with whatever playit.gg assigned to your UDP tunnel.

One other important detail: TRANSPORT, SERVER_UDP_PORTS, and SERVER_IP were added to the itzg image in builds from 2026-09-17 onward as part of PR #675.

If you’re running an older image, those environment variables may simply be ignored.

That newer image also changes the container healthcheck to use /v1/join when NetherNet is enabled.

On the playit side, I ended up using two tunnels.

The first is a TCP tunnel with a port count of 1, pointing to:

127.0.0.1:19132

This handles the initial NetherNet handshake and server information.

This is also the hostname and port that players actually enter in Minecraft.

If you use a custom hostname, this is the tunnel I would attach it to.

The second is a UDP tunnel with a port count of 4, pointing to:

<server-lan-ip>:61226

Replace 61226 with the first port assigned by playit.

For example, if playit assigns:

61226-61229

then the Minecraft server should also be configured to use:

61226-61229

because of the same-port requirement described above.

Players never manually enter the UDP tunnel address. The server advertises that information through NetherNet.

Once the TCP and UDP tunnels are working, the old legacy Bedrock UDP tunnel should no longer be necessary.

You can test the signaling side without opening Minecraft.

From another machine, run:

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

A working response should look similar to:

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

If you get JSON back, the TCP signaling path is working.

If the request times out, focus on the TCP tunnel.

If /v1/join works but remote players still fail during connection, focus on the UDP tunnel, UDP port range, and the server-udp-ports configuration.

One final useful detail: the itzg container also creates its own pre-upgrade backup under:

minecraft-data/backup-pre-<version>

when the server version changes.

2 Likes

Thanks dean, for the detailed notes on your effort to get this going. I will have to read that a few more times in order to digest and understand what you’ve said.

I’m hoping for playit.gg to just say “Here’s a new updated Minecraft Bedrock tunnel option you click to enable NetherNet support with one single click when setting up a new tunnel”. :slight_smile:

I am running the Bedrock server directly on my Ubuntu, not via Docker itzg container.

After reading Dean’s reply, I attempted to set up a single Playit.gg TCP Tunnel with Port Count 1. (Not a Minecraft Bedrock Tunnel Type).

The Local IP I left it as 127.0.0.1.

The Local Port I entered the port number for the Minecraft server, which the default is 19132.

I wanted to see if I can detect the server, but lo and behold, it actually connected and logged me in and I was able to play via the external link.

There wasn’t any need to set up a second tunnel for the UDP channels that Dean described. The caveat is that I am running the server directly on Ubuntu and not via a Docker container.

I tested making a new “Minecraft Bedrock” Tunnel Type, but that still failed.

Did you guys find a solution? Dean, I read your reply but I got completely confused when you said, “You can check whether the server actually opened the listener with:docker logs | grep “Accepting clients””. After this I figured you were talking about something completely different, are you referencing to Geyser?

I have spent hours trying to find a solution to this update but I am still yet to figure it out. I really need help. I have looked for various alternatives to PlayIt.GG, however it is the same story. These do not support NetherNet which uses a completely different infrastructure, combining TCP and UDP. I am aware that I can create a tunnel with these two on PlayIt.GG but it is behing a paywall.