docs(crafty): Bedrock 19132 refuses nothing -- BDS ships transport=nethernet
Reported as "users cannot connect to Bedrock on UDP 19132". Measured read-only on prod; the platform delivered the packets and the server never opened the socket. Server `K3s-Bedrock` (c5837301-..., type=minecraft-bedrock, server_port=19132) exists and `./bedrock_server` is alive, but /proc/net/udp and /proc/net/udp6 in the crafty container hold NO socket on 19132 (0x4ABC) in either family -- port 19132 is bound as TCP (/proc/net/tcp6 ...:4ABC state 0A). Cause, from the server's own server.properties: transport=nethernet, the value Microsoft's BDS archive ships. Its inline docs: `Allowed values: "raknet" or "nethernet"`, and against server-portv6, `This property is ignored when transport=nethernet`. NetherNet is the WebRTC/Xbox-signalled transport and opens no RakNet UDP listener. Crafty does not manage the property (no `transport` anywhere under /crafty/app/classes/) and its only Bedrock probe is raknet_ping.py, hence commander.log spamming "Got timeout while issuing bedrock ping to 127.0.0.1:19132" -- over loopback, which indicts the server, not the network. The path below it is sound and was measured as such: crafty-l4-udp live as externalTrafficPolicy: Cluster with the VIP in status.loadBalancer, a non-empty EndpointSlice, `cilium-dbg service list` showing 192.168.2.22:19132/UDP => 10.0.0.130:19132/UDP (active) on BOTH announcing nodes, the datapath policy map carrying `Allow Ingress reserved:world 19132/UDP` with 26 packets / 27660 bytes already counted through it, pihole answering crafty-mc -> 192.168.2.22, and Flux at main@sha1:20ea70d == the GitRepository artifact. So this is not a platform or manifest defect. No manifest is touched: adding ports or widening policy for this would be manufacturing work. The repo-side defect is documentation -- the README told the operator that creating a server on 19132 was sufficient. README: add "Bedrock on UDP 19132 -- the transport trap" (the measurement chain, and the raknet_ping warning as its signature) and "Bedrock realities that are NOT platform defects" (no LAN/Friends discovery behind a VIP, consoles cannot enter an address, enable-lan-visibility collides with slots 1-2, server-portv6 is not exposed). Correct three stale claims: "the operator has not created any servers yet" (two exist), the human test implying a started Bedrock server is reachable, and the single-server Runtime state section (now a two-row table recording K3s-Bedrock's auto_start=0 / crash_detection=0 -- the create-API trap, live again, so it will not survive a pod restart). Also measured, reported, and deliberately NOT changed: the shared VIP's two leases sit on different nodes (crafty-l4-tcp on k3s-prod-3, crafty-l4-udp on k3s-prod-1), so two nodes ARP-announce 192.168.2.22. Benign under `Cluster` -- both nodes carry the full active frontend set -- and the existing L0 check l2-announced-vips-serve-from-any-node already forbids the `Local` that would make it fatal. A "shared VIPs must co-locate" check would assert runtime lease placement a static check cannot see. Read-only throughout: no apply/edit/patch, no flux reconcile, no write inside the container. Operator actions (set transport=raknet and verify the UDP bind; PATCH auto_start; tell players to Add Server by hand) are in the DECISIONS-LOG entry, along with what is UNVERIFIED -- chiefly that `raknet` fixes it is reasoned from the shipped docs, not observed. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
20ea70d221
commit
07f03536b3
2 files changed
+255
-7
No files matched your search
@@ -83,8 +83,8 @@ themselves. `external-dns` publishes `crafty-mc.home.keithjackson.dev → 192.16
|
||||
|
||||
### Adding more game ports (when the operator creates servers)
|
||||
|
||||
The operator has **not created any servers yet**; the starter set covers 3 Java + 3 Bedrock slots. To
|
||||
add capacity:
|
||||
As of 2026-09-29 **two** servers exist (see *Runtime state* below): Java `homelab` on 25565 and
|
||||
Bedrock `K3s-Bedrock` on 19132. The starter set covers 3 Java + 3 Bedrock slots. To add capacity:
|
||||
|
||||
1. In the Crafty UI, create the server and bind it to a NEW port (Java TCP or Bedrock UDP).
|
||||
2. Add that port to the matching Service in `service-l4.yaml` (one
|
||||
@@ -93,6 +93,63 @@ add capacity:
|
||||
4. (Optional) add a `containerPort` in `deployment.yaml` for documentation.
|
||||
5. Commit → Flux reconciles.
|
||||
|
||||
### Bedrock on UDP 19132 — the transport trap (MEASURED on prod 2026-09-29)
|
||||
|
||||
**A Bedrock server that Crafty created, started, and reports as running can still have nothing bound
|
||||
to `19132/udp`, with every layer in this repo provably correct.** This is the first thing to check
|
||||
when "Bedrock players cannot connect" — before the Service, the policy, the lease or the VIP.
|
||||
|
||||
Measured on prod 2026-09-29 against server `K3s-Bedrock` (`c5837301-12b1-404e-b50e-70eafb37226b`,
|
||||
DB `type=minecraft-bedrock`, `server_port=19132`, process `./bedrock_server` alive):
|
||||
|
||||
- `/proc/net/udp` and `/proc/net/udp6` inside the crafty container held **no socket on 19132**
|
||||
(`0x4ABC`) at all — only ephemeral UDP sockets. Port 19132 was bound as **TCP**
|
||||
(`/proc/net/tcp6`, `…:4ABC`, state `0A`/LISTEN), not UDP.
|
||||
- Cause, from the server's own `server.properties`: **`transport=nethernet`** — the value Microsoft's
|
||||
BDS archive *ships by default*. Its own inline docs: `# Allowed values: "raknet" or "nethernet"`,
|
||||
and against `server-portv6`: `# This property is ignored when transport=nethernet and a dual-stack
|
||||
socket will be opened on server-port instead`. NetherNet is the WebRTC/Xbox-signalled transport; it
|
||||
**never opens a RakNet UDP listener**, so nothing binds `19132/udp` however `server-port` is set.
|
||||
- Crafty does not manage this property — `transport` does not appear anywhere under
|
||||
`/crafty/app/classes/` — and Crafty's *only* Bedrock reachability probe is `raknet_ping.py`, so the
|
||||
panel spams `WARNING app.classes.remote_stats.raknet_ping - Got timeout while issuing bedrock ping
|
||||
to 127.0.0.1:19132` every 5–30 s against a server it started successfully. **That warning is the
|
||||
signature of this trap**, and it comes from `127.0.0.1` — i.e. it indicts the server, not the LAN.
|
||||
- The platform path was verified sound at the same time: `crafty-l4-udp` live as
|
||||
`externalTrafficPolicy: Cluster` with `status.loadBalancer.ingress[0].ip` = the VIP, a non-empty
|
||||
EndpointSlice, `cilium-dbg service list` showing `<VIP>:19132/UDP → 10.0.0.130:19132/UDP (active)`
|
||||
on *every* node, and the crafty endpoint's datapath policy map carrying
|
||||
`Allow Ingress reserved:world 19132/UDP` **with 26 packets / 27660 bytes already counted through
|
||||
it**. Real player packets reached the pod and were allowed; the application had no socket to take
|
||||
them.
|
||||
|
||||
**Operator fix — application state on the PVC, not git and not Flux:** stop the server in Crafty, set
|
||||
`transport=raknet` in `/crafty/servers/<uuid>/server.properties`, start it, and **confirm a UDP
|
||||
listener on 19132 exists** (`grep 4ABC /proc/net/udp /proc/net/udp6`, or the `raknet_ping` warnings
|
||||
stopping) before suspecting the network. *(That `raknet` restores the UDP bind is read from the
|
||||
shipped property documentation, not yet observed on this cluster — see the DECISIONS-LOG entry of
|
||||
2026-09-29.)*
|
||||
|
||||
### Bedrock realities that are NOT platform defects but present identically
|
||||
|
||||
- **LAN / Friends-tab discovery can never work here.** Bedrock discovery is a UDP broadcast on 19132
|
||||
inside one L2 segment; this server sits behind a LoadBalancer VIP (and SNAT), not on the LAN, so it
|
||||
will **never** appear in a client's Friends/LAN list. Players must use **Add Server** and type the
|
||||
address and port by hand: `crafty-mc.home.keithjackson.dev` (or the VIP) with port **19132**.
|
||||
`external-dns` publishes that name from the **-tcp** Service, so it resolves to the shared VIP and
|
||||
is correct for Bedrock too — only the port differs from Java's 25565.
|
||||
- **Consoles cannot reach this at all.** Switch/Xbox/PlayStation Bedrock clients have no
|
||||
arbitrary-server-address field; only Windows/mobile/Fire do. Reaching it from a console needs a DNS
|
||||
redirect of a featured-server hostname, which is out of scope for `service-l4.yaml`.
|
||||
- **`enable-lan-visibility=true` (the shipped default) collides with Bedrock slots 1 and 2.** Under
|
||||
`transport=raknet` it makes a server bind the **default** ports 19132/19133 *even when `server-port`
|
||||
is set to something else* — the shipped comment says exactly that. So a second Bedrock server put on
|
||||
19133 or 19134 will fight the first for 19132. Set `enable-lan-visibility=false` on every Bedrock
|
||||
server after the first; LAN discovery cannot work here anyway (above).
|
||||
- **`server-portv6` is not exposed and is not meant to be.** `service-l4.yaml` is IPv4 single-stack,
|
||||
so the default `server-portv6=19133` is unreachable from the LAN. Harmless — but do not read
|
||||
`19133` in `server.properties` as "slot 1 is in use".
|
||||
|
||||
## Policies
|
||||
|
||||
`namespace.yaml` sets only `gateway-access=shared` (platform namespace, like headlamp/homepage), so
|
||||
@@ -114,14 +171,29 @@ Gateway VIP). The sidecar→Crafty hop is pod-local (`127.0.0.1`) and not subjec
|
||||
local admin. A **non-platform-admins** user → **403** (authenticated but not authorized).
|
||||
2. **Pod health / fsGroup:** `kubectl -n crafty get pod` Ready 2/2; Crafty writes its DB under
|
||||
`/crafty/app/config` and `/crafty/servers` without EACCES.
|
||||
3. **Server-create + game reach:** in the Crafty UI create a Java server bound to `25565`; start it;
|
||||
connect a Minecraft client to `crafty-mc.home.keithjackson.dev:25565` (or `192.168.1.55:25565`)
|
||||
from the LAN and confirm the world loads. (Bedrock: a server on `19132/udp` reached at the VIP.)
|
||||
3. **Server-create + game reach (Java):** in the Crafty UI create a Java server bound to `25565`;
|
||||
start it; connect a Minecraft client to `crafty-mc.home.keithjackson.dev:25565` (or
|
||||
`192.168.1.55:25565`) from the LAN and confirm the world loads.
|
||||
4. **Server-create + game reach (Bedrock):** creating and starting the server is **not sufficient** —
|
||||
check `transport=raknet` and a live UDP listener on 19132 first (see *the transport trap* above),
|
||||
then **Add Server** by hand in a Windows/mobile client at `crafty-mc.home.keithjackson.dev` port
|
||||
`19132`. It will never show up in the LAN/Friends tab, and a console cannot reach it.
|
||||
|
||||
## Runtime state: the servers themselves are NOT in git
|
||||
|
||||
As of 2026-09-14 one Java server exists — **"homelab"**, Paper 26.2, TCP 25565, 2 GiB heap, autostart
|
||||
on, UUID `13c7b85d-00bb-4a58-8c86-2433ca47891c`. It was created through Crafty's v2 API, and **Mojang's
|
||||
As of 2026-09-29 **two** servers exist (both measured live, `select * from servers`):
|
||||
|
||||
| Name | Type | Port | UUID | `auto_start` |
|
||||
|---|---|---|---|---|
|
||||
| `homelab` | `minecraft-java` (Paper 26.2, 2 GiB heap) | TCP 25565 | `13c7b85d-00bb-4a58-8c86-2433ca47891c` | **1** |
|
||||
| `K3s-Bedrock` | `minecraft-bedrock` | UDP 19132 | `c5837301-12b1-404e-b50e-70eafb37226b` | **0** ⚠ |
|
||||
|
||||
`K3s-Bedrock` was created 2026-09-29 20:51 and has `auto_start=0` **and** `crash_detection=0` — the
|
||||
create-API trap documented at the bottom of this file, live again. **It will not come back after a pod
|
||||
restart**, and merging any change to `deployment.yaml` restarts the pod (`strategy: Recreate`). PATCH
|
||||
both to true and read them back.
|
||||
|
||||
`homelab` was created through Crafty's v2 API, and **Mojang's
|
||||
EULA (<https://aka.ms/MinecraftEULA>) was accepted on the operator's behalf** to let it start; see the
|
||||
DECISIONS-LOG entry of that date.
|
||||
|
||||
|
||||
Reference in new issue
Block a user