# Journey Into Imagination — Minecraft Server Deployment Plan **Application:** PaperMC Minecraft Server **Namespace:** `minecraft` **Deployment name:** `papermc` **Service / DNS name:** `journey-into-imagination` **ArgoCD path:** `cluster/applications/minecraft/` **Reviewed:** _Pending Ryan approval_ --- ## Version Pinning | Component | Version | |-----------|---------| | itzg/minecraft-server image | `2026.7.0` | | PaperMC (Minecraft version) | `1.21.4` (build 232 — last stable 1.21.x) | | SleepMost plugin | `5.6.2` (auto-downloaded at server start) | > **Note on PaperMC versioning:** PaperMC migrated to a new version scheme (`26.x`) as of mid-2026. The task requested 1.21.x, so we pin `VERSION=1.21.4`. When you're ready to upgrade to the latest stable, change `VERSION` in `deployment.yaml` and `configmap.yaml` to `26.2` and bump the image tag to the latest `itzg/minecraft-server` release. Check plugin compatibility (SleepMost) before upgrading. --- ## Storage - **StorageClass:** `pure-block` (confirmed live — `kubectl get storageclass`) - **PVC size:** 50Gi — expandable via Pure Storage CSI if the world grows - **Mount:** `/data` inside the container (worlds, plugins, configs all live here) --- ## Networking Architecture ``` Internet (players) | | DNS: journey-into-imagination.mk-labs.cloud → WAN IP (Cloudflare A record) | UniFi UDM Pro | Port Forward: WAN:25565 → 10.1.71.80:25565 (TCP) | ingress-nginx LoadBalancer (10.1.71.80) | tcp-services ConfigMap: 25565 → minecraft/journey-into-imagination:25565 | journey-into-imagination Service (ClusterIP, minecraft namespace) | papermc Pod (port 25565) ``` --- ## Prerequisites — Manual Steps Before Deploying ### 1. Generate a real RCON password ```bash # Generate a secure password openssl rand -base64 24 # Output example: abc123... (save this — you'll need it) # Base64-encode it for the Secret echo -n 'YOUR_GENERATED_PASSWORD' | base64 ``` Edit `cluster/applications/minecraft/secret.yaml` and replace the placeholder value: ```yaml data: rcon-password: ``` > ⚠️ Do NOT commit real credentials in plaintext. If this is a concern long-term, > migrate to ExternalSecrets + 1Password (Day 2 operation). ### 2. UniFi Port Forward (Ryan — manual step) In UniFi Network → Firewall & Security → Port Forwarding: - **Name:** `minecraft-papermc` - **Protocol:** TCP - **External Port:** 25565 - **Internal IP:** 10.1.71.80 (ingress-nginx LoadBalancer) - **Internal Port:** 25565 - **Enabled:** Yes ### 3. Cloudflare DNS Records (Ryan — manual step) In Cloudflare Dashboard → mk-labs.cloud zone: **A Record (public server address):** | Type | Name | Value | Proxy | |------|------|-------|-------| | A | `journey-into-imagination` | `` | DNS only (gray cloud) | > Minecraft uses raw TCP — Cloudflare proxy (orange cloud) will NOT work. > Use DNS-only mode (gray cloud). **SRV Record (allows clients to connect without specifying port):** | Type | Name | Service | Proto | Priority | Weight | Port | Target | |------|------|---------|-------|----------|--------|------|--------| | SRV | `_minecraft._tcp.journey-into-imagination` | `_minecraft` | `_tcp` | 0 | 5 | 25565 | `journey-into-imagination.mk-labs.cloud` | > The SRV record allows players to connect using `journey-into-imagination.mk-labs.cloud` > without specifying `:25565`. Most modern Minecraft clients resolve SRV records. ### 4. Internal DNS (Technitium — automated via ExternalDNS) The Service in `service.yaml` has this annotation: ```yaml external-dns.alpha.kubernetes.io/hostname: journey-into-imagination.local.mk-labs.cloud ``` ExternalDNS (Technitium provider) will create the internal A record automatically when ArgoCD syncs. No manual action required for internal DNS. --- ## Deployment Steps ### Step 1: Update the RCON Secret Complete prerequisite #1 above, then commit the updated secret. ### Step 2: Commit and Push to Gitea ```bash cd ~/git/homelab git status # review what changed git add cluster/applications/minecraft/ cluster/platform/ingress-nginx/values.yaml git commit -m "feat(minecraft): add Journey Into Imagination PaperMC server - Namespace, Deployment, Service (journey-into-imagination), PVC, Secret, ConfigMap - ArgoCD Application at cluster/applications/minecraft/ - ingress-nginx TCP forwarding: 25565 -> minecraft/journey-into-imagination:25565 - PaperMC 1.21.4, itzg/minecraft-server:2026.7.0, SleepMost 5.6.2 - StorageClass: pure-block, 50Gi PVC for world data" git push ``` ### Step 3: Verify ArgoCD Discovers and Syncs ArgoCD app-of-apps auto-discovers `cluster/applications/minecraft/application.yaml`. ```bash # Watch ArgoCD pick it up (from carousel-of-progress) kubectl get application minecraft -n argocd -w # Or check ArgoCD UI at argocd.local.mk-labs.cloud ``` Wait for status: `Synced` / `Healthy` ### Step 4: Watch the Pod Start Up First startup will download the PaperMC jar — this can take 2-3 minutes. ```bash kubectl get pods -n minecraft -w # Tail the logs to watch PaperMC boot kubectl logs -n minecraft -l app.kubernetes.io/component=papermc -f ``` Look for: ``` [Server thread/INFO]: Done (X.XXXs)! For help, type "help" ``` ### Step 5: Install SleepMost Plugin (auto via PLUGINS env var) The `PLUGINS` env var in the ConfigMap points to the SleepMost JAR download URL. itzg/minecraft-server downloads and installs it automatically on startup. Verify it loaded: ```bash kubectl exec -n minecraft -it deployment/papermc -- rcon-cli # In rcon console: plugins # Should list: SleepMost ``` ### Step 6: Verify Connectivity **Internal test (from carousel-of-progress):** ```bash # Port probe — should succeed nc -zv journey-into-imagination.local.mk-labs.cloud 25565 # Or via the ClusterIP directly kubectl get svc -n minecraft nc -zv 25565 ``` **External test (after UniFi port forward + DNS configured):** - Open Minecraft Java Edition - Add server: `journey-into-imagination.mk-labs.cloud` - Should connect and show MOTD: "Journey Into Imagination" --- ## Plugin Details ### SleepMost v5.6.2 - **Source:** https://github.com/mrgeneralq/sleep-most - **Download:** https://github.com/mrgeneralq/sleep-most/releases/download/v5.6.2/SleepMost-5.6.2.jar - **Compatibility:** PaperMC 1.8 through 1.21.x (use 5.6.2 for 1.21.x; 5.7.0+ drops backward compat) - **Configuration:** Lives at `/data/plugins/SleepMost/config.yml` after first boot Default behavior: configurable percentage of online players must sleep to skip night. To tune (exec into the pod after first start): ```bash kubectl exec -n minecraft -it deployment/papermc -- bash cat /data/plugins/SleepMost/config.yml # Edit as needed, then /sleepmost reload in rcon ``` > **Geyser compatibility note:** SleepMost 5.x does NOT require Geyser to function. > If you add Geyser later for Bedrock crossplay, SleepMost is compatible. --- ## Day 2 Operations ### Enabling the Whitelist When ready to lock the server to approved players: 1. Edit `cluster/applications/minecraft/configmap.yaml`: ```yaml WHITE_LIST: "true" ENFORCE_WHITELIST: "true" ``` 2. Add players via RCON (live, no restart needed): ```bash kubectl exec -n minecraft -it deployment/papermc -- rcon-cli whitelist add whitelist list ``` 3. Commit the ConfigMap change for GitOps consistency. Note: the Deployment will restart when the ConfigMap changes (env var reload). Players will be briefly disconnected — plan accordingly. ### Console / RCON Access ```bash # Interactive RCON (from inside the pod) kubectl exec -n minecraft -it deployment/papermc -- rcon-cli # One-shot command kubectl exec -n minecraft -it deployment/papermc -- rcon-cli "list" kubectl exec -n minecraft -it deployment/papermc -- rcon-cli "say Server restarting in 5 minutes" ``` ### Upgrading PaperMC Version 1. Check PaperMC API: `curl -sA 'Mozilla/5.0' https://fill.papermc.io/v3/projects/paper/versions | head` 2. Update `VERSION` in `deployment.yaml` env vars and the comment header 3. Update image tag if a new `itzg/minecraft-server` release is out 4. Verify SleepMost compatibility with the new version 5. Commit, push — ArgoCD handles the rolling restart (Recreate strategy) ### Expanding PVC Storage Pure Storage CSI supports online volume expansion: ```bash kubectl patch pvc papermc-world-data -n minecraft \ -p '{"spec":{"resources":{"requests":{"storage":"100Gi"}}}}' ``` No pod restart required. ### Backups No automated backup is configured in this skeleton. Recommended Day 2 addition: CronJob that runs `rcon-cli save-all` + `rcon-cli save-off`, copies `/data/world*` to a separate PVC or object store, then `rcon-cli save-on`. --- ## Troubleshooting | Symptom | Check | |---------|-------| | Pod stuck in `Init` / slow start | `kubectl logs -n minecraft -l app.kubernetes.io/component=papermc` — jar download may be slow | | Port 25565 connection refused externally | Verify UniFi port forward is active; `kubectl get svc -n minecraft` shows correct ClusterIP | | Players can't authenticate | `ONLINE_MODE=true` requires Mojang auth; check player has a valid Java account | | World data lost after pod restart | Verify PVC is `Bound`; check `pure-block` StorageClass is healthy | | EULA error in logs | `EULA=TRUE` is set in deployment.yaml — this should not occur; check env var injection | --- ## File Manifest Summary | File | Purpose | |------|---------| | `namespace.yaml` | `minecraft` namespace | | `application.yaml` | ArgoCD Application (sync-wave 20) | | `pvc.yaml` | 50Gi pure-block PVC for world data | | `secret.yaml` | RCON password (⚠️ placeholder — update before deploy) | | `configmap.yaml` | server.properties overrides + SleepMost plugin download | | `deployment.yaml` | PaperMC Deployment (Recreate strategy, resource limits set) | | `service.yaml` | ClusterIP Service named `journey-into-imagination` | | `../../../platform/ingress-nginx/values.yaml` | Added `tcp: 25565` forwarding entry |