Skip to content

Configuration Guide

This guide covers common configuration patterns and best practices for running Minecraft servers with mc-operator.

Memory is the most important resource to size correctly. Minecraft is memory-intensive, and undersized heaps cause lag.

Minimum for a small private server (1–5 players):

jvm:
initialMemory: "1G"
maxMemory: "2G"
resources:
memoryRequest: "2Gi"
memoryLimit: "2Gi" # At least maxMemory + 512Mi overhead

Production Paper server (10–50 players):

jvm:
initialMemory: "2G"
maxMemory: "4G"
extraJvmArgs:
- "-XX:+UseG1GC"
- "-XX:G1HeapRegionSize=4M"
- "-XX:+UnlockExperimentalVMOptions"
- "-XX:MaxGCPauseMillis=200"
- "-XX:+DisableExplicitGC"
- "-XX:+AlwaysPreTouch"
resources:
cpuRequest: "1"
cpuLimit: "4"
memoryRequest: "4500Mi" # maxMemory + ~500Mi JVM overhead
memoryLimit: "4500Mi"
storage:
enabled: true
size: "20Gi" # Generous for mods/world growth
storageClassName: "fast-ssd" # Use a fast SSD class if available
deleteWithServer: false # Always retain data (the default)
Server typeRecommended sizeNotes
Private/small10–20 GiVanilla worlds grow slowly
Semi-public Paper20–50 GiPlugins add data
Large/public50 Gi+Allow room for world growth

By default, the PVC is retained when the MinecraftServer is deleted. This is the right default for production.

If you delete a MinecraftServer and want to restore data later, the PVC remains in the namespace:

Terminal window
kubectl get pvc -n minecraft
# data-my-server-0 Bound ...

You can reconnect it by recreating the server with the same name — the StatefulSet will reattach to data-<server-name>-0.

For servers accessed only within the cluster or via kubectl port-forward:

service:
type: ClusterIP

For home labs or simple external access:

service:
type: NodePort
nodePort: 30565 # Optional; auto-assigned if omitted

For cloud environments with external load balancers:

service:
type: LoadBalancer
annotations:
# AWS NLB example
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

The server IP appears in status.endpoint.host once the load balancer is provisioned.

Set replicas: 0 to pause a server without losing world data:

spec:
replicas: 0

The StatefulSet scales to zero, the pod stops, but the PVC remains intact. Resume by setting replicas: 1.

Online mode (default) authenticates players with Mojang’s servers. Set onlineMode: false for:

  • LAN/private servers with custom auth
  • Development/testing
properties:
whitelistEnabled: true
whitelist:
- "PlayerOne"
- "PlayerTwo"

Update the resource to add/remove players. The operator reconciles the running server accordingly.

properties:
ops:
- "AdminPlayer"

Ops have full in-game admin access. Changes are applied when the server reads the ops environment variable on startup.

For properties not directly exposed in the spec, use additionalProperties:

properties:
additionalProperties:
enable-command-block: "true"
max-world-size: "10000"
spawn-monsters: "true"
max-tick-time: "60000"

These are appended to server.properties and override any derived values from the spec.

To use your own Docker image (e.g. with pre-installed plugins):

spec:
image: "registry.example.com/my-minecraft:1.20.4"
imagePullPolicy: Always

The operator skips the distribution-type logic and uses your image directly.

properties:
levelSeed: "12345" # Reproducible seed
levelType: DEFAULT # DEFAULT | FLAT | LARGBIOMES (no E, itzg convention) | AMPLIFIED
levelName: "my-world" # Directory name inside /data
generateStructures: true
allowNether: true

The MinecraftServerCluster resource manages multiple backend servers behind a Velocity proxy. This section covers common configuration patterns for clusters.

The proxy is the player-facing entry point. Configure it the same way you would a standalone server’s service:

LoadBalancer (cloud environments):

proxy:
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"

NodePort (home labs):

proxy:
service:
type: NodePort
nodePort: 30577

ClusterIP (internal access only):

proxy:
service:
type: ClusterIP

The proxy endpoint appears in status.proxyEndpoint once provisioned.

Player forwarding controls how the proxy passes player identity (IP, UUID, skin) to backend servers.

ModeDescriptionRecommended for
ModernVelocity native forwarding with shared secretPaper backends (recommended)
BungeeGuardBungeeGuard-style token verificationServers with BungeeGuard plugin
LegacyBungeeCord-style IP forwarding (less secure)Legacy setups
NoneNo forwardingTesting only

The tryOrder field controls which backend server a player connects to first. Values are zero-based indices of the backend servers:

proxy:
tryOrder: [0, 2, 1] # Try server 0 first, then 2, then 1

When omitted, servers are tried in ascending index order (0, 1, 2, ...). This is suitable for most load-balancing scenarios.

Static mode — fixed number of servers:

scaling:
mode: Static
replicas: 3

Dynamic mode — auto-scale between bounds (framework ready, metric collection pending):

scaling:
mode: Dynamic
minReplicas: 1
maxReplicas: 5
policy:
metric: PlayerCount
targetPercentage: 75