Kubernetes
Kasm Workspaces core services can be deployed to Kubernetes using the open-source Kasm Helm chart, which will be Generally Available as of Kasm version 1.19.0 (the developer preview is available using chart version 1.1190.0).
Not sure which components you need? The Helm chart does not cover everything — what you provision alongside it depends on your session types (Docker containers, RDP, VNC) and whether you are running multiple zones. See Kubernetes Deployment Options for a full breakdown before you start.
Quick Start
If you have a running Kubernetes cluster and just want to get Kasm up quickly, here are the minimal steps. See Installation below for the full walkthrough with all options.
Prerequisites: Kubernetes 1.24+, Helm 3.18.x+, a domain name, and a TLS certificate or cert-manager.
Create a namespace and install your TLS certificate as a Kubernetes secret (see Configure TLS Certificates for the available methods), then create a minimal values file:
# my-values.yaml
publicAddr: kasm.example.com
certificate:
secretName: {CERTIFICATE_SECRET_NAME}
Install the chart:
kubectl create namespace {NAMESPACE}
helm install {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \
--version 1.1190.0 -n {NAMESPACE} -f my-values.yaml
Wait for pods to be ready, then retrieve the admin password:
kubectl get pods -n {NAMESPACE} --watch
kubectl get secret --namespace {NAMESPACE} {RELEASE_NAME}-secrets \
-o jsonpath="{.data.admin-password}" | base64 -d; echo
Point your DNS for publicAddr to the address shown by kubectl get ingress -n {NAMESPACE} and log in at https://{publicAddr} with admin@kasm.local.
After a successful install, disable the one-time initialization jobs before any future helm upgrade:
dbManagement:
initialize: false
upgrade:
enable: false
Architecture Overview
The Kasm Helm chart deploys the core control-plane services inside a Kubernetes cluster. Containerized desktop and application sessions are not run inside the cluster; they are hosted on external Docker Agent servers that you provision separately (either as static agents or via auto scaling). RDP sessions are routed to external Windows or Linux hosts running RDP servers.
The following diagram shows the main components and how traffic flows between them:
Multi-Zone Architecture
Kasm supports multiple deployment zones, which are commonly used to serve users across geographic regions but can also be used to segment groups of users or isolate different workload types across separate pools of compute resources. In a multi-zone deployment, each zone runs its own set of API-layer and proxy-layer services. Additional zones only receive the App role from the Helm chart — their proxy layer is deployed separately using the multi-zone proxy instructions.
Key points to note:
- Agents are not included in the Helm chart. The Kasm Agent, which hosts containerized sessions (desktops, browsers, apps), must be deployed on separate Docker hosts outside the cluster. You can add agents manually as static servers or configure auto scaling to provision them on demand.
- RDP over port 3389 requires extra configuration. Standard Kubernetes Ingress only handles HTTP/HTTPS traffic on port 443. By default, thick-client RDP connections route through the RDP HTTPS Gateway on port 443, which works out of the box. To support direct RDP connections on port 3389, you must expose the RDP Gateway via a NodePort or LoadBalancer service. See Direct RDP Connections on Kubernetes for setup instructions.
- Ingress acts as the external load balancer. All browser and HTTPS-based client traffic enters the cluster through the Ingress controller, which should be backed by a cloud load balancer or similar in production.
Prerequisites
Before installing, ensure you have:
- Kubernetes 1.24+
- Helm 3.18.x+: install from helm.sh
kubectlconfigured and connected to your target cluster- A default StorageClass (or explicit
storageClassNamein your values): required for the built-in PostgreSQL database PVC. Not needed if using a standalone external database. Runkubectl get storageclassto verify a default is set. - A domain name with DNS control, to use as the
publicAddrfor Kasm - A TLS certificate or cert-manager installed in your cluster. See Configure TLS Certificates for Kasm on Kubernetes
Note that Helm chart versions are based upon Kasm versions, for example chart version 1.1190.0 corresponds to Kasm version 1.19.0, with the minor (middle) number corresponding to the officially supported Kasm version.
If you are deploying on a managed Kubernetes platform such as Amazon EKS, Google GKE, or Azure AKS, ensure that your cloud provider's CLI tools are installed and configured (e.g., aws, gcloud, az) and that your kubectl context is pointed at the correct cluster. Refer to your provider's documentation for cluster setup and authentication:
Cloud-hosted deployments may also benefit from using a managed database service (e.g., Amazon RDS, Cloud SQL, Azure Database for PostgreSQL) instead of the built-in database. See the chart's database values for external database configuration.
Installation
If you are using a developer preview version of the Kasm Helm chart, be aware that no clean migration path to future updates is guaranteed. Review the Developer Preview Builds warnings before proceeding.
0. Verify Your Cluster
Before proceeding, confirm that your cluster is reachable and that nodes are healthy:
kubectl cluster-info
kubectl get nodes
All nodes should show a Ready status. If not, resolve any cluster issues before continuing.
1. Create the Namespace
kubectl create namespace {NAMESPACE}
2. Configure TLS
Install your TLS certificate into the namespace as a Kubernetes secret. See Configure TLS Certificates for Kasm on Kubernetes for the available methods.
Note the secret name you create, as you will need it as {CERTIFICATE_SECRET_NAME} in the next step.
3. Create Your Values File
Create a my-values.yaml file. At minimum, include:
publicAddr: kasm.example.com
certificate:
secretName: {CERTIFICATE_SECRET_NAME}
Refer to the chart definition for a list of all available configuration options (documented in /charts/kasm/values.yaml).
Customizing Component Image Tags
By default, each component uses rolling image tags which pull the latest at time of deployment. To pin a specific build, override the tag field for each component in your values file:
components:
proxy:
image:
tag: 1.19.0-rolling-20260215
api:
image:
tag: 1.19.0-rolling-20260215
manager:
image:
tag: 1.19.0-rolling-20260215
guac:
image:
tag: 1.19.0-rolling-20260215
rdpGateway:
image:
tag: 1.19.0-rolling-20260215
rdpHttpsGateway:
image:
tag: 1.19.0-rolling-20260215
database:
image:
tag: 1.19.0-rolling-20260215
You can override any subset of components independently; omitted components continue to use the chart's default tag.
To apply tag changes to a running deployment after initial install, see Applying Changes to a Running Instance below.
deploymentSize Variable ValuedeploymentSize controls resource allocation across all Kasm components.
Three values are supported: small, medium, and large. Each value maps to a preset that sets CPU and memory requests/limits and scales the replica count for each component (1/2/3 respectively). The database StatefulSet always runs as a single replica regardless of size.
Choose small for evaluation, single-node, or low-concurrency deployments. Use medium or large for production environments where session throughput and availability matter. Any component's resources or replica count can be overridden individually via components.<name>.resources and components.<name>.replicas when the preset does not match your workload.
4. (Optional) Pre-Create Kasm Secrets
By default, the Helm chart auto-generates random credentials during installation and stores them in a Kubernetes secret. If you prefer to use your own credentials, create the secret before installing the chart.
The secret must be named {RELEASE_NAME}-secrets, where {RELEASE_NAME} is the name you will pass to helm install in the next step. For example, if you plan to run helm install kasm ..., the secret must be named kasm-secrets.
apiVersion: v1
kind: Secret
metadata:
name: {RELEASE_NAME}-secrets
namespace: {NAMESPACE}
type: Opaque
data:
admin-password: "<base64-encoded value>"
user-password: "<base64-encoded value>"
db-password: "<base64-encoded value>"
manager-token: "<base64-encoded value>"
service-token: "<base64-encoded value>"
Apply it with:
kubectl apply -f kasm-secrets.yaml
To base64-encode a value: echo -n 'my-password' | base64
If the chart finds an existing secret with this name during installation, it will use those values instead of generating new ones.
5. Install the Chart
The Kasm Helm chart is available as an OCI Helm chart and from a classic Helm repository.
OCI Registry (Recommended)
helm install {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \
--version 1.1190.0 -n {NAMESPACE} -f my-values.yaml
Classic Helm Repository
helm repo add kasm https://helm.kasm.com
helm repo update
helm install {RELEASE_NAME} kasm/kasm-helm --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml
Once the installation completes, disable the one-time initialization jobs in your values file before running any future helm upgrade. Leaving them enabled will cause them to re-run on every upgrade:
dbManagement:
initialize: false
upgrade:
enable: false
To customize the Helm chart beyond what values allow, clone the kasm-helm GitHub repository and check out the tagged release that corresponds to your Kasm version (e.g., release/1.1190.0):
git clone https://github.com/kasmtech/kasm-helm.git
cd kasm-helm
git checkout release/1.1190.0
Then install from the local chart directory:
helm install {RELEASE_NAME} ./charts/kasm-helm -n {NAMESPACE} -f my-values.yaml
6. Verify All Pods Are Running
kubectl get pods -n {NAMESPACE} --watch
Wait until all pods show Running or Completed, then press Ctrl+C.
Post-Installation
Configure DNS
Retrieve the ingress address assigned to your deployment:
kubectl get ingress -n {NAMESPACE}
Update your DNS record for publicAddr to point to the value in the ADDRESS column. Once DNS has propagated, Kasm will be reachable at https://{publicAddr}.
Retrieve Credentials
The quickest way to see all post-install information is:
helm get notes {RELEASE_NAME} -n {NAMESPACE}
Or retrieve credentials directly:
# Admin password (login: admin@kasm.local)
kubectl get secret --namespace {NAMESPACE} {RELEASE_NAME}-secrets \
-o jsonpath="{.data.admin-password}" | base64 -d; echo
# User password (login: user@kasm.local)
kubectl get secret --namespace {NAMESPACE} {RELEASE_NAME}-secrets \
-o jsonpath="{.data.user-password}" | base64 -d; echo
Pulling the Latest Build
The chart uses rolling image tags which are rebuilt with the latest software updates and patches on a regular schedule. While Kubernetes does not automatically check for newer images for a running service, you can trigger updates by restarting each service and ensuring the imagePullPolicy is set to Always (which is the chart's default).
If you need to pin a specific build, you can pin to a timestamped tag such as 1.19.0-rolling-20260215 following the section Customizing Component Image Tags. Timestamped tags are immutable so a rollout restart will not pull a newer build. To advance to a newer timestamped build, update the tag in your values file and run helm upgrade.
Use the command kubectl rollout restart to restart services and pull updates. This type of restart will respect the uptime policies in the chart and minimize disruptions.
kubectl rollout restart deployment/{RELEASE_NAME}-api \
deployment/{RELEASE_NAME}-manager \
deployment/{RELEASE_NAME}-proxy \
deployment/{RELEASE_NAME}-guac \
deployment/{RELEASE_NAME}-rdp-gateway \
deployment/{RELEASE_NAME}-rdp-https-gateway \
-n {NAMESPACE}
Monitor rollout progress for any individual deployment:
kubectl rollout status deployment/{RELEASE_NAME}-api -n {NAMESPACE}
If you configured kasmZones, each zone creates its own set of Deployments with the zone name appended (for example, {RELEASE_NAME}-api-{ZONE_NAME}). Run kubectl get deployments -n {NAMESPACE} to list all Deployments in your namespace before restarting.
Applying Changes to a Running Instance
To apply changes to your values for a running deployment, always set dbManagement.initialize to false. If left enabled, the one-time initialization job will re-run and fail on an already-initialized database.
The value of dbManagement.upgrade.enable depends on whether the change includes a database schema migration. If applying a config change or image tag update with no schema migration (typical of rolling updates) you should set upgrade.enable to false in addition to your other changes:
dbManagement:
initialize: false
upgrade:
enable: false
If an image tag update includes a database schema migration (typical of major/minor version updates, e.g. 1.18.0 -> 1.18.1), then set the value to true:
dbManagement:
initialize: false
upgrade:
enable: true
When upgrade.enable: true is set, the upgrade job runs a full database backup and restore cycle on every helm upgrade, regardless of whether a schema migration is needed. It will not fail if there is nothing to migrate, but it will perform unnecessary work. Always reset upgrade.enable to false once the upgrade completes.
If you use false when a migration was required, pods will fail to start and the API logs will contain an alembic version mismatch error. Rerun the upgrade with upgrade.enable: true to recover, then reset it to false.
Then run:
helm upgrade {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \
--version 1.1190.0 -n {NAMESPACE} -f my-values.yaml
Next Steps
- Configure TLS Certificates: Certificate management options
- Kubernetes How-To Guides: Multi-region proxies, VM migration, and more
- Upgrade Kasm on Kubernetes: Upgrade paths
- Kubernetes Troubleshooting: Diagnose pod, ingress, and storage issues