Helm values reference
Production-facing chart settings, accepted types, defaults, and the operational effect of each value.
Use helm template or helm diff to preview your values before applying them to production. Secret values should always be referenced from Kubernetes Secrets, never committed to version control.
Releases up to and including v0.3.0 are published under ghcr.io/valgulnecron, so this page uses that registry; releases after v0.3.0 move to ghcr.io/gameplanepanel.
Core and image settings
Configure container images, registry access, and fundamental cluster behavior.
| Key | Type | Default | Description |
|---|---|---|---|
image.registry |
string | ghcr.io/valgulnecron/gameplane |
Container registry where component images are published. Override to point to a private mirror for air-gapped installs. |
image.tag |
string | (empty — uses chart’s appVersion) |
Image tag for all components. Empty defaults to the chart version (e.g., chart v0.2.0 pulls v0.2.0 images). Set to "edge" to track rolling images published on every master push. |
image.pullPolicy |
enum | IfNotPresent |
Kubernetes image pull behavior: IfNotPresent, Always, or Never. Use Always for :edge tags; use IfNotPresent for production release tags. |
image.pullSecrets |
list | [] |
Array of image pull Secret names if your registry requires authentication. Example: [{name: myregistry}] |
gamesNamespace |
string | gameplane-games |
Kubernetes namespace where the operator creates GameServer pods. Does not need to exist at install time — the operator creates it. |
Operator configuration
Control operator behavior, logging, high availability, and module storage.
| Key | Type | Default | Description |
|---|---|---|---|
operator.replicas |
integer | 1 |
Operator Deployment replicas. Use 1 for single-cluster installs; set higher for HA with leaderElect: true. |
operator.logLevel |
enum | info |
Zap log level: debug, info, or error (warn not supported by zap’s --zap-log-level). |
operator.leaderElect |
boolean | true |
Enable leader election for HA deployments. Set to false for single-replica or resource-constrained clusters to avoid missed lease renewals causing crash loops. |
operator.addressManager |
enum | none |
Load-balancer address manager: metallb, cilium, or none. Controls how the operator expresses GameServer pool/address preferences on the Service. |
operator.metalLBNamespace |
string | metallb-system |
Namespace where MetalLB’s IPAddressPool resources live (consulted only when addressManager: metallb). |
Networking and ingress
Configure external access, TLS, and dashboard routing.
| Key | Type | Default | Description |
|---|---|---|---|
ingress.enabled |
boolean | true |
Create an Ingress for the dashboard and API. Disable only for headless/API-only installs. |
ingress.className |
string | nginx |
Ingress controller class, e.g., nginx, istio, or your cloud provider’s controller. |
ingress.host |
hostname | gameplane.local |
DNS hostname presented to users and OIDC providers. Must be reachable and match OIDC redirect URLs. |
ingress.tls |
boolean | true |
Enable HTTPS. Session cookies and login credentials require TLS in production. Set to false only for throwaway dev clusters; provide a cert via cert-manager annotations or a pre-created gameplane-tls Secret. |
web.enabled |
boolean | true |
Deploy the web/dashboard frontend. Disable only for API-only installs; the ingress then points directly at the API. |
Authentication
Configure local accounts and OIDC single sign-on. Local password-based accounts are always available; OIDC is optional.
| Key | Type | Default | Description |
|---|---|---|---|
api.oidc.enabled |
boolean | false |
Enable OIDC identity provider integration for single sign-on. When disabled, only local password authentication is available. |
api.oidc.issuer |
string | (required if enabled) | OIDC provider issuer URL (e.g., https://accounts.google.com, https://keycloak.example.com/realms/gameplane). |
api.oidc.clientID |
string | (required if enabled) | OAuth 2.0 Client ID issued by your OIDC provider. |
api.oidc.clientSecretRef |
object | {name: gameplane-oidc, key: clientSecret} |
Reference to a Kubernetes Secret holding the OAuth client secret. Create the Secret first: kubectl create secret generic gameplane-oidc --from-literal=clientSecret=<your-secret>. |
api.oidc.redirectURL |
string | (empty) | Explicit OAuth redirect URL. When empty, derived from ingress.host (e.g., https://gameplane.local/auth/oidc/callback). Override only if your ingress URL differs from the redirect URL your OIDC provider expects. |
The following OIDC fields enable install-time role mapping and customization of the login UI. They are not available in v0.2.0-beta.8 — upgrade to v0.3.0 to use them.
| Key | Type | Default | Description |
|---|---|---|---|
api.oidc.displayName |
string | "Single sign-on" |
Label for the OIDC login button shown on the login screen (before authentication). |
api.oidc.groupsClaim |
string | (empty — defaults to “groups”) | OIDC claim name containing group or role memberships. Examples: groups, roles, membership, department. When empty, the groups claim is read. This only chooses which claim is read; it does not turn group-based role mapping on or off (roleMappings does). Mapping is active whenever at least one roleMappings list is non-empty or an admin has set a mapping override in the dashboard. With neither, new OIDC users get viewer and existing users’ roles are never re-evaluated. |
api.oidc.defaultRole |
string | (empty — defaults to “viewer”) | Default dashboard role for new OIDC users when no group matches a configured mapping. Accepted: viewer, operator, admin, deny (deny = reject login). When empty, defaults to “viewer”. |
api.oidc.roleMappings |
object | {admin: [], operator: [], viewer: []} |
Map OIDC groups to dashboard roles at install/upgrade time. Example: admin: ["gameplane-admins", "ops-team"]. DB-managed role overrides (set via dashboard) take precedence and survive Helm upgrades. |
API replicas and trusted proxies
| Key | Type | Default | Description |
|---|---|---|---|
api.replicas |
integer | 1 |
Keep at 1. SQLite is single-writer on a ReadWriteOnce volume; with db.driver: postgres (experimental) the user-management lock and audit hash chain are still per-process. |
api.trustedProxies |
string | loopback + RFC 1918 + link-local + ULA ranges | Comma-separated CIDRs of trusted reverse proxies. The API reads X-Forwarded-For only when the TCP peer is inside one of these networks; any other peer is itself the client. Used for rate limiting and audit records. The default suits in-cluster ingress. If dashboard users connect from a private network and per-client limits matter for them, narrow it to the ranges your proxies run in (for example the pod CIDR). For direct exposure without an ingress, set it to "". |
CRD auto-apply
helm upgrade never updates CRDs, so the chart applies them with a hook. See CRD updates on upgrade.
| Key | Type | Default | Description |
|---|---|---|---|
crds.autoApply.enabled |
boolean | true |
Run a pre-install/pre-upgrade hook that applies the chart’s CRDs with kubectl apply --server-side. It runs on every upgrade; from v0.3.0 it also runs on an install over CRDs that an earlier, uninstalled release left behind. |
crds.autoApply.image |
string | registry.k8s.io/kubectl:v1.36.3 |
kubectl image the hook runs. Retag to a private mirror for air-gapped installs. |
crds.autoApply.pullPolicy |
enum | IfNotPresent |
Pull policy for the hook image, separate from image.pullPolicy so tracking :edge does not re-pull it on every upgrade. |
Agent mTLS and S3 audit sink
| Key | Type | Default | Description |
|---|---|---|---|
api.agentMTLS.caSecretRef.name |
string | gameplane-agent-ca |
Secret holding the CA for in-pod agent mTLS (ca.crt, ca.key). By default the chart generates it at install and reuses it on upgrade. From v0.3.0 you can bring your own: pre-create the Secret in the release namespace and set its name, and the chart does not generate it. Data key names are fixed. A referenced Secret that does not exist then fails a live install or upgrade, and rotating a custom Secret rolls the API and operator. |
api.agentMTLS.clientCertRef.name |
string | gameplane-agent-client |
Secret holding the API/operator client certificate (tls.crt, tls.key). Same rules as above. |
api.audit.s3.endpoint |
string | (empty) | S3-compatible endpoint host:port (for example minio:9000). Leave empty to disable the S3 sink. |
api.audit.s3.bucket |
string | (empty) | Bucket name (required when endpoint is set). |
api.audit.s3.prefix |
string | (empty) | Object key prefix, for example gameplane-audit. Empty = bucket root. |
api.audit.s3.region |
string | (empty) | S3 region. Empty defaults to us-east-1. |
api.audit.s3.insecure |
boolean | false |
Use plain HTTP instead of HTTPS (no TLS at all), for local S3-compatible endpoints. TLS verification is never skipped. |
api.audit.s3.credentialsSecretRef |
object | (empty name) | Secret holding the S3 credentials. Leave name empty to disable the S3 sink. |
API database and persistence
Configure data persistence, audit logging, and telemetry.
| Key | Type | Default | Description |
|---|---|---|---|
api.db.driver |
enum | sqlite |
Database backend: sqlite (built-in, production-tested) or postgres (external server, experimental). The published api image is built without PostgreSQL, so postgres needs an image rebuilt with -tags postgres; it is not yet covered by e2e or upgrade tests, and api.replicas must stay 1 with either driver. |
api.db.dsn |
string | file:/data/gameplane.db?_pragma=journal_mode(WAL) |
Database connection string. SQLite path (only when driver: sqlite). For PostgreSQL, use a connection string like postgres://gameplane:***@postgres/gameplane?sslmode=require. |
api.storage.size |
string | 2Gi |
Size of the SQLite PersistentVolumeClaim (only when db.driver: sqlite). Adjust based on audit log retention and historical data. |
api.storage.storageClassName |
string | (empty) | Storage class for the SQLite PVC. When empty, uses the cluster’s default storage class. |
api.storage.existingClaim |
string | (empty) | Coming in v0.3.0 — Use an existing PersistentVolumeClaim instead of creating one. Leave empty to create a new PVC. When migrating, ensure the existing claim has the helm.sh/resource-policy: keep annotation. |
api.audit.retentionDays |
integer | 0 |
Audit event retention in days. 0 keeps all events indefinitely; set a positive number to prune older records daily. |
api.audit.webhook.url |
string | (empty) | Outbound webhook URL for audit events. The API POSTs each event as JSON (best-effort, non-blocking). Point it at a log aggregator, SIEM, or the bundled audit-syslog-bridge. |
Observability and monitoring
Configure logging, metrics, and alerting sinks.
| Key | Type | Default | Description |
|---|---|---|---|
api.audit.stdout |
boolean | false |
Mirror audit events to stdout as structured JSON lines, for capture by cluster log aggregators (Loki, ELK, CloudWatch). Events always land in the database regardless. |
api.audit.syslogBridge.enabled |
boolean | false |
Deploy the bundled RFC 5424 syslog bridge (audit-syslog-bridge image). When enabled and webhook.url is unset, the API auto-wires to it. |
api.audit.syslogBridge.syslog.addr |
string | (empty — required if enabled) | Syslog collector address in host:port format, e.g., syslog.example:514. |
api.audit.syslogBridge.syslog.network |
enum | tcp |
Syslog transport: tcp (recommended for reliability) or udp (no delivery confirmation). |
api.telemetry.enabled |
boolean | true |
Hard on/off for usage telemetry. false means the API never sends telemetry, whatever the admin switches say, and no first-login notice is shown. Use it for air-gapped and privacy-sensitive clusters. |
api.telemetry.endpoint |
string | (empty) | Where reports go. Empty means the project’s default provider, https://telemetry.gameplane.net/ingest. Set a URL such as https://telemetry.example.com/ingest to send reports to your own receiver instead; it replaces the default and disables the bundled receiver auto-wiring. |
serviceMonitors.enabled |
boolean | false |
Create Prometheus Operator ServiceMonitor resources for scraping Gameplane metrics. Requires Prometheus Operator to be installed in your cluster. |
Storage and modules
Configure persistent volumes and local module sources.
| Key | Type | Default | Description |
|---|---|---|---|
operator.localModules.existingClaim |
string | (empty) | PersistentVolumeClaim for local module bundles (homebrew/homelab pattern: drop module directories on disk and they appear in the catalog). Provide exactly one of existingClaim or hostPath. |
operator.localModules.hostPath |
string | (empty) | Host path for local module bundles (node-local storage). Use only on single-node clusters; requires nodeSelector to pin the operator to that node. |
Cluster operations
Enable credential-minting and node/kubeconfig management.
| Key | Type | Default | Description |
|---|---|---|---|
clusterOps.enabled |
boolean | false |
Enable cluster credential operations: bootstrap tokens (Add node) and short-lived kubeconfigs (Download kubeconfig). Grants powerful kube-system + CSR-approval RBAC. |
clusterOps.externalAddress |
string | (empty) | External API server address in join-token commands and downloaded kubeconfigs, e.g., "1.2.3.4:6443" or "https://k8s.example.com:6443". When empty, uses the in-cluster address (typically unreachable from outside). |
Network policies
Configure default-deny policies for game pods and backups.
| Key | Type | Default | Description |
|---|---|---|---|
networkPolicies.enabled |
boolean | true |
Create default-deny NetworkPolicies in gamesNamespace. Disable only when using a service mesh that handles policies or in non-networked environments. |
networkPolicies.gameEgress.enabled |
boolean | true |
Allow game pods outbound access to the public internet (HTTP/HTTPS) for downloads. Private ranges (RFC 1918 + link-local) are always blocked to prevent SSRF. |
networkPolicies.backupEgress.enabled |
boolean | true |
Allow backup/restore Job pods to reach external restic repositories (S3, REST, SFTP, etc.). Covers HTTPS and SSH ports by default. |
networkPolicies.gameIngress.enabled |
boolean | true |
Create per-GameServer Ingress NetworkPolicies allowing player traffic from fromCIDRs. Operator configures the exact advertised ports per server. |
networkPolicies.gameIngress.fromCIDRs |
list | ["0.0.0.0/0"] |
CIDR ranges allowed to reach game ports. Set to a LAN range (e.g., ["192.168.1.0/24"]) to restrict access. Cannot be an empty list; set enabled: false instead. |
networkPolicies.apiServerCIDRs |
list | [] (falls back to RFC 1918 + link-local) |
CIDRs holding the kube-apiserver endpoints the agent sidecar reaches for its status heartbeat, on TCP 443 and 6443. Set it to narrow that egress to your API endpoints, or when they sit outside those ranges. |
These network capture values are not available in v0.2.0-beta.8.
| Key | Type | Default | Description |
|---|---|---|---|
capture.enabled |
boolean | false |
Let admins opt individual GameServers into packet capture. Capture is always opt-in per server; a server that does not opt in gets no capture sidecar. |
capture.defaultMaxDurationSeconds |
integer | 300 |
Default maximum runtime per network capture (5 minutes). Captures stop automatically at the limit. |
capture.defaultMaxSizeBytes |
integer | 943718400 |
Default maximum capture size (900 MiB), kept under the 1 GiB emptyDir limit backing the capture volume. Captures stop automatically at the limit. |
Advanced: MCP and telemetry
Configure optional integrations.
| Key | Type | Default | Description |
|---|---|---|---|
mcpServer.enabled |
boolean | false |
Deploy a read-only Model Context Protocol (MCP) server for AI assistant integrations. It reads 7 Gameplane CRDs (not Cluster, nor NetworkCapture, the ninth CRD added in v0.3.0), plus Pods, Events and pod logs. Read-only, stdio JSON-RPC only (no network port). See mcp-server/README.md. |
api.telemetry.receiver.enabled |
boolean | false |
Deploy the bundled telemetry receiver (telemetry-receiver image). When enabled and endpoint is unset, the API auto-wires to it, so reports stay in your cluster. Admin switches in the dashboard control whether anything is sent. |
api.telemetry.receiver.persistence.enabled |
boolean | true |
Keep the receiver’s aggregates in a PVC at /data (persistence.size, default 1Gi). With false an emptyDir is used and everything is lost on restart. While on, receiver.replicas must stay 1. |
api.telemetry.receiver.dashboard.tokenSecretRef.name |
string | (empty) | Secret holding the receiver’s dashboard token (key token, at least 32 characters). Setting it starts the private dashboard listener on port 8081; reach it with kubectl port-forward. |
api.telemetry.receiver.pepperSecretRef.name |
string | (empty) | Optional Secret (key pepper) with the HMAC pepper for install IDs. Empty means the receiver generates and stores one. |
api.telemetry.receiver.publicSummary.enabled |
boolean | false |
Serve five public aggregate counters on GET /v1/summary. |
api.telemetry.receiver.retentionDays |
integer | 730 |
Daily aggregate retention (minimum 365). |
api.telemetry.receiver.activityExpiryDays |
integer | 90 |
Per-install activity record expiry (minimum 31). |
api.telemetry.receiver.ingestPow.enabled |
boolean | false |
Require proof-of-work on report ingestion (tuned by targetPerMinute 60, minBits 0, maxBits 22; maxBits at most 26). Meant for a public provider. |
To run a receiver for other installs, see Run a telemetry provider on Kubernetes.
Example: minimal production install
image:
tag: "0.2.0"
ingress:
enabled: true
host: gameplane.example.com
tls: true
api:
db:
driver: sqlite
storage:
size: 2Gi
oidc:
enabled: true
issuer: https://keycloak.example.com/realms/gameplane
clientID: gameplane-app
clientSecretRef:
name: gameplane-oidc
key: clientSecret
networkPolicies:
enabled: true
gameEgress:
enabled: true
gameIngress:
enabled: true
fromCIDRs:
- 0.0.0.0/0
See the full Helm chart values.yaml for all options and detailed comments.