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 mode | How it works | Extra Kubernetes config needed |
|---|---|---|
| Web native client | Rendered in the browser via Guacamole; no RDP gateways involved | None |
| Thick client via RDP HTTPS Gateway | Native RDP client connects over HTTPS (port 443) via the RDP HTTPS Gateway | None — works through standard ingress |
| Thick client via RDP Gateway (direct) | Native RDP client connects directly on port 3389 via the RDP Gateway | Required — 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.
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:
- Creates an external-facing service (NodePort or LoadBalancer) to route port 3389 traffic to the RDP Gateway pods
- Automatically sets
SERVER_HOSTNAMEto therdpAccessURLyou provide, so generated.rdpfiles 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
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:
OCI Registry (Recommended)
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)
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
- 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
- Confirm
SERVER_HOSTNAMEis set to yourrdpAccessURL:kubectl get deployment {RELEASE_NAME}-rdp-gateway -n {NAMESPACE} \-o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="SERVER_HOSTNAME")].value}' - In the Kasm Admin UI, go to Infrastructure → Deployment Zones → Edit your zone and confirm Enable RDP HTTPS Gateway is disabled.
- Launch an RDP workspace through the Kasm web interface. Kasm will generate an
.rdpfile — open it in your RDP client and verify the connection succeeds on port 3389.
Troubleshooting
See Kubernetes Troubleshooting for general pod and service diagnostics.