Direct RDP connections on Kubernetes (port 3389)
Overview
Kasm Workspaces delivers RDP sessions through the browser or through a native RDP client, depending on workspace and zone configuration. The native client path can route over HTTPS on port 443 through the RDP HTTPS Gateway, or connect directly on port 3389 through the RDP Gateway. This guide configures the additional Kubernetes resources needed to expose the RDP Gateway on port 3389, so native RDP clients connect directly to a Kasm Workspaces deployment on Kubernetes. Standard Kubernetes Ingress handles only HTTP and HTTPS traffic, so the direct path requires a NodePort or LoadBalancer service.
The three RDP connection modes are summarized below.
| Connection mode | How it works | Extra Kubernetes config needed |
|---|---|---|
| Web native client | Rendered in the browser through Guacamole, with no RDP gateways involved | None |
| Thick client through RDP HTTPS Gateway | Native RDP client connects over HTTPS (port 443) through the RDP HTTPS Gateway | None. Works through standard Ingress. |
| Thick client through RDP Gateway (direct) | Native RDP client connects directly on port 3389 through the RDP Gateway | Required. This guide. |
The web native and RDP HTTPS Gateway modes both work out of the box with a standard Kasm Workspaces Kubernetes deployment. The thick client default routes through the RDP HTTPS Gateway. To switch to the direct RDP Gateway path, an Administrator disables Enable RDP HTTPS Gateway in the zone settings. Kasm Workspaces then 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, which is the default. This routing is transparent and does not require any of the configuration in this guide.
When a user launches a session through the direct RDP Gateway path, Kasm Workspaces generates an .rdp file containing the gateway address. This address is built from the SERVER_HOSTNAME environment variable on the RDP Gateway container. The variable defaults to the internal Kubernetes service name, which is not reachable from outside the cluster. The Kasm Helm chart provides the directRdpService values to resolve this. When enabled, the chart creates an external-facing service to route port 3389 traffic to the RDP Gateway pods. The chart also sets SERVER_HOSTNAME to the rdpAccessURL you provide, so generated .rdp files contain the correct external address.
Prerequisites
Before you begin, confirm the following:
- A working Kasm Workspaces deployment on Kubernetes installed with the Kasm Helm chart. See the Kubernetes installation tutorial.
- Access to your
my-values.yamlHelm values file and permission to runhelm upgradeagainst the deployment. - Administrator access to the Kasm Workspaces UI, with permission to edit Deployment Zones.
- For a LoadBalancer service, a cluster with a load balancer provisioner and permission to create DNS records.
Solution approach
This guide progresses through the following phases:
- Configure the
directRdpServiceHelm values. - Apply the updated configuration.
- Configure DNS for the external address.
- Verify the direct RDP connection.
Detailed steps
Configure the directRdpService Helm values
Add the directRdpService block to your my-values.yaml. Choose LoadBalancer for cloud environments with a load balancer provisioner, or NodePort for any cluster.
Option A: LoadBalancer
A LoadBalancer service provisions an external IP address 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, for example internal compared with external, or NLB compared with 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 address 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 address.
Apply the updated configuration
Apply your updated values file with one of the following methods. Use the OCI registry method unless you maintain a classic Helm repository.
OCI Registry (Recommended)
helm upgrade {RELEASE_NAME} oci://registry-1.docker.io/kasmweb/kasm-helm \
--version 1.1190.0-develop -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-develop -n {NAMESPACE} -f my-values.yaml \
--set dbManagement.initialize=false \
--set dbManagement.upgrade.enable=false
Configure DNS for the external address
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. If the value shows <pending>, wait a few minutes for provisioning to complete.
Verify the direct RDP connection
-
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 Workspaces UI, go to Infrastructure > Deployment Zones > Edit for your zone, and confirm Enable RDP HTTPS Gateway is disabled.
-
Launch an RDP workspace through the Kasm Workspaces web interface. Kasm Workspaces generates an
.rdpfile. Open the file in your RDP client and verify the connection succeeds on port 3389.
Common troubleshooting steps
- The generated
.rdpfile points to an internal address. ConfirmSERVER_HOSTNAMEresolves to yourrdpAccessURL. Run thekubectl get deploymentcommand in the verification phase to check the value. - The RDP client cannot reach port 3389. For LoadBalancer, confirm the service has an
EXTERNAL-IPand that DNS resolves yourrdpAccessURLto it. For NodePort, confirm clients reach a node IP address on the assigned node port and that firewalls allow that port. - The session still routes over HTTPS. Confirm Enable RDP HTTPS Gateway is disabled in the zone settings, so Kasm Workspaces generates
.rdpfiles for the direct path. - The LoadBalancer address stays
<pending>. Confirm the cluster has a load balancer provisioner and that any requireddirectRdpService.annotationsare correct for your cloud provider.
For general pod and service diagnostics, see Kubernetes troubleshooting.