Homelab
Minecraft Plugin Updates
Refreshing Stale Geyser, Floodgate, and Paper Plugins on a Minecraft Kubernetes Server
Overview
Long-running Minecraft pods accumulate plugin drift because the itzg image's PLUGINS URLs only re-resolve when the container starts. This procedure restarts the pod so REMOVE_OLD_MODS: TRUE1 wipes the stale jars and the entrypoint downloads the current upstream builds of Geyser2 and Floodgate3.
Verified on MC 1.21.11 Paper, May 31, 2026 — refreshed to Geyser 2.10.0-b1158, Floodgate 2.2.5-SNAPSHOT b132, ViaVersion 5.9.1.
Before You Begin
Prerequisites
- Minecraft Paper Server completed
- Pod with
AGEmore than a few weeks (the jars are downloaded on container start, so anything long-running is a candidate)
Why This Approach
The itzg image's refresh mechanism is restart-driven, not runtime-driven. There is no in-pod "reload plugins" command that re-pulls the PLUGINS URLs. Editing the HelmRelease and reconciling Flux works too, but if the URLs haven't changed Flux has nothing to apply. kubectl rollout restart terminates the pod, lets the entrypoint re-execute the download with REMOVE_OLD_MODS: TRUE wiping the old jars, and brings up a pod with current upstream builds.
Diagnose Plugin Staleness
Pod Uptime
kubectl get pods -n minecraft Observed (2026-05-31): AGE 53d — 7+ weeks since the last container start.
Plugin Jar Dates
kubectl exec -n minecraft deploy/minecraft -- ls -la /data/plugins | grep -iE 'geyser|floodgate' Observed (2026-05-31):
-rw-rw-r--. 1 minecraft 2000 11559667 Apr 8 09:06 floodgate-spigot.jar
-rw-rw-r--. 1 minecraft 2000 18214145 Apr 8 09:06 Geyser-Spigot.jar Save the World
RCON: save-all
kubectl exec -n minecraft deploy/minecraft -- rcon-cli "save-all" Expected: Saving the game (this may take a moment!)Saved the game
Restart the Pod
Kubectl: Rollout Restart
kubectl rollout restart deployment -n minecraft minecraft Observed (2026-05-31): PodSecurity warning about the playit-agent sidecar's allowPrivilegeEscalation and capability drop — namespace is in WARN mode, rollout proceeded.
Watch the Rollout
kubectl get pods -n minecraft -w Expected: new pod reaches 2/2 Running within 2-5 minutes as plugins re-download.
Diagnose the Sidecar Crash
On the 2026-05-31 rollout, the new pod went CrashLoopBackOff 11 seconds after start — too fast for Paper to be the failure point.
Pod Events
POD=$(kubectl get pod -n minecraft -l app=minecraft -o jsonpath='{.items[0].metadata.name}')
kubectl describe pod -n minecraft $POD | sed -n '/Events:/,$p' Observed: Back-off restarting failed container playit-agent — the minecraft container itself was Running.
Sidecar Logs
kubectl logs -n minecraft $POD -c playit-agent --tail=50 Observed:
INFO playitd::daemon: Starting playitd socket_path=None secret_path=None version=1.0.5
playitd error: IPC error: Failed to bind to socket: Permission denied (os error 13) playit-agent 1.0.5 hardcodes its IPC socket to /var/run/playitd.sock4, which is not writable in this container.
Compare With a Working Sidecar
kubectl get pods -n factorio -o json | jq -r '.items[].status.containerStatuses[] | select(.name=="playit-agent") | "image: \(.image)\nimageID: \(.imageID)"' Observed: factorio's running digest 84d8ea84… differed from minecraft's failed pull 188c2129… (the upstream 1.0.5 tag). Factorio is on an older registry-untagged digest cached locally — :latest rolled forward only on minecraft's fresh pull.
Pin the Sidecar
HelmRelease: Pin Image and Socket Path
k8s/apps/minecraft/helmrelease.yaml (postRenderers patch):
# ... existing postRenderers + patches header ...
patch: |
- op: add
path: /spec/template/spec/containers/-
value:
name: playit-agent
image: ghcr.io/playit-cloud/playit-agent:1.0.5 # was :latest
args: # new
- "--socket-path"
- "/tmp/playitd.sock"
env:
- name: SECRET_KEY
valueFrom:
secretKeyRef:
name: playit-secret
key: secret-key Git: Commit and Push
git add k8s/apps/minecraft/helmrelease.yaml
git commit -m "fix(minecraft): pin playit-agent to 1.0.5, route IPC socket to /tmp"
git push Flux: Reconcile
flux reconcile source git flux-system && flux reconcile kustomization sync Reconciliation replaces the pod; both containers restart and plugins re-download a second time.
Verify Plugin Refresh and Bedrock Connection
Pod Status
kubectl get pods -n minecraft Expected: 2/2 Running.
Sidecar Startup
kubectl logs -n minecraft deploy/minecraft -c playit-agent --tail=30 Expected: socket_path=Some("/tmp/playitd.sock") on the first line, followed by agent registered. The playit.gg dashboard flips both Minecraft Java and Bedrock tunnels back to green.
Plugin Startup Banners
kubectl logs -n minecraft -l app=minecraft -c minecraft --tail=500 | grep -iE 'loading server plugin|geyser version' Expected: current upstream versions for floodgate, ViaVersion, Geyser-Spigot.
Bedrock Connection
After a Bedrock player retries:
kubectl logs -n minecraft -l app=minecraft -c minecraft --tail=200 | grep -iE 'geyser|floodgate' Expected: [Geyser-Spigot] Player connected with username <name> followed by [floodgate] Floodgate player logged in as .<name> joined (UUID: 00000000-0000-0000-xxxx-xxxxxxxxxxxx). Whitelisting Bedrock players is covered in Server Management.
Resources
Footnotes
itzg, "Docker Minecraft Server — Plugins and Mods," github.com. Accessed: May 31, 2026. [Online]. Available: https://docker-minecraft-server.readthedocs.io/en/latest/mods-and-plugins/ ↩
GeyserMC, "Geyser Downloads," geysermc.org. Accessed: May 31, 2026. [Online]. Available: https://geysermc.org/download/?project=geyser ↩
GeyserMC, "Floodgate Downloads," geysermc.org. Accessed: May 31, 2026. [Online]. Available: https://geysermc.org/download/?project=floodgate ↩
playit-cloud, "playit-agent — playit-ipc/src/paths.rs (v1.0.5)," github.com. Accessed: May 31, 2026. [Online]. Available: https://github.com/playit-cloud/playit-agent/blob/v1.0.5/packages/playit-ipc/src/paths.rs ↩