Explore More Everyday
Your go-to source for everyday advice

Secure Remote RDP Access with Cloudflare Zero Trust and Cloudflare Tunnel

Written by ·
Secure Remote RDP Access with Cloudflare Zero Trust and Cloudflare Tunnel

Access Private Windows Servers Without Opening RDP to the Internet

Remote access to Windows servers traditionally requires exposing RDP through a firewall, NAT, or port-forwarding rule. While this approach is straightforward, exposing TCP/3389 to the public Internet significantly increases the attack surface.

A better approach is to use Cloudflare Zero Trust with Cloudflare Tunnel.

With this architecture, the Windows server remains on the private network. A Cloudflare Tunnel agent establishes an outbound connection to Cloudflare, and authenticated users access the server through Cloudflare Access.

No inbound firewall rule or public RDP port is required.


Architecture Overview

The final architecture looks like this:

                        Internet
                           │
                           │ HTTPS
                           ▼
                  ┌───────────────────┐
                  │ Cloudflare Zero    │
                  │ Trust / Access     │
                  └─────────┬─────────┘
                            │
                     Authentication
                     + Access Policy
                            │
                            ▼
                  ┌───────────────────┐
                  │ Cloudflare Tunnel │
                  └─────────┬─────────┘
                            │
                       Outbound only
                            │
                            ▼
             ┌─────────────────────────────┐
             │       Private Network       │
             │                             │
             │     ┌──────────────────┐    │
             │     │ Windows Server   │    │
             │     │ 192.168.1.10     │    │
             │     │ TCP/3389         │    │
             │     └──────────────────┘    │
             │                             │
             └─────────────────────────────┘

The important security characteristic is that the private network does not need to accept an inbound connection from the Internet.


What We Are Building

In this example, we have a Windows server:

Server IP:      192.168.1.10
RDP Port:       3389
Private Network: 192.168.1.0/24

We want authorized users to access the server using browser-based RDP.

The user experience will be:

User
 │
 │ Open Cloudflare Access URL
 ▼
Cloudflare Login
 │
 │ Authentication
 ▼
Access Policy
 │
 │ Authorized?
 ▼
Browser-Based RDP
 │
 ▼
192.168.1.10:3389

Prerequisites

Before starting, make sure you have the following:

Cloudflare

  • A Cloudflare account
  • Cloudflare Zero Trust configured
  • A Zero Trust organization/team name
  • Access to the Zero Trust dashboard
  • A domain configured in Cloudflare if required for your application hostname

Network

The network containing the Windows server must have:

  • Internet connectivity
  • Outbound connectivity to Cloudflare
  • DNS resolution
  • The ability to reach the target server from the tunnel connector

Windows Server

Example:

Operating System: Windows Server
IP Address:       192.168.1.10
RDP Port:         3389

Verify that RDP works internally before troubleshooting Cloudflare.

For example, from another machine on the same network:

mstsc /v:192.168.1.10

If internal RDP doesn't work, fix that first.


The Four Key Components

One of the easiest ways to understand this setup is to think about four separate components.

Tunnel
   │
   ▼
Route
   │
   ▼
Target
   │
   ▼
Application
   │
   ▼
Access Policy

Each component has a different responsibility.

Component Responsibility
Tunnel Creates the connection between your private network and Cloudflare
Route Defines which IP/network is reachable through the tunnel
Target Defines the actual server/service
Application Defines how users access the service
Access Policy Defines who is allowed to access it

Keeping these concepts separate makes troubleshooting much easier.


Step 1 — Create the Cloudflare Tunnel

In the Cloudflare Zero Trust dashboard, go to:

Networks → Tunnels & Mesh

Create a new tunnel.

A tunnel connector/agent runs inside your private network and establishes an outbound connection to Cloudflare.

Screenshot Placeholder

[SCREENSHOT 1 — Create Cloudflare Tunnel]

Insert screenshot showing:

Zero Trust → Networks → Tunnels & Mesh → Create Tunnel

The important point here is:

Private Network
      │
      │ OUTBOUND
      ▼
Cloudflare

You do not need:

Internet
   │
   │ INBOUND
   ▼
Firewall
   │
   ▼
TCP/3389

This is one of the primary benefits of using Cloudflare Tunnel.


Step 2 — Deploy the Tunnel Connector

After creating the tunnel, Cloudflare will provide instructions for installing the connector/agent on a system inside your private network.

The connector can run on a suitable Linux server, VM, container, or another supported host.

Conceptually:

                 Cloudflare
                     ▲
                     │
                     │ Outbound
                     │
             ┌───────┴────────┐
             │ Tunnel Connector│
             └───────┬────────┘
                     │
                     │ Private LAN
                     ▼
             192.168.1.10:3389

Screenshot Placeholder

[SCREENSHOT 2 — Tunnel Connector Installation]

Insert screenshot showing the tunnel installation command and connector status.

After installation, verify that the tunnel shows as healthy/connected in the Zero Trust dashboard.

Validation

Before moving forward, confirm:

Tunnel Status: Connected

If the tunnel isn't connected, there is no reason to troubleshoot RDP yet.


Step 3 — Create a Network Route

The next step is to tell Cloudflare which network should be reachable through the tunnel.

Go to the tunnel's network/route configuration and create a route.

Suppose your private network is:

192.168.1.0/24

Create:

192.168.1.0/24

This means the tunnel can route traffic to addresses in that network.


Using /32 for a Single Server

If you only need access to one server:

192.168.1.10

you can use:

192.168.1.10/32

A /32 represents one IPv4 address.

This is often preferable from a least-privilege perspective when only one server needs to be accessed.

For example:

192.168.1.10/32

instead of:

192.168.1.0/24

Route Examples

Requirement Route
Entire subnet 192.168.1.0/24
One server 192.168.1.10/32
Another subnet 10.10.20.0/24
Specific public IP 203.162.3.3/32

Screenshot Placeholder

[SCREENSHOT 3 — Network Route Configuration]

Show the route configuration for:

192.168.1.10/32


Step 4 — Create the Target

Now define the server that users will actually access.

For this example:

Target:
192.168.1.10

Service:
RDP

Port:
3389

The relationship is:

Route
└── 192.168.1.10/32
        │
        ▼
Target
└── 192.168.1.10:3389
        │
        ▼
Windows RDP

Screenshot Placeholder

[SCREENSHOT 4 — Create Target]

Show the target configuration pointing to:

192.168.1.10


Step 5 — Create the Cloudflare Application

Now we create the application that users will see.

Go to:

Access → Applications

Create a new application.

Select:

Self-hosted

The application represents the user-facing entry point.


Configure the Public Hostname

Define the hostname users will access.

For example:

rdp.example.com

Users will use this hostname rather than connecting directly to:

192.168.1.10:3389

Screenshot Placeholder

[SCREENSHOT 5 — Self-hosted Application / Public Hostname]

Show the application configuration with the public hostname.


Step 6 — Enable Browser-Based RDP

When configuring the application, enable:

Allow access through browser-based RDP, SSH, or VNC sessions

This allows users to launch an RDP session directly from their browser.

The user does not necessarily need to install a traditional RDP client.

The flow becomes:

Browser
   │
   ▼
Cloudflare Access
   │
   ▼
Browser-based RDP
   │
   ▼
Cloudflare Tunnel
   │
   ▼
Windows Server

Screenshot Placeholder

[SCREENSHOT 6 — Enable Browser-Based RDP]

Highlight:

Allow access through browser-based RDP, SSH, or VNC sessions


Step 7 — Configure the Target and Port

Associate the application with the target created earlier.

For example:

Target:
192.168.1.10

Port:
3389

Your configuration should now logically look like:

Application
    │
    ├── Public Hostname
    │      └── rdp.example.com
    │
    ├── Target
    │      └── 192.168.1.10
    │
    └── Port
           └── 3389

Screenshot Placeholder

[SCREENSHOT 7 — Application Target Configuration]


Step 8 — Configure the Access Policy

This is where Zero Trust becomes especially useful.

The tunnel determines how Cloudflare reaches the server.

The Access Policy determines who is allowed to reach it.

For example:

Application:
rdp.example.com

Policy:

ALLOW
    └── Authorized users

You could restrict access based on your organization's authentication requirements.

For example:

Allow
 ├── Specific users
 ├── Corporate identity
 └── Required authentication conditions

The principle should be:

Deny by default and explicitly allow authorized users.

Screenshot Placeholder

[SCREENSHOT 8 — Access Policy]

Show the Allow policy configuration.


Step 9 — Test User Access

After the application is created, go to your Cloudflare Access team URL:

<teamname>.cloudflareaccess.com

Log in with an authorized account.

After successful authentication, you should see the applications available to you.

For example:

┌────────────────────────────┐
│                            │
│       Windows Server       │
│                            │
│          RDP               │
│                            │
└────────────────────────────┘

Click the application.

The browser-based RDP session should start.


End-to-End Validation

When troubleshooting, validate the architecture from left to right.

1. User Authentication
          │
          ▼
2. Access Policy
          │
          ▼
3. Application
          │
          ▼
4. Target
          │
          ▼
5. Route
          │
          ▼
6. Tunnel
          │
          ▼
7. Private Network
          │
          ▼
8. Windows RDP

Don't immediately assume that an RDP problem is an RDP problem.

There are several layers between the user and the Windows server.


Troubleshooting

Tunnel Shows as Disconnected

Symptoms

The Cloudflare dashboard shows that the tunnel connector is offline or disconnected.

Check

Verify that the connector is running.

For a Linux-based connector, check its service/container status.

Also verify outbound Internet connectivity from the connector host.

For example:

ping 8.8.8.8

and:

curl https://www.cloudflare.com

Also check DNS resolution.

nslookup cloudflare.com

Most Common Causes

  • Firewall blocking outbound traffic
  • DNS problems
  • Connector process stopped
  • Host has lost Internet connectivity
  • Proxy restrictions
  • Incorrect tunnel configuration

2. Tunnel Is Connected but RDP Doesn't Work

This usually means the tunnel itself is healthy, but the connector cannot reach the target.

From the tunnel connector host, test:

ping 192.168.1.10

Then test TCP/3389.

For Linux:

nc -vz 192.168.1.10 3389

or:

telnet 192.168.1.10 3389

You want to see that TCP/3389 is reachable.

If it isn't, investigate:

Tunnel Connector
      │
      X
      │
192.168.1.10:3389

Possible causes include:

  • Windows Firewall
  • Incorrect route
  • Incorrect IP address
  • Network ACL
  • VLAN restrictions
  • Routing problems
  • RDP service not running

3. RDP Works Internally but Not Through Cloudflare

If this works:

Internal Client
      │
      ▼
192.168.1.10:3389

but this doesn't:

Cloudflare
    │
    ▼
Tunnel
    │
    ▼
192.168.1.10:3389

then focus on the Cloudflare configuration.

Check these components in order:

Tunnel
  ↓
Route
  ↓
Target
  ↓
Application
  ↓
Access Policy

Make sure the target IP exactly matches the Windows server.

For example:

Target:
192.168.1.10

and not:

192.168.1.1

4. User Can Log In but Doesn't See the Application

This is usually an Access Policy issue.

Check:

  • Is the user authenticated?
  • Is the user's email/account included in the Allow policy?
  • Is there a conflicting policy?
  • Is the application enabled?
  • Is the user accessing the correct team URL?

Remember that successfully logging into Cloudflare Access does not automatically mean the user has permission to access every application.


5. Browser-Based RDP Doesn't Start

Verify that:

  • Browser-based RDP is enabled
  • The application is configured for RDP
  • The target is correct
  • Port 3389 is correct
  • Windows RDP is enabled
  • The server is reachable from the tunnel connector

Also verify the Windows RDP service.


6. Windows Firewall

On the Windows server, verify that Remote Desktop is allowed through Windows Firewall.

The expected traffic is:

Tunnel Connector
       │
       │ TCP 3389
       ▼
192.168.1.10

The firewall must allow the connector/network to reach TCP/3389.

Importantly, you do not need to expose TCP/3389 on your Internet-facing firewall.


7. Windows 7 Compatibility

One important limitation:

Browser-based RDP does not work with Windows 7 Server.

If you are dealing with an older Windows environment, verify compatibility before using browser-based RDP as the access method.

For legacy systems, you may need to use a traditional RDP client or another supported remote-access solution.


Security Recommendations

From an SRE/DevOps perspective, getting the connection working is only the first step.

The next objective should be reducing the attack surface.

Avoid Broad Routes

If users only need one server, prefer:

192.168.1.10/32

instead of:

192.168.1.0/24

This follows the principle of least privilege.


Don't Expose TCP/3389

Avoid configurations such as:

Public IP
   │
   ▼
TCP/3389
   │
   ▼
Windows Server

Instead:

User
 │
 ▼
Cloudflare Access
 │
 ▼
Tunnel
 │
 ▼
Private RDP

Use Strong Authentication

Require appropriate identity authentication and, where supported by your organization's configuration, MFA.


Keep Policies Explicit

Instead of:

Allow everyone

use:

Allow
 └── Authorized users/groups

Monitor Access

From an operational perspective, monitor:

  • Tunnel availability
  • Authentication failures
  • Access policy events
  • RDP availability
  • Windows Server health
  • Network connectivity

This allows the solution to become part of your normal observability strategy rather than being a standalone remote-access configuration.


Operational Runbook

For an SRE/operations team, the following checklist is useful.

Connectivity

[ ] Tunnel connected
[ ] Tunnel connector healthy
[ ] Route exists
[ ] Target exists
[ ] Target IP is correct
[ ] TCP/3389 reachable

Cloudflare Access

[ ] Application exists
[ ] Public hostname is correct
[ ] Browser-based RDP enabled
[ ] Target assigned
[ ] Port 3389 configured
[ ] Access policy configured
[ ] User authorized

Windows

[ ] Server is online
[ ] RDP enabled
[ ] RDP service running
[ ] Windows Firewall allows RDP
[ ] Server accepts TCP/3389

Final Architecture

Once everything is configured, the complete solution looks like this:

                         USER
                           │
                           │
                           ▼
                ┌─────────────────────┐
                │ Cloudflare Access   │
                │ Authentication      │
                └──────────┬──────────┘
                           │
                     Access Policy
                           │
                           ▼
                ┌─────────────────────┐
                │    Application      │
                │ rdp.example.com     │
                └──────────┬──────────┘
                           │
                           ▼
                ┌─────────────────────┐
                │       Target        │
                │ 192.168.1.10:3389   │
                └──────────┬──────────┘
                           │
                           ▼
                ┌─────────────────────┐
                │       Route         │
                │ 192.168.1.10/32     │
                └──────────┬──────────┘
                           │
                           ▼
                ┌─────────────────────┐
                │  Cloudflare Tunnel  │
                │    Outbound Only    │
                └──────────┬──────────┘
                           │
                           ▼
              ┌──────────────────────────┐
              │      Private Network     │
              │                          │
              │  ┌────────────────────┐  │
              │  │ Windows Server     │  │
              │  │ 192.168.1.10       │  │
              │  │ RDP :3389          │  │
              │  └────────────────────┘  │
              │                          │
              └──────────────────────────┘

Summary

Cloudflare Zero Trust provides a clean way to provide remote access to private Windows servers without exposing RDP directly to the Internet.

The key concepts are:

1. Tunnel
Connects your private network to Cloudflare using outbound connectivity.

2. Route
Defines which IP addresses or networks can be reached through the tunnel.

3. Target
Identifies the specific server and service you want to access.

4. Application
Provides the user-facing hostname and browser-based RDP configuration.

5. Access Policy
Controls which users are allowed to access the application.

The most important architectural principle is:

Keep the server private. Authenticate the user at the edge. Use the tunnel to reach the private service.

This approach eliminates the need for traditional Internet-facing RDP port forwarding and provides a much cleaner foundation for centralized access control and operational monitoring.


Quick Reference

Private Server
192.168.1.10:3389
        │
        │
        ▼
Cloudflare Tunnel
        │
        ▼
Route
192.168.1.10/32
        │
        ▼
Target
192.168.1.10:3389
        │
        ▼
Application
rdp.example.com
        │
        ▼
Access Policy
Authorized Users
        │
        ▼
Browser-Based RDP

No inbound RDP port forwarding required.

No public exposure of TCP/3389 required.

Access is controlled through Cloudflare Zero Trust.