Chapter 8 — RDP and VNC Through Firewalls
Everything so far has assumed you're on the same local network as the
machine you're connecting to. The moment you step outside that network —
whether working from a café, a hotel, or simply a different building — you
hit two problems: NAT (your target machine doesn't have a
public IP) and firewalls (ports 3389 and 5901 are blocked
or dangerous to open). This chapter covers the practical solutions.
Three Approaches — Pick the Right One
SSH Tunnel
Recommended
Forward RDP or VNC through an existing SSH connection. No extra software, fully encrypted, works wherever SSH works. Requires port 22 (or a custom port) to be reachable.
Cloudflare Tunnel
Zero open ports
The tunnel dials out from your machine to Cloudflare. Nothing inbound needs to be open. Supports RDP natively via the WARP client or cloudflared access. Best for always-on remote access.
VPN
Full network access
Connect to a WireGuard or OpenVPN server on your home network — your device appears to be on the LAN. Then use RDP or VNC exactly as you would locally. Covered in full in the VPN course.
Don't open 3389 or 5901 to the internet directly.
Port 3389 is constantly scanned. Within minutes of opening it, automated
tools will begin brute-forcing credentials. All three methods above avoid
exposing these ports publicly.
Method 1 — SSH Tunnel for RDP
The pattern: forward the remote machine's RDP port (3389) to a local
port on your machine, then point mstsc or Remmina at
localhost. The RDP traffic travels inside the encrypted SSH
connection.
your laptop localhost:13389
│
SSH tunnel (port 22) encrypted — internet
│
SSH jump host / home router port 22 open, 3389 closed
│
target Windows/Linux box 127.0.0.1:3389 (RDP)
# Tunnel — forward local port 13389 to the target's RDP port via the SSH host
# Use a high local port (13389) to avoid conflicts with a local RDP server
ssh -fNL 13389:TARGET_IP:3389 user@SSH_HOST
# Examples:
# Target IS the SSH host (same machine runs SSH and RDP)
ssh -fNL 13389:localhost:3389 philip@myhome.example.com
# Target is a different machine behind the SSH host (jump pattern)
ssh -fNL 13389:192.168.0.50:3389 philip@myhome.example.com
# Step 2 — connect mstsc to the local end of the tunnel
mstsc /v:localhost:13389
Persistent tunnel in ~/.ssh/config
# ~/.ssh/config — define the tunnel as part of the host alias
Host home-rdp
HostName myhome.example.com
User philip
IdentityFile ~/.ssh/id_home
LocalForward 13389 192.168.0.50:3389 # or localhost:3389 if same host
# Usage: ssh -fN home-rdp then mstsc /v:localhost:13389
SSH on port 443: Some networks block outbound port 22.
Configure your SSH server to also listen on port 443
(Port 443 in /etc/ssh/sshd_config). HTTPS
traffic on 443 is almost never blocked. Combine with
Port 22 to keep the standard port working too.
Method 1b — SSH Tunnel for VNC
# Forward VNC display :1 (port 5901) through SSH
ssh -fNL 5901:localhost:5901 philip@myhome.example.com
# Then connect the VNC viewer to the local tunnel end
vncviewer localhost:5901 # Linux/macOS
# TigerVNC Viewer on Windows: enter localhost:5901
# In Remmina — configure the SSH tunnel inside the connection profile:
# Protocol: VNC → SSH Tunnel tab → enable, enter SSH host details
# Remmina creates the tunnel automatically when you connect
Method 2 — Cloudflare Tunnel for RDP
Cloudflare Tunnel (cloudflared) creates an outbound-only
connection from your server to Cloudflare's network. Nothing inbound is
required. Cloudflare provides an RDP-specific access method through their
Zero Trust product.
server — set up cloudflared RDP tunnel
# install cloudflared (if not already present from host1–host8 course)
philip@debian:~$ sudo apt install cloudflared
# authenticate and create a named tunnel
philip@debian:~$ cloudflared tunnel login
philip@debian:~$ cloudflared tunnel create home-rdp
# configure the tunnel to forward to RDP
philip@debian:~$ cat ~/.cloudflared/config.yml
tunnel: home-rdp
credentials-file: /home/philip/.cloudflared/<uuid>.json
ingress:
- hostname: rdp.example.com
service: rdp://localhost:3389
- service: http_status:404
# run the tunnel
philip@debian:~$ cloudflared tunnel run home-rdp
client — connect via cloudflared access
# on the client machine — install cloudflared
# open a local listener that forwards to the Cloudflare tunnel
C:\Users\philip> cloudflared access rdp --hostname rdp.example.com --url localhost:13389
# browser opens for Cloudflare Zero Trust authentication
# once authenticated, connect mstsc to the local listener
C:\Users\philip> mstsc /v:localhost:13389
Why Cloudflare Tunnel for RDP? Port 3389 never needs to
be open anywhere. Cloudflare's Zero Trust layer adds authentication before
the RDP connection is even established — an attacker can't reach the RDP
server at all. It also works from any network, including those that block
SSH port 22.
Performance Tuning for Slow Connections
Remote desktop over a high-latency or low-bandwidth link feels sluggish
because every screen update must make a round trip. The goal is to send
less data per frame and tolerate more latency gracefully.
RDP (mstsc / xfreerdp) — what to disable first
| Setting | mstsc .rdp key | xfreerdp flag | Saving |
| Colour depth → 16-bit |
session bpp:i:16 |
/bpp:16 |
Large — halves pixel data |
| Disable wallpaper |
disable wallpaper:i:1 |
-wallpaper |
Large — removes background redraws |
| Disable font smoothing |
allow font smoothing:i:0 |
-fonts |
Moderate |
| Disable desktop composition |
allow desktop composition:i:0 |
-aero |
Moderate |
| Disable themes |
disable themes:i:1 |
-themes |
Moderate |
| Disable animations |
disable menu anims:i:1 |
-animations |
Moderate |
| Enable compression |
compression:i:1 |
/compression |
Moderate on slow links |
# Slow-link .rdp profile — all bandwidth optimisations applied
full address:s:localhost:13389
session bpp:i:16
compression:i:1
disable wallpaper:i:1
disable themes:i:1
disable menu anims:i:1
allow font smoothing:i:0
allow desktop composition:i:0
connection type:i:2 # 2 = low-speed broadband preset
# xfreerdp slow-link one-liner
xfreerdp /v:localhost:13389 /u:philip /bpp:16 /compression \
-wallpaper -themes -aero -fonts -animations \
/dynamic-resolution +clipboard /cert:ignore
VNC — reducing bandwidth
# TigerVNC viewer — maximum compression, lower colour
vncviewer -compress 9 -quality 4 localhost:5901
# Server side — start with higher compression
vncserver :1 -ZlibLevel 9 -depth 16 -geometry 1280x720
# In xfce4 — disable compositing to reduce screen update frequency
# Settings Manager → Window Manager Tweaks → Compositor → uncheck "Enable display compositing"
SSH tunnel compression
# -C enables gzip compression on the SSH tunnel itself
# Useful for VNC (pixel data compresses well); marginal gain for RDP (already compressed)
ssh -fNL 5901:localhost:5901 -C philip@myhome.example.com
Diagnosing a Slow Remote Desktop Session
measuring your connection quality
# round-trip time to your home SSH host — the dominant factor
philip@laptop:~$ ping myhome.example.com -c 10
rtt min/avg/max = 12.4/14.1/18.6 ms # excellent — LAN-like
rtt min/avg/max = 80/95/140 ms # acceptable — some lag visible
rtt min/avg/max = 250/300/400 ms # poor — use text mode if possible
# measure available bandwidth through the SSH tunnel
philip@laptop:~$ ssh philip@myhome.example.com 'dd if=/dev/zero bs=1M count=100' | \
pv > /dev/null
100MiB transferred in 8.3s — 12.0 MB/s (96 Mbit/s)
# check CPU on the remote server — a maxed-out CPU causes lag independent of bandwidth
philip@debian:~$ top -bn1 | head -5
Security Hardening Checklist
-
Never expose port 3389 or 5901 directly to the internet.
Use an SSH tunnel, VPN, or Cloudflare Tunnel instead.
-
Require key-based authentication for the SSH tunnel.
Disable password auth on the SSH server: PasswordAuthentication no
in /etc/ssh/sshd_config.
-
Run fail2ban on the SSH server.
Even with key-only auth, fail2ban stops log spam and blocks scanners.
-
Use a non-standard SSH port (e.g. 2222 or 443).
Eliminates 99% of automated scan noise. Not security by obscurity —
just noise reduction.
-
For VNC, start the server with -localhost yes.
VNC then only accepts connections from 127.0.0.1 — the SSH tunnel is the
only way in, and port 5901 can stay closed in the firewall.
-
Use strong, unique passwords for RDP and VNC accounts.
RDP: ensure the Windows account has a password. VNC: set a password with
vncpasswd separate from the system password.
-
Restrict RDP to specific users.
On Windows: System Properties → Remote → Select Users. Add only
the accounts that need remote access.
-
Keep xRDP and TigerVNC updated.
Both have had security patches. sudo apt upgrade xrdp tigervnc-standalone-server
periodically.
-
Review who has AnyDesk / TeamViewer unattended access.
Revoke access for old installations. Never share your ID publicly.
-
Check active sessions periodically.
On Windows: query session or Task Manager → Users tab.
On Linux: who and ss -tlnp | grep 590.
Course Complete — Remote Desktop: RDP & VNC
You've covered the full spectrum of remote desktop technology — from the
protocols and their trade-offs, through setting up Windows RDP, Linux
xRDP, VNC, and modern alternatives, to reaching everything securely from
outside your network. The tools you now know cover every scenario from
a quick home-lab connection to a hardened production remote access setup.
3
Protocols (RDP · VNC · NX)
10
Security checklist items