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
3389is 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.