Homelab
Minecraft Hardening
Hardening Minecraft: Encrypted Storage, NetworkPolicy, and Security
Overview
This article hardens the Minecraft server by migrating to encrypted storage, adding NetworkPolicy, and pinning Helm versions. Game servers are internet-exposed via playit.gg - hardening limits the blast radius if compromised.
| Tip: | Having trouble? See v1.8.0 for what your setup should look like after completing this article. |
Before You Begin
Prerequisites
- Longhorn Hardening completed
What We're Hardening
| Component | Before | After |
|---|---|---|
| Storage | Unencrypted longhorn | Encrypted longhorn-encrypted |
| NetworkPolicy | None | Egress limited |
| Helm chart | Floating version | Pinned version |
Why These Controls
Encrypted Storage: World data and player information protected at rest. Physical disk theft or node compromise no longer exposes plaintext data.
NetworkPolicy: Minecraft needs to reach the internet for player authentication and playit.gg tunnel. We can still block access to other VLANs (Network, Drive).
Helm Pinning: Ensures reproducible deployments without surprise breaking changes.
How Longhorn Encryption Works
Longhorn uses LUKS (Linux Unified Key Setup) for block-level encryption1. You cannot convert existing unencrypted volumes - the block format differs. Instead, we backup the data, create a new encrypted volume, and restore2.
Backup World Data
Create a tar backup of the entire data directory (/data mount).
# Get pod name
POD=$(kubectl get pod -n minecraft -o jsonpath='{.items[0].metadata.name}')
# Create backup inside container
kubectl exec -n minecraft $POD -- tar czf /tmp/minecraft-backup.tar.gz -C /data .
# Copy to local machine
kubectl cp minecraft/$POD:/tmp/minecraft-backup.tar.gz ./minecraft-backup-$(date +%Y%m%d).tar.gz Verify the backup:
# Check file exists and size
ls -lh ./minecraft-backup-$(date +%Y%m%d).tar.gz
# List contents
tar tzf ./minecraft-backup-$(date +%Y%m%d).tar.gz | head -20 Expected: File is several hundred MB, contents show world folders, server.properties, etc.
Harden Minecraft
Check Current Version
# Find current chart version to pin
helm list -n minecraft Note the chart version (e.g., minecraft-5.1.1) - this is what you'll pin.
PVC
Update to use the encrypted volume.
k8s/apps/minecraft/pvc.yaml:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: minecraft-data-encrypted # CHANGE from minecraft-data
namespace: minecraft
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn-encrypted # CHANGE from longhorn
resources:
requests:
storage: 20Gi HelmRelease
k8s/apps/minecraft/helmrelease.yaml:
# ... existing HelmRepository ...
---
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: minecraft
namespace: minecraft
spec:
interval: 30m
chart:
spec:
chart: minecraft
version: "5.1.1" # PIN to current version
sourceRef:
kind: HelmRepository
name: minecraft
# ... existing install, upgrade ...
values:
# ... existing values ...
persistence:
dataDir:
enabled: true
existingClaim: minecraft-data-encrypted # CHANGE from minecraft-data NetworkPolicy
k8s/apps/minecraft/networkpolicy.yaml:
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: minecraft
namespace: minecraft
spec:
podSelector: {}
policyTypes:
- Egress
egress:
# DNS resolution
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
# Internet (Mojang auth, playit.gg, plugin downloads)
# Block private ranges
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16 Kustomization
k8s/apps/minecraft/kustomization.yaml:
# ... existing header ...
resources:
- namespace.yaml
- pvc.yaml
- secret.sops.yaml
- helmrelease.yaml
- networkpolicy.yaml # ADD Deploy Changes
Commit Changes
git add k8s/apps/minecraft/
git commit -m "feat(minecraft): harden with encrypted storage and NetworkPolicy"
git push Reconcile
flux reconcile source git flux-system
flux reconcile kustomization sync Minecraft will start with an empty encrypted volume.
Restore Data
Copy and extract the backup to the running pod:
# Get pod name
POD=$(kubectl get pod -n minecraft -o jsonpath='{.items[0].metadata.name}')
# Copy backup to pod
kubectl cp ./minecraft-backup-*.tar.gz minecraft/$POD:/tmp/backup.tar.gz
# Extract backup (clears existing data first)
kubectl exec -n minecraft $POD -- sh -c "rm -rf /data/* && tar xzf /tmp/backup.tar.gz -C /data" Restart to load restored data:
kubectl rollout restart deploy -n minecraft minecraft Verify Hardening
Verify Pod Running
kubectl get pods -n minecraft Expected: Pod shows Running with all containers ready.
Verify Encrypted PVC
Confirm the pod is using the encrypted volume:
kubectl get pod -n minecraft -l app=minecraft -o jsonpath='{.items[0].spec.volumes[?(@.name=="datadir")].persistentVolumeClaim.claimName}' Expected: minecraft-data-encrypted
Verify NetworkPolicy
kubectl get networkpolicy -n minecraft Expected: minecraft policy listed.
Verify World Loads
Check logs for successful startup:
kubectl logs -n minecraft deploy/minecraft --tail=20 Expected: World loaded, no errors. Login to the server to confirm player data and world are intact.
Clean Up Old Volume
After verifying Minecraft works:
# Remove old unencrypted volume
kubectl delete pvc -n minecraft minecraft-data Next Steps
With Minecraft hardened, continue with Factorio hardening.
See: Factorio Hardening
Resources
Footnotes
Longhorn, "Volume Encryption," longhorn.io. Accessed: Feb. 28, 2026. [Online]. Available: https://longhorn.io/docs/1.9.2/advanced-resources/security/volume-encryption/ ↩
Longhorn, "Encrypt existing volume," github.com. Accessed: Feb. 28, 2026. [Online]. Available: https://github.com/longhorn/longhorn/issues/9502 ↩