---
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 >}}
