Bedrock Edition is the easiest Minecraft variant to self-host. No mod loader, no Java heap tuning, one well-maintained Docker image. The interesting part is not standing it up from scratch. It is moving a world that has already been played on for real, without silently corrupting it. Running Java too, for mods? See the separate guides on legacy Forge and modern Fabric. Bedrock can run neither.
itzg/minecraft-bedrock-server
is the de facto standard. Actively maintained, tracks Mojang's Bedrock server releases quickly, and exposes
every server property as an environment variable, so a whole world's config lives in one
docker-compose.yml instead of hand-edited property files:
services:
minecraft-bedrock:
image: itzg/minecraft-bedrock-server
restart: unless-stopped
environment:
EULA: "TRUE"
SERVER_NAME: "Family Server"
GAMEMODE: survival
DIFFICULTY: normal
ports:
- "19132:19132/udp"
volumes:
- /opt/minecraft/data:/data
That is genuinely the whole setup for a fresh world. The gotchas below are about moving an existing world onto a server like this, not first-time setup.
A Minecraft world usually starts life on whatever Docker host was already running. A NAS, a shared homelab VM, whatever was convenient. That is fine for a while. It also means the world is not isolated from unrelated experiments on the same host, and it easily ends up outside your backup coverage when backups are scoped per VM or per container rather than blanket-covering the box. Migrate it onto its own small dedicated container, so it gets its own backup job entry and nothing else on the source host can affect it.
The migration is a plain two-hop copy. Nothing Minecraft-specific about it:
ssh <old-host> "sudo tar -C /path/to/world -cf - ." | tar -C <local-stage> -xf -
tar -C <local-stage> -cf - . | ssh <new-host> "tar -C /opt/minecraft/data -xf -"
Using sudo tar at the source, rather than a network filesystem client like NFS or SMB, sidesteps
any permission-mapping weirdness the file-sharing layer adds on top of what is described below.
If the world's previous home was a NAS, Synology or QNAP or similar, expect a stray thumbnail and indexing
folder to come along in a naive recursive copy. Synology's is @eaDir. It is harmless, and the
server never touches it. Delete it after the copy to keep the data directory clean. Otherwise it sits there
confusing whoever goes looking through the folder later.
behavior_packs/<pack-name>/ folder left
as dr-xr-xr-x, read-only with no write bit at all, from however it was extracted. The container
image rewrites that directory on every boot as part of its internal version-migration check. When it
cannot, you get an immediate Permission denied and a crash-loop that has nothing to do with the
world data being corrupt. Fix it with a blanket permission reset on the whole data directory before first
boot on the new host:
chmod -R u+w /opt/minecraft/data
Do that as a standard step on any world you migrate from another host, not as a reactive fix once
you hit the crash. It costs nothing and avoids a confusing debugging session that looks like data corruption
and is not.
Bedrock's protocol runs entirely over UDP, RakNet, which rules out any tunnel that only forwards TCP. A
UDP-capable tunnel forwarded straight to 19132/udp is all you need. Either a lightweight P2P
tunnel service or your own small relay VPS running something like
frp. No port-forwarding on your home router. No static IP.
One client-side gotcha is worth knowing ahead of time, specific to Bedrock's own "Add Server" dialog and a
few similar Bedrock-ecosystem clients, Hytale's included. The address field wants host and port
separately. Paste a combined host:port string into the single address field and
you get a generic "server address is not correctly formatted" error that says nothing about whether the
server is reachable. It fails identically whether the server is up or down. If that error persists after you
split the fields, delete the saved server entry and re-add it from scratch rather than editing it. A stale,
partially pasted previous attempt is more likely than a server-side problem.