RDP and VNC Through Firewalls

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

Settingmstsc .rdp keyxfreerdp flagSaving
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.
8
Chapters
3
Protocols (RDP · VNC · NX)
6
Tools covered
10
Security checklist items