Skip to main content
Version: 1.19.0 (latest)

Direct RDP Connections on Kubernetes (Port 3389)

When a user launches an RDP workspace in Kasm, the session can be delivered in three ways depending on workspace and zone configuration:

Connection modeHow it worksExtra Kubernetes config needed
Web native clientRendered in the browser via Guacamole; no RDP gateways involvedNone
Thick client via RDP HTTPS GatewayNative RDP client connects over HTTPS (port 443) via the RDP HTTPS GatewayNone — works through standard ingress
Thick client via RDP Gateway (direct)Native RDP client connects directly on port 3389 via the RDP GatewayRequired — this guide

The web native and RDP HTTPS Gateway modes both work out of the box with a standard Kasm Kubernetes deployment. The thick client default is to route through the RDP HTTPS Gateway. To switch to the direct RDP Gateway path, an admin must disable Enable RDP HTTPS Gateway in the zone settings — after which Kasm generates .rdp files that connect directly on port 3389.

note

The RDP HTTPS Gateway also routes connections internally through the RDP Gateway when Enable RDP HTTPS Gateway DLP is enabled (the default). This is transparent and does not require any of the configuration in this guide.

This guide covers the additional Kubernetes configuration needed to expose the RDP Gateway on port 3389 for direct thick client connections. Standard Kubernetes Ingress does not support arbitrary TCP ports, so you must expose the RDP Gateway using a NodePort or LoadBalancer service type.


How it Works

When a user launches an RDP session using the direct RDP Gateway path, Kasm generates an .rdp file containing the gateway address. This address is built from the SERVER_HOSTNAME environment variable on the RDP Gateway container, which defaults to the internal Kubernetes service name (not reachable from outside the cluster).

The Kasm Helm chart provides the directRdpService values to handle this configuration. When enabled, the chart:

  1. Creates an external-facing service (NodePort or LoadBalancer) to route port 3389 traffic to the RDP Gateway pods
  2. Automatically sets SERVER_HOSTNAME to the rdpAccessURL you provide, so generated .rdp files contain the correct external address

Step 1: Configure directRdpService in Your Values File

Add the directRdpService block to your my-values.yaml. Choose LoadBalancer (cloud environments with a load balancer provisioner) or NodePort (available on any cluster).

Option A: LoadBalancer

A LoadBalancer service provisions an external IP or hostname from your cloud provider. Clients connect directly to port 3389 on that address.

directRdpService:
enabled: true
rdpAccessURL: rdp.example.com
type: LoadBalancer

Cloud providers may require annotations to configure the load balancer (e.g., internal vs external, NLB vs ALB). Add them under directRdpService.annotations:

directRdpService:
enabled: true
rdpAccessURL: rdp.example.com
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb

Option B: NodePort

A NodePort service exposes a port on every worker node in the cluster. External clients connect to any node IP on the assigned node port.

directRdpService:
enabled: true
rdpAccessURL: rdp-node.example.com
type: NodePort
note

If your nodes are behind a load balancer or NAT, set rdpAccessURL to the address clients actually reach — not the internal node IP.


Step 2: Apply the Configuration

Apply your updated values file:

helm upgrade {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \
--version 1.1190.0 -n {NAMESPACE} -f my-values.yaml \
--set dbManagement.initialize=false \
--set dbManagement.upgrade.enable=false

Classic Helm Repository

helm repo add kasm https://helm.kasm.com
helm repo update
helm upgrade {RELEASE_NAME} kasm/kasm-helm --version 1.1190.0 -n {NAMESPACE} -f my-values.yaml \
--set dbManagement.initialize=false \
--set dbManagement.upgrade.enable=false

Step 3: Configure DNS (LoadBalancer only)

This step is optional

Skip this step if you used NodePort, or if your cluster runs ExternalDNS or a similar controller that automatically creates DNS records from service annotations.

If you chose LoadBalancer, retrieve the external address assigned by your cloud provider:

kubectl get service -n {NAMESPACE} -l app.kubernetes.io/name={RELEASE_NAME}-rdp-gateway

Create a DNS record pointing your rdpAccessURL hostname to the value in the EXTERNAL-IP column. Wait a few minutes for provisioning if the value shows <pending>.


Verify

  1. Confirm the RDP Gateway service shows the expected type and external address:
    kubectl get service -n {NAMESPACE} -l app.kubernetes.io/name={RELEASE_NAME}-rdp-gateway
  2. Confirm SERVER_HOSTNAME is set to your rdpAccessURL:
    kubectl get deployment {RELEASE_NAME}-rdp-gateway -n {NAMESPACE} \
    -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="SERVER_HOSTNAME")].value}'
  3. In the Kasm Admin UI, go to InfrastructureDeployment ZonesEdit your zone and confirm Enable RDP HTTPS Gateway is disabled.
  4. Launch an RDP workspace through the Kasm web interface. Kasm will generate an .rdp file — open it in your RDP client and verify the connection succeeds on port 3389.

Troubleshooting

See Kubernetes Troubleshooting for general pod and service diagnostics.