200 lines
4.8 KiB
Markdown
200 lines
4.8 KiB
Markdown
---
|
||
title: "Dockerizing my Minecraft Server + Geyser: from 'no space left' to stable releases"
|
||
date: 2025-09-29T09:06:29Z
|
||
draft: false
|
||
tags: ["minecraft", "docker", "paper", "papermod", "geyser", "linux", "lvm"]
|
||
categories: ["Homelab", "Games"]
|
||
toc: true
|
||
summary: "How I containerized a Java Minecraft server with Geyser, hit a /var space wall, and locked the server to the latest stable release."
|
||
---
|
||
|
||
## Why
|
||
I’ve been running a Java Minecraft world (with Bedrock players via **Geyser**) in `tmux`. I moved it to Docker for easier updates, backups, and restarts. Along the way I hit:
|
||
|
||
- `failed to register layer: ... no space left on device`
|
||
- Client saying: **“Outdated client, please use 1.21.9 Pre-Release 2”**
|
||
- Wanting config in a neat `.env` and **no whitelist**
|
||
|
||
Here’s exactly what I did.
|
||
|
||
---
|
||
|
||
## Folder layout
|
||
```bash
|
||
~/minecraft/
|
||
├─ docker-compose.yml
|
||
├─ .env
|
||
└─ plugins/
|
||
```
|
||
|
||
---
|
||
|
||
## `.env` (secrets & knobs)
|
||
Use the **latest stable** (not snapshots/pre-releases) by setting `VERSION=LATEST`.
|
||
|
||
```env
|
||
# Minecraft server configuration
|
||
EULA=TRUE
|
||
TYPE=PAPER
|
||
VERSION=LATEST
|
||
MEMORY=4G
|
||
USE_AIKAR_FLAGS=true
|
||
|
||
# RCON (remote console)
|
||
ENABLE_RCON=true
|
||
RCON_PASSWORD=superSecretPassword123
|
||
```
|
||
|
||
> I don’t use a whitelist, so no `WHITELIST`/`ENFORCE_WHITELIST` variables.
|
||
|
||
---
|
||
|
||
## `docker-compose.yml`
|
||
```yaml
|
||
services:
|
||
mc:
|
||
image: itzg/minecraft-server:latest
|
||
container_name: mc
|
||
restart: unless-stopped
|
||
ports:
|
||
- "25565:25565" # Java
|
||
- "19132:19132/udp" # Bedrock via Geyser plugin
|
||
env_file:
|
||
- .env
|
||
volumes:
|
||
- mc-data:/data
|
||
- ./plugins:/plugins:ro
|
||
volumes:
|
||
mc-data: {}
|
||
```
|
||
|
||
> The `version:` key in Compose is obsolete now, so I dropped it.
|
||
|
||
---
|
||
|
||
## Add Geyser (and optional Floodgate) as plugins
|
||
```bash
|
||
mkdir -p ~/minecraft/plugins
|
||
cd ~/minecraft/plugins
|
||
|
||
# Geyser (Spigot/Paper)
|
||
wget https://download.geysermc.org/v2/projects/geyser/versions/latest/builds/latest/downloads/spigot -O Geyser-Spigot.jar
|
||
|
||
# Floodgate (optional: Bedrock accounts without Java linking)
|
||
wget https://download.geysermc.org/v2/projects/floodgate/versions/latest/builds/latest/downloads/spigot -O Floodgate-Spigot.jar
|
||
```
|
||
|
||
Start it up:
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
On first run, Geyser writes its config to `/data/plugins/Geyser-Spigot/`. Open UDP **19132** on your firewall.
|
||
|
||
---
|
||
|
||
## Hit a wall: `/var` ran out of space
|
||
Docker stores layers at `/var/lib/docker` by default. My `/var` LV was tiny:
|
||
|
||
```
|
||
/dev/mapper/ubuntu--vg-var 3.9G 3.4G 333M 92% /var
|
||
```
|
||
|
||
### Quick cleanup
|
||
```bash
|
||
docker system df
|
||
docker system prune -f
|
||
docker builder prune -af
|
||
sudo apt-get clean
|
||
sudo journalctl --vacuum-size=100M
|
||
```
|
||
|
||
If that’s not enough, you have two good options:
|
||
|
||
### Option A — Move Docker’s data off `/var`
|
||
```bash
|
||
sudo systemctl stop docker
|
||
sudo mkdir -p /home/docker
|
||
sudo rsync -aHAX --info=progress2 /var/lib/docker/ /home/docker/
|
||
echo '{ "data-root": "/home/docker" }' | sudo tee /etc/docker/daemon.json
|
||
sudo systemctl start docker
|
||
docker info | grep "Docker Root Dir"
|
||
```
|
||
If all looks good, free the old space:
|
||
```bash
|
||
sudo rm -rf /var/lib/docker/*
|
||
```
|
||
|
||
### Option B — Grow `/var` (LVM)
|
||
Check free space in the VG:
|
||
```bash
|
||
sudo vgdisplay # look for "Free PE / Size"
|
||
```
|
||
If available, extend `/var` by +5G:
|
||
```bash
|
||
sudo lvextend -L +5G /dev/mapper/ubuntu--vg-var
|
||
sudo resize2fs /dev/mapper/ubuntu--vg-var
|
||
```
|
||
|
||
---
|
||
|
||
## The version mismatch: pre-release vs stable
|
||
My logs showed:
|
||
```
|
||
Starting minecraft server version 1.21.9 Pre-Release 2
|
||
```
|
||
That happens if the server pulls a pre-release build (or if `VERSION=LATEST`). Fix:
|
||
|
||
1. Ensure `.env` has:
|
||
```env
|
||
VERSION=LATEST_RELEASE
|
||
```
|
||
2. Recreate:
|
||
```bash
|
||
docker compose down
|
||
docker compose pull
|
||
docker compose up -d
|
||
```
|
||
3. Verify:
|
||
```bash
|
||
docker logs mc | grep "Starting minecraft server version"
|
||
# -> Starting minecraft server version 1.21.1 (example)
|
||
```
|
||
|
||
> Tip: If you **want to pin** and avoid auto-updates entirely, set `VERSION=1.21.1` (or whatever stable you’ve validated).
|
||
|
||
---
|
||
|
||
## No whitelist
|
||
Because I don’t set `WHITELIST`/`ENFORCE_WHITELIST`, anyone can join (subject to online-mode, bans, and Geyser/Floodgate auth settings). Manage ops/permissions via:
|
||
```bash
|
||
docker exec -it mc rcon-cli "op YourJavaIGN"
|
||
```
|
||
(or edit `/data/ops.json`).
|
||
|
||
---
|
||
|
||
## Backup & updates
|
||
- World/data live under the `mc-data` volume → back up `/data` regularly.
|
||
- Update cleanly:
|
||
```bash
|
||
docker compose pull && docker compose up -d
|
||
```
|
||
- Watch space:
|
||
```bash
|
||
watch -n5 'df -h /var; docker system df'
|
||
```
|
||
|
||
---
|
||
|
||
## TL;DR
|
||
- Put **Geyser/Floodgate** jars in `./plugins` and expose **19132/udp**.
|
||
- Keep configs in `.env`.
|
||
- Fix `/var` space by pruning, **moving Docker’s data-root**, or **extending `/var`** via LVM.
|
||
- Verify version in logs after each change.
|
||
|
||
Happy block-breaking! 🧱🚀
|
||
|
||
---
|
||
|
||
{{< sigdl >}}
|