Skip to content

Minecraft VM runbook (VM 103)

Operating guide for the Bedrock server VM (minecraft, VM 103, 192.168.1.224, WireGuard 10.10.0.2). Three native Bedrock Dedicated Server (BDS) instances run as systemd services under the minecraft user. Players reach them through the VPS (mc.byers.cc + per-server UDP port) — see VPS and WireGuard.

Golden rules

  1. Back up before you change anything. Before touching any world or config, make a timestamped tarball in ~/manual-backups/ and confirm it exists.
  2. Never delete anything under bedrock_backups/, dbbackups/, or any worlds/ directory — add or replace only, deliberately.
  3. Don't restart all three servers at once — orphaned bedrock_server processes steal each other's ports (see Port race).
  4. Never print secrets: WireGuard private keys, ~/.cloudflared/ credentials, anything in .ssh/. Locations only.

Access

From Command
LAN / tailnet (ops is subnet router) ssh minecraft
Anywhere, via the VPS jump host ssh -J vps minecraft@10.10.0.2

Key-only auth everywhere. The Proxmox host is root@192.168.1.138 if you need the hypervisor.

How players and backups flow

flowchart LR
    players["Players"] -- "mc.byers.cc<br/>UDP 19132 / 19134 / 19136" --> npm["VPS · NPM<br/>stream passthrough"]
    npm -- "WireGuard<br/>10.10.0.1 → 10.10.0.2" --> bds["VM 103<br/>three BDS instances"]
flowchart LR
    cron["03:00<br/>root cron"] --> a["autoupdate.sh:<br/>stop servers"] --> t["tarball worlds<br/>→ ~/bedrock_backups"] --> u["update BDS<br/>if release"] --> r["restart<br/>servers"] --> p["prune<br/>14d + 8w"]
    p --> k["03:30 kopia<br/>backup@mc → NAS<br/>30d + 52w"]

The 02:30–03:30 window is a no-touch zone — the chain above owns the servers during it.

The three worlds

Directory systemd service In-game name Ports (v4·v6) Active world Mode
creative-world minecraft-creative-world "Rory and Elliott Creative World" 19132·19133 Creative level Creative, open
rorys-friends-creative minecraft-rorys-friends-creative "Rorys Friends Creative" 19134·19135 ipad-world Creative, allowlist on
survival-classic minecraft-survival-classic "Survival World" 19136·19137 Survival level Survival, allowlist on
  • 19132 is the default Bedrock port — players who don't type a port land on the creative world.
  • Every server.properties needs enable-lan-visibility=true. false blanks the MOTD and nobody can join (see troubleshooting).
  • History note: rorys-friends-creative is the ipad-world clone (renamed from the old survival-world slot 2026-06-13, keeping port 19134); survival-classic is the original survival world, resurrected the same day.
  • Services run with StandardInput=null — there is no interactive console. All three are enabled (start on boot).

Allowlist changes: prefer the mc-admin panel; manual fallback is editing allowlist.json in the server dir (validate the JSON) then sudo systemctl restart minecraft-<dir>. Adding a whole new server: see New world.

The 03:00 no-touch window

Do not touch services or worlds between roughly 02:30 and 03:30

/home/minecraft/autoupdate.sh fires at 03:00 daily as a root cron. It stops every minecraft-* service, rsyncs new BDS binaries, restarts them, takes the nightly world tarballs, and prunes old ones. Service operations or world edits during this window race the updater and are how worlds get corrupted. The nightly vzdump (02:00) and the kopia snapshot (03:30) bracket it — treat 02:00–03:30 as maintenance-owned time.

What autoupdate.sh preserves: worlds/, server.properties, allowlist.json, permissions.json — it replaces only binaries and vanilla packs, and since 2026-06-17 it re-asserts enable-lan-visibility=true after each update. Its SERVER_DIRECTORIES=(...) array must list every server directory — keep it in sync when servers change.

Cleanup candidate: update_log.txt

autoupdate.sh appends to update_log.txt with no rotation — it is ~64 MB and growing. Safe to truncate or put under logrotate; nothing reads it programmatically.

Do NOT touch

  • /home/minecraft/autoupdate.sh — root cron, 03:00. Edit only the SERVER_DIRECTORIES array when adding/removing a server, and take a timestamped .bak first.
  • /home/minecraft/create_mc_world.sh — provisions new instances + systemd units.
  • /home/minecraft/addon_install.py — addon installer pipeline.
  • /etc/systemd/system/minecraft-*.service — service definitions.
  • Anything under bedrock_backups/, dbbackups/, or worlds/.
  • cron itself (crontab, /etc/cron.*).

Backup chain — as of 2026-08-12

The old chain is dead — do not trust older docs

PBS is decommissioned (LXC 101 stopped; destroy after 9 Sep 2026) and the VPS rsync leg was fully retired 2026-08-11 — no push, no VPS retention, old tarballs deleted. Any doc mentioning pbs-nas or minecraft_backups/ on the VPS is stale.

The chain in words, innermost to outermost:

  1. On the VMautoupdate.sh (03:00) tars each server's world into bedrock_backups/<server>/backup_*.tar.gz (root-owned) and prunes nightly to 14 daily + 8 weekly. Ad-hoc backups you make by hand go in ~/manual-backups/ (owned by minecraft). The mc-admin restore menu reads these VM-local tarballs only — nothing off-VM.
  2. Off-VM history (kopia)backup@mc snapshots /home/minecraft/bedrock_backups daily at 03:30 to the kopia repo on the NAS, via the kopia server on ops (192.168.1.190:51515, TLS, per-machine users). Retention 30 daily + 52 weekly — this is where you go for anything older than two weeks. Details in Backups overview.
  3. Whole-VM image (vzdump) — nightly 02:00 Proxmox vzdump of VMs 100/102/103 to the NAS over NFS, zstd, keep 7 daily + 4 weekly. Disaster recovery for the whole VM, not for a single world.
  4. Offsite — the latest vzdump set only syncs to Google Drive at 04:00 (rclone, --drive-use-trash=false --delete-before). See Offsite.

The kopia world history has no cloud copy

Only the vzdump images reach Google Drive. The kopia repo (including 52 weeks of world tarballs) lives solely on the NAS — owner's accepted risk; B2 at ~$0.40/mo is the standing fix. If the NAS burns, world history beyond the latest vzdump is gone.

Restore procedures live in Restores; the quick path for "roll a world back a few days" is the mc-admin Backups tab (it tars the current world to manual-backups/ before swapping, and never touches configs or allowlists).

Troubleshooting

Servers ping but nobody can join ("Kelp")

Clients spin then time out, disconnect codeword "Kelp"; RakNet pong is 33 bytes with a blank MOTD. Cause: something reset enable-lan-visibility=false in server.properties (a BDS auto-update did exactly this in June 2026). Fix: set it back to true in each server.properties and restart. Healthy pong is ~140 bytes starting MCPE;<name>;…. Diagnose UDP reach from the VPS: sudo timeout 30 tcpdump -ni any "udp and portrange 19132-19137" while a client joins.

A port answers as the wrong server, or "server full"

Restarting several BDS instances at once leaves orphaned processes holding ports. Check: ss -ulnp | grep -E ':1913[2-7]' — every port must map to a distinct pid. Fix: stop all three services, pkill -9 -u minecraft -f bedrock_server, then start them one at a time ~8 s apart, creative (19132) first. Never restart them together.

Auto-update outran the clients

autoupdate.sh pulls the newest BDS nightly; lagging client apps may silently fail to join. Option: pin LATEST_FILENAME in autoupdate.sh until clients catch up (with approval — see do-not-touch list).