This document describes the complete setup of a Minecraft Bedrock Dedicated Server running in Kubernetes (k3s) with Crafty Controller and WorldEdit Bedrock Edition.
- Server: Minecraft Bedrock Dedicated Server 1.21.131.1
- Management: Crafty Controller (running in Kubernetes)
- Addon: WorldEdit Bedrock Edition 0.10.4
- External Access: allpurpose.ddns.net:30132 (UDP)
- Crafty Web UI: https://allpurpose.ddns.net:30443
Internet → Router (port forward 30132/UDP, 30443/TCP) → k3s NodePort Services → Crafty Pod → Bedrock Server
- k3s Kubernetes cluster
- Crafty Controller deployed (see crafty-controller.yaml)
- Python 3 with nbtlib (
pip3 install nbtlib) - kubectl access to the cluster
The Crafty Controller deployment is in ~/minecraft-k8s/crafty-controller.yaml:
- Namespace: minecraft
- Storage: 10Gi PersistentVolumeClaim (local-path)
- Ports:
- 30443/TCP - Crafty HTTPS Web UI
- 30132/UDP - Bedrock server (port 19132 internally)
Server files are located at:
/crafty/servers/<server-uuid>/
Current server UUID: a7c1de95-4d8c-4c1b-81a0-956110f721a5
# Download from GitHub releases
wget https://github.com/SIsilicon/WorldEdit-BE/releases/download/v0.10.4/WorldEdit_v0.10.4.mcaddon
# Or from alternative source if GitHub is unavailablemkdir -p /tmp/worldedit_extract
cd /tmp/worldedit_extract
unzip WorldEdit_v0.10.4.mcaddon
# This creates WorldEditBP/ and WorldEditRP/ folders# Get pod name
POD=$(kubectl get pods -n minecraft -l app=crafty-controller -o jsonpath='{.items[0].metadata.name}')
# Copy behavior pack
kubectl cp /tmp/worldedit_extract/WorldEditBP minecraft/$POD:/crafty/servers/a7c1de95-4d8c-4c1b-81a0-956110f721a5/behavior_packs/
# Copy resource pack
kubectl cp /tmp/worldedit_extract/WorldEditRP minecraft/$POD:/crafty/servers/a7c1de95-4d8c-4c1b-81a0-956110f721a5/resource_packs/Create/edit /crafty/servers/<uuid>/valid_known_packs.json:
[
{
"file_system": "RawPath",
"path": "behavior_packs/WorldEditBP",
"uuid": "3cdb2ddf-662e-4f8f-a0a1-1293b91ccb2f",
"version": "0.10.4"
},
{
"file_system": "RawPath",
"path": "resource_packs/WorldEditRP",
"uuid": "e304a4eb-f0a0-4979-ac17-7b0f46a555c8",
"version": "0.10.4"
}
]For the world (e.g., test-world), create these files in worlds/test-world/:
world_behavior_packs.json:
[
{
"pack_id": "3cdb2ddf-662e-4f8f-a0a1-1293b91ccb2f",
"version": [0, 10, 4]
}
]world_resource_packs.json:
[
{
"pack_id": "e304a4eb-f0a0-4979-ac17-7b0f46a555c8",
"version": [0, 10, 4]
}
]WorldEdit requires Beta APIs (Script API) to be enabled. This must be done by modifying the world's level.dat file.
- STOP THE SERVER FIRST before modifying level.dat
- The server will overwrite level.dat if it's running
- Bedrock level.dat uses little-endian NBT with an 8-byte header
Save this as enable_experiments.py:
#!/usr/bin/env python3
import nbtlib
from nbtlib import Byte
import struct
import sys
def enable_experiments(input_file, output_file):
# Read the file with 8-byte header
with open(input_file, 'rb') as f:
header = f.read(8) # 8-byte header (4-byte version + 4-byte length)
nbt_data = f.read()
# Write NBT data to temp file for parsing
temp_nbt = '/tmp/level_nbt_temp.dat'
with open(temp_nbt, 'wb') as f:
f.write(nbt_data)
# Load NBT (little-endian for Bedrock)
nbt = nbtlib.load(temp_nbt, byteorder='little')
# Enable experiments
if 'experiments' not in nbt:
nbt['experiments'] = nbtlib.Compound()
nbt['experiments']['experiments_ever_used'] = Byte(1)
nbt['experiments']['saved_with_toggled_experiments'] = Byte(1)
nbt['experiments']['gametest'] = Byte(1) # Beta APIs - REQUIRED for WorldEdit
nbt['experiments']['data_driven_items'] = Byte(1)
nbt['experiments']['upcoming_creator_features'] = Byte(1)
nbt['experiments']['data_driven_biomes'] = Byte(1)
# Save modified NBT
temp_modified = '/tmp/level_nbt_modified.dat'
nbt.save(temp_modified, byteorder='little')
# Read modified NBT data
with open(temp_modified, 'rb') as f:
modified_nbt_data = f.read()
# Reconstruct file with new header (update length)
version = struct.unpack('<I', header[:4])[0]
new_length = len(modified_nbt_data)
new_header = struct.pack('<II', version, new_length)
# Write final file
with open(output_file, 'wb') as f:
f.write(new_header)
f.write(modified_nbt_data)
print(f"Experiments enabled. Output written to {output_file}")
if __name__ == '__main__':
if len(sys.argv) != 3:
print("Usage: python enable_experiments.py <input_level.dat> <output_level.dat>")
sys.exit(1)
enable_experiments(sys.argv[1], sys.argv[2])# 1. STOP THE SERVER IN CRAFTY FIRST!
# 2. Get the pod name
POD=$(kubectl get pods -n minecraft -l app=crafty-controller -o jsonpath='{.items[0].metadata.name}')
# 3. Copy level.dat from server
kubectl cp minecraft/$POD:/crafty/servers/a7c1de95-4d8c-4c1b-81a0-956110f721a5/worlds/test-world/level.dat /tmp/level.dat
# 4. Run the script
python3 enable_experiments.py /tmp/level.dat /tmp/level_modified.dat
# 5. Copy modified level.dat back
kubectl cp /tmp/level_modified.dat minecraft/$POD:/crafty/servers/a7c1de95-4d8c-4c1b-81a0-956110f721a5/worlds/test-world/level.dat
# 6. Start the server in CraftyEdit /crafty/servers/<uuid>/permissions.json:
[
{
"permission": "operator",
"xuid": "2535410129381849"
}
]To find a player's XUID, check the server logs when they connect:
Player connected: ChipMc59, xuid: 2535410129381849
Key settings in server.properties:
level-name=test-world
view-distance=16
server-port=19132
server-portv6=19133
gamemode=survival
difficulty=normal
allow-cheats=trueOnce properly configured:
- Connect to the server
- Use
;wandto get the WorldEdit wand (wooden axe) - Use
;kitto see available kits - Left-click to set position 1, right-click to set position 2
- Use commands like
;set stone,;copy,;paste, etc.
Full command reference: https://github.com/SIsilicon/WorldEdit-BE
Symptom: Server starts fine but crashes immediately when a player joins.
Cause: WorldEdit requires Beta APIs but experiments are not enabled.
Solution: Follow the "Enabling Beta APIs" section above. Make sure to STOP the server before modifying level.dat.
Symptom: Experiments are enabled but reset to disabled after server restart.
Cause: The server was still running when level.dat was modified, so it overwrote your changes.
Solution: Always stop the server BEFORE modifying level.dat. Verify by checking the server is fully stopped in Crafty before copying files.
Symptom: Player has [worldedit] tag but commands like ;wand don't respond.
Cause: Beta APIs not enabled or player is not operator.
Solution:
- Verify experiments are enabled (check level.dat)
- Verify player XUID is in permissions.json with "operator" permission
- Restart server after changes
Symptom: Log shows Configured pack (id: xxx) was not found and was ignored
Cause: Pack files exist but are not registered in valid_known_packs.json.
Solution: Add the pack to valid_known_packs.json with correct UUID and version.
Backups can be configured in Crafty's web interface. The backup schedule is stored in:
/crafty/app/config/db/crafty.sqlite
To disable/enable backups via SQL:
-- Disable
UPDATE schedules SET enabled=0 WHERE schedule_id=1;
-- Enable
UPDATE schedules SET enabled=1 WHERE schedule_id=1;| Pack | UUID | Version |
|---|---|---|
| WorldEditBP (Behavior) | 3cdb2ddf-662e-4f8f-a0a1-1293b91ccb2f | 0.10.4 |
| WorldEditRP (Resource) | e304a4eb-f0a0-4979-ac17-7b0f46a555c8 | 0.10.4 |
- External Address: allpurpose.ddns.net:30132
- Protocol: UDP (Bedrock Edition)
- Crafty Web UI: https://allpurpose.ddns.net:30443
| File | Purpose |
|---|---|
/crafty/servers/<uuid>/server.properties |
Server configuration |
/crafty/servers/<uuid>/permissions.json |
Player permissions/operators |
/crafty/servers/<uuid>/valid_known_packs.json |
Addon registration |
/crafty/servers/<uuid>/behavior_packs/ |
Behavior pack files |
/crafty/servers/<uuid>/resource_packs/ |
Resource pack files |
/crafty/servers/<uuid>/worlds/<world>/level.dat |
World settings & experiments |
/crafty/servers/<uuid>/worlds/<world>/world_behavior_packs.json |
World behavior packs |
/crafty/servers/<uuid>/worlds/<world>/world_resource_packs.json |
World resource packs |
Last updated: 2026-01-07 Server UUID: a7c1de95-4d8c-4c1b-81a0-956110f721a5 World: test-world Player: ChipMc59 (XUID: 2535410129381849)