Security

Tunnel Remote Desktop port 3389 through SSH

Carry Remote Desktop inside an encrypted SSH connection to your Windows VPS, connect mstsc to localhost, and only then tighten public access to port 3389.

AdvancedWindows server5 min read

An SSH tunnel lets you reach Remote Desktop without exposing port 3389 to the whole internet. Your RDP app connects to a port on your own computer. SSH carries that traffic to the server and hands it to Remote Desktop on 127.0.0.1:3389. Bots see only the SSH port, which you can protect with keys.

This guide sets up the tunnel with OpenSSH on your Windows VPS, tests it, and only then restricts public access to 3389.

Before you start

  • A Windows VPS with Administrator access over Remote Desktop.
  • OpenSSH Server installed and running on the VPS. If it is not, follow Install OpenSSH Server on Windows first.
  • An inbound firewall rule for SSH (TCP 22). The OpenSSH installer normally creates one called OpenSSH-Server-In-TCP.
  • An SSH client on your computer. Windows 10/11, macOS and Linux all include ssh.
  • Access to your VPS provider's browser console as a fallback.

Note: Key-based SSH login is strongly recommended before you rely on this tunnel. See Set up SSH key login on Windows.

How the tunnel works

A local forward has three parts:

  • Local port on your computer, for example 13389.
  • SSH server, your VPS at 203.0.113.10, port 22.
  • Destination as seen from the VPS: 127.0.0.1:3389, where Remote Desktop listens.

Your RDP app connects to 127.0.0.1:13389. SSH encrypts the traffic, sends it to the VPS, and the VPS connects to itself on 3389. Because that last hop comes from the server itself, it does not need the public firewall rule.

We use 13389 locally so it never clashes with anything already running on your PC.

Check SSH works first

From your computer, sign in over SSH with your Windows username:

Bash
ssh admin@203.0.113.10

Accept the host key the first time, enter your password (or use your key), and you should get a cmd or PowerShell prompt on the server. Type exit to leave. If this fails, fix SSH before going further.

Open the tunnel

On your computer, run:

Bash
ssh -N -L 13389:127.0.0.1:3389 admin@203.0.113.10
  • -L 13389:127.0.0.1:3389 forwards local port 13389 to 127.0.0.1:3389 on the server.
  • -N opens the tunnel without starting a remote shell.

After you sign in, the window looks idle. That is correct. The tunnel stays open as long as this window does. Press Ctrl + C to close it.

On Windows, run the same command in PowerShell or Windows Terminal. On macOS or Linux, run it in Terminal.

Save it in your SSH config

To avoid typing the full command, add an entry to ~/.ssh/config (on Windows, C:\Users\<you>\.ssh\config):

Host rdp-tunnel
    HostName 203.0.113.10
    User admin
    LocalForward 13389 127.0.0.1:3389
    ServerAliveInterval 30

Then start it with ssh -N rdp-tunnel. ServerAliveInterval keeps idle tunnels from being dropped by routers.

Connect Remote Desktop through the tunnel

With the tunnel open:

  1. Press Win + R, type mstsc and press Enter.
  2. In Computer, enter 127.0.0.1:13389.
  3. Click Connect and sign in with your Windows username and password.

Or from PowerShell:

PowerShell
mstsc /v:127.0.0.1:13389

On a Mac, add a PC in Windows App with the PC name 127.0.0.1:13389.

The certificate warning will mention a name mismatch, because you connected to 127.0.0.1. That is expected for a tunnel.

Check it works

While connected through the tunnel, open PowerShell on the server and run:

PowerShell
Get-NetTCPConnection -LocalPort 3389 -State Established |
  Format-Table LocalAddress, RemoteAddress

A line with RemoteAddress of 127.0.0.1 (or ::1) proves your session arrived through SSH rather than directly over the internet.

Tighten public access to 3389

Only do this after the tunnel has worked at least once, and preferably from more than one place.

Warning: Once 3389 is closed to the internet, the tunnel becomes your only Remote Desktop route. If SSH breaks, you will need the browser console in your VPS provider's control panel to get back in.

The safer option is to allow 3389 only from one fixed IP you trust, as described in Restrict RDP port 3389 to your own IP addresses:

PowerShell
Set-NetFirewallRule -DisplayName "Remote Desktop (TCP 3389)" -RemoteAddress 198.51.100.20

If you want the tunnel to be the only route, disable the public rule instead. Disabling keeps it, so you can turn it back on quickly:

PowerShell
Disable-NetFirewallRule -DisplayName "Remote Desktop (TCP 3389)"

To undo, run Enable-NetFirewallRule with the same name, from the browser console if needed. Use the exact display name of your 3389 rule.

Troubleshooting

  • "bind: Address already in use": something on your computer already uses 13389. Pick another local port, such as 23389, in both the ssh and mstsc commands.
  • mstsc says it can't connect to 127.0.0.1:13389: the tunnel window is closed or the SSH login failed. Start the tunnel again and keep that window open.
  • "channel 2: open failed: connect failed": the tunnel is up, but nothing answers on 3389 on the server. Check that Remote Desktop listens on 3389 from the server itself.
  • Tunnel drops after idle time: add ServerAliveInterval 30 to your SSH config, as shown above.

Next steps

  • Learn more about forwarding: SSH local port forwarding.
  • Compare options: Proxy vs VPN vs SSH tunnel.
Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.