minecraft LXC¶
Overview¶
| Property | Value |
|---|---|
| Hostname | minecraft |
| IP Address | 192.168.0.213 |
| VMID | 112 |
| OS | Debian GNU/Linux 12 (bookworm) |
| CPU | 2 cores |
| RAM | 6 GB |
| Disk | 20 GB (local-lvm) |
| Purpose | Minecraft Java + Paper server with Bedrock cross-play via GeyserMC |
Status (2026-07-05): stopped. The
minecraftcontainer was stopped after causing a host-wide CPU contention incident (see Lessons Learned). Scheduled for deletion - not currently running.
Running Services¶
| Service | Description |
|---|---|
sshd |
OpenSSH server |
| Docker daemon | Container runtime |
minecraft container |
PaperMC + GeyserMC + Floodgate |
Open Ports¶
| Port | Protocol | Service |
|---|---|---|
| 22 | TCP | SSH |
| 25565 | TCP | Minecraft Java Edition |
| 19132 | UDP | Minecraft Bedrock Edition (GeyserMC) |
| 8100 | TCP | BlueMap web map (LAN only) |
Docker Stack¶
Single compose stack at /opt/minecraft/.
| Container | Image | Description |
|---|---|---|
minecraft |
itzg/minecraft-server:latest |
PaperMC server with auto-installed plugins |
Plugins (auto-installed via env)¶
| Plugin | Purpose |
|---|---|
| GeyserMC | Translates Bedrock protocol to Java - allows phone/console players |
| Floodgate | Microsoft account auth for Bedrock players (no Java licence needed) |
Plugins (manually placed in /opt/minecraft/data/plugins/)¶
| Plugin | Version | Purpose |
|---|---|---|
| EssentialsX | 2.21.2 | 130+ extra commands: /home, /tpa, /warp, /spawn, /kit, /afk |
| EssentialsXSpawn | 2.21.2 | Spawn management addon for EssentialsX |
| WorldEdit | 7.4.2 | Bulk block editing, copy/paste, area fills |
| WorldGuard | 7.0.15 | Region protection - restrict building in defined areas |
| BlueMap | 5.16 | Live 3D web map, accessible at http://192.168.0.213:8100 |
Volumes¶
| Path | Description |
|---|---|
/opt/minecraft/data |
Server data - world, plugins, configs, logs |
Public Access¶
Exposed via Pangolin raw TCP/UDP resources on the Hetzner VPS:
| Resource | Type | VPS Port | Target |
|---|---|---|---|
| Minecraft Java | TCP | 25565 | 192.168.0.213:25565 |
| Minecraft Bedrock | UDP | 19132 | 192.168.0.213:19132 |
Komodo¶
Managed by Komodo (LXC 105) via periphery agent in outbound mode.
- Periphery config:
/etc/komodo/periphery.config.toml - Core address:
http://192.168.0.105:9120
SSH Access¶
Key-based authentication only. Password login disabled.
To add a new key from the Proxmox host:
Common Operations¶
# View live logs
docker compose -f /opt/minecraft/docker-compose.yml logs -f
# Restart server
docker compose -f /opt/minecraft/docker-compose.yml restart
# Update to latest Paper + plugins
docker compose -f /opt/minecraft/docker-compose.yml pull
docker compose -f /opt/minecraft/docker-compose.yml up -d
# Open server console (RCON-like)
docker attach minecraft
# Detach: Ctrl+P then Ctrl+Q
Admin (OP) Management¶
# Op a player (Java - use Java profile name visible in tab list)
ssh root@192.168.0.213 "docker exec minecraft rcon-cli op PlayerName"
# Op a Bedrock player (GeyserMC adds a dot prefix to Xbox gamertag)
ssh root@192.168.0.213 "docker exec minecraft rcon-cli op .XboxGamertag"
# Remove op
ssh root@192.168.0.213 "docker exec minecraft rcon-cli deop PlayerName"
# Interactive console (run multiple commands)
ssh root@192.168.0.213 "docker exec -i minecraft rcon-cli"
Useful in-game admin commands (after getting op):
gamemode creative PlayerName # creative mode
gamemode survival PlayerName # survival mode
time set day # set daytime
weather clear # clear weather
whitelist add PlayerName # add to whitelist
tp PlayerName1 PlayerName2 # teleport
Note: Use the name exactly as shown in the in-game Tab list - that is how the server identifies the player. Java profile name and Xbox gamertag can differ.
New World Generation¶
ssh root@192.168.0.213
cd /opt/minecraft
docker stop minecraft
rm -rf data/world data/world_nether data/world_the_end
docker start minecraft
Warning: the old world is permanently deleted. Back up
/opt/minecraft/data/world/first if needed.
Second Server (Planned - Not Yet Implemented)¶
Run a second Minecraft server on the same LXC 112 for a separate group of players.
Resource requirements¶
Before adding the second server, increase LXC 112 RAM in Proxmox from 6 GB to 10 GB:
- Server 1 (family): 4G
- Server 2 (friends): 2G
- OS overhead: ~1G buffer
In Proxmox web UI: LXC 112 - Resources - Memory - set to 10240 MB. No restart needed if done while container is running (hot-add), or restart the LXC after.
Compose changes¶
Add a second service to /opt/minecraft/docker-compose.yml (and the repo file at compose/proxmox-lxc-112/minecraft/docker-compose.yml):
minecraft2:
image: itzg/minecraft-server:latest
container_name: minecraft2
environment:
EULA: "TRUE"
TYPE: PAPER
MEMORY: 2G
TZ: Europe/Budapest
PLUGINS: |
https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot
https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot
MOTD: "Homelab Minecraft 2"
MAX_PLAYERS: "10"
DIFFICULTY: normal
ports:
- "25566:25565"
- "19133:19132/udp"
- "8101:8100"
volumes:
- /opt/minecraft/data2:/data
restart: unless-stopped
After adding, create the data dir and start:
Post-start: set auth-type: floodgate in /opt/minecraft/data2/plugins/Geyser-Spigot/config.yml and enforce-secure-profile=false in /opt/minecraft/data2/server.properties, then restart minecraft2.
Pangolin - new raw resources (VPS)¶
Add to /opt/pangolin/config/traefik/traefik_config.yml:
Add to /opt/pangolin/docker-compose.yml gerbil ports:
Add in Pangolin UI (Sites - Minecraft - New Resource):
| Resource | Protocol | External Port | Target |
|---|---|---|---|
| Minecraft Java 2 | TCP | 25566 | localhost:25566 |
| Minecraft Bedrock 2 | UDP | 19133 | localhost:19133 |
Open UFW on VPS:
Restart Pangolin stack:
Connection addresses¶
| Server | Java | Bedrock |
|---|---|---|
| Server 1 (family) | pangolin.homelabor.net:25565 |
pangolin.homelabor.net:19132 |
| Server 2 (friends) | pangolin.homelabor.net:25566 |
pangolin.homelabor.net:19133 |
Lessons Learned¶
- GeyserMC auth-type: After the first start, edit
/opt/minecraft/data/plugins/Geyser-Spigot/config.ymland setauth-type: floodgate. Without this, Bedrock players also need a Java Edition account. - UDP through Pangolin: Pangolin raw UDP resources can have higher latency for Bedrock players compared to direct port forwarding. If Bedrock feels laggy, consider adding a direct UDP port forward on the router as an alternative path.
- EULA:
EULA: "TRUE"must be set - the server refuses to start without accepting the Minecraft EULA. - Memory: The
MEMORY: 4Genv var sets both-Xmsand-Xmx. 4G is comfortable for up to ~10 players with vanilla Paper. Increase to 6G for modpacks. - World persistence: The world lives in
/opt/minecraft/data/world/. Back this up separately if needed - it is not included in the standard Restic backup script. - Paper version naming: Paper labels the current Minecraft 26.1.x releases as "1.21.11" internally (for API compatibility). This is not an old version - the build date in the logs confirms it. Use the latest launcher client; it connects fine despite the name difference.
- Multiplayer disabled on Java launcher: If the launcher shows "Multiplayer disabled - please check your Microsoft account settings", go to
account.xbox.com/settingsand enable "You can join multiplayer games" under Privacy settings. This is triggered by age restrictions on the Microsoft/Xbox account. - Bedrock players cannot chat (enforce-secure-profile): By default Paper has
enforce-secure-profile=trueinserver.properties. Bedrock players (via GeyserMC) don't have a Java chat signing key, so they cannot chat. Fix: edit/opt/minecraft/data/server.propertiesand setenforce-secure-profile=false, then restart the container. Note: theENFORCE_SECURE_PROFILEenv var in the compose file does NOT override an existingserver.propertiesvalue - direct file edit is required. - BlueMap requires accept-download: On first start BlueMap needs
accept-download: truein/opt/minecraft/data/plugins/BlueMap/core.conf, then reload with/bluemap reload. Without this it starts but the webserver doesn't serve the map. BlueMap uses port 8100, not 8123 like dynmap. - dynmap incompatible with 1.21.11: dynmap 3.2.1 (latest GitHub release) cannot find internal Minecraft classes on 1.21.11. The 3.8 version that supports it is only on SpigotMC (requires login). Use BlueMap instead - actively maintained, supports 1.21.11, available on Modrinth.
- Minecraft Flatpak on Nobara/KDE - use Prism Launcher: The official
com.mojang.MinecraftFlatpak has a token storage bug on KDE/non-GNOME desktops - it cannot save the Microsoft account token, causing "couldn't connect to Minecraft services" errors on every launch. Fix: install Prism Launcher instead (flatpak install flathub org.prismlauncher.PrismLauncher). Prism handles auth via browser login which bypasses the keyring issue. Remove the official Flatpak withsudo flatpak uninstall com.mojang.Minecraft --delete-data. - EssentialsX unsupported version warning: EssentialsX 2.21.2 logs "You are running an unsupported server version!" on 1.21.11. The plugin loads and works despite the warning - commands function normally.
- Komodo GitOps for compose changes: Always edit the repo compose file and deploy via Komodo (Pull + Deploy). Do not edit
/opt/minecraft/docker-compose.ymldirectly on the server - it will be overwritten on the next Komodo deploy. - Powder Snow (puder hó): In snowy biomes players fall through powder snow blocks and start freezing. Fix: wear leather boots - they allow walking on top of powder snow. Other boot materials (iron, diamond, etc.) fall through. Quick admin fix:
/give PlayerName leather_boots. - World seed: Current world uses seed
-2350879005487267529(cherry grove + snowy mountain + village near spawn). Set viaSEEDenv var in compose file. - Pangolin gerbil restart breaks Traefik: Traefik uses
network_mode: service:gerbil- it shares gerbil's network namespace. If only gerbil is recreated, Traefik stays attached to the old (deleted) namespace and stops routing all traffic - port 443 goes dark, newt tunnels disconnect, Minecraft ports stop working. Fix: always recreate the full stack together:cd /opt/pangolin && docker compose up -d --force-recreate. Never restart gerbil alone. - Pangolin health check false negatives: Pangolin's built-in health check sends HTTP requests to ports 25565 and 19132. Minecraft TCP returns EOF (not HTTP) and UDP is unreachable via HTTP, so both show as offline in the UI. The actual tunnel works - verify with
nc -z pangolin.homelabor.net 25565. Disable health checks in the Pangolin resource settings to avoid confusion.
Incident: BlueMap render thread starved the whole Proxmox host (2026-07-05)¶
Symptom: After a Proxmox host reboot at 21:08 CEST, several unrelated public services on LXC 100 (Jellyfin, DocuSeal, Form, Kan) started flapping between healthy/unhealthy every 1-3 minutes via Pangolin/Newt (context deadline exceeded on health checks), continuing for 2+ hours - long after the reboot itself. Initial suspicion was a problem specific to Jellyfin or a Komodo-related issue (Komodo's mongo container was separately crash-looping the same night, on a different LXC - unrelated coincidence).
Diagnosis: Proxmox host load average sat at 5.8-6.3 with only 6 physical cores. Per-thread CPU accounting on the minecraft container's Java process (for t in /proc/<pid>/task/*/; do ... done) showed the BlueMap-MapUpdate thread had burned ~20x more CPU ticks than any other thread - BlueMap was continuously re-rendering the world map at ~100%+ of a full core, non-stop, since server startup. With only 6 cores total on the host, this single sustained hog was enough to cause scheduling delays for other LXCs sharing the same physical CPU, which showed up as intermittent slow HTTP responses (and thus health-check timeouts) on completely unrelated services on LXC 100.
Fix: Stopped the minecraft container entirely (docker stop minecraft on LXC 112), which also stops BlueMap. Host load average dropped from ~6.0 to ~4.1 within seconds. Server and BlueMap are marked for deletion later - not currently planned to be restarted as-is.
Lesson: A single CPU-hungry container on ANY LXC can starve every other LXC on the same Proxmox host if the host is near its core count - it is not sandboxed away by the LXC boundary. BlueMap in particular does full-world background rendering on every restart (not just first install) and has no default rate limit. If BlueMap is used again, throttle it via render-thread-count in plugins/BlueMap/core.conf, and don't assume a "healthy 2 hours uptime" container status means it isn't degrading other services on the same host - check host-wide uptime/load average, not just per-container health.