Networking

How to Setup RDP via SSH Tunnel VPS Raspberry Pi

Step-by-step guide to set up RDP access to home PC (192.168.0.20:3389) through VPS proxy (200.1.1.1) using SSH tunnel on Raspberry Pi. Fix iptables, AllowTcpForwarding, GatewayPorts, and verify forwarding.

1 answer 1 view

How to set up RDP access to a home PC (192.168.0.20:3389) through a VPS proxy (200.1.1.1) using an SSH tunnel via Raspberry Pi (192.168.0.10)?

Current setup:

  • L2TP tunnel between VPS (PPP: 10.10.0.1) and router (PPP: 10.10.0.2) – working.
  • SSH tunnel from VPS to Raspberry Pi: ssh -L 200.1.1.1:3389:192.168.0.20:3389 user@10.10.0.2:22 – tunnel establishes successfully.

iptables rules on VPS for ISP IP (100.1.1.1):

iptables -A INPUT -s 100.1.1.1 -p tcp --dport 3389 -m conntrack -ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -d 100.1.1.1 -p tcp --sport 3389 -m conntrack -ctstate ESTABLISHED -j ACCEPT

Packets arrive on VPS port 3389, but RDP connection from external client to VPS:3389 fails to forward through the SSH tunnel to PC:3389. What configuration is missing for proper RDP tunneling over SSH via proxy?

Your SSH tunnel is up but the VPS isn’t exposing the forwarded socket to the network. To fix RDP access through your VPS (200.1.1.1) to the home PC (192.168.0.20:3389) over the SSH tunnel via the Pi, you must: allow TCP forwarding on the SSH server, make the tunnel listen on the VPS public interface (use -g and bind to 0.0.0.0 or the VPS IP, or use a reverse -R with GatewayPorts), and open/adjust iptables (or enable net.ipv4.ip_forward if you use DNAT). Once those are set, verify the VPS is actually listening on 200.1.1.1:3389 (ss/netstat), then test with telnet/mstsc and ssh -vvv.


Contents


Quick checklist — what’s missing

  • AllowTcpForwarding must be enabled on the SSH server you connect to (the machine at 10.10.0.2 / the Pi/router). See logs if it’s disabled.
  • The SSH client on the VPS must let remote hosts connect to the forwarded local port: add -g or bind to 0.0.0.0 (or use a reverse tunnel with GatewayPorts yes).
  • Confirm 200.1.1.1 is actually assigned to the VPS interface (ip addr show). If not, bind to 0.0.0.0 or the correct address.
  • iptables must actually allow incoming TCP to 3389 from the client(s) you expect (your current rules are restrictive). If you DNAT incoming traffic to loopback, enable net.ipv4.ip_forward and use the nat PREROUTING rule.
  • Verify with ss/netstat/tcpdump and ssh -vvv that the VPS is listening and forwarding.

Why does this checklist matter? Because your SSH tunnel only forwards traffic it is allowed to accept and only if the server permits the requested forwarding type. If any of those links in the chain is closed, the client’s RDP packets will arrive at the VPS but never be handed to the SSH process to forward to 192.168.0.20.


Why your current -L command doesn’t forward externally

A few common causes given your command and setup:

  • Binding vs listening: by default SSH local forwards listen on loopback only. Even if you specified a bind address, remote connections are blocked unless the SSH client was started with -g (allow remote connections). See how local (-L) vs remote (-R) forwarding behaves in practical guides like this primer on SSH tunnels and forwarding options interface31.ru.
  • SSH server policy: the server you connect to must allow TCP forwarding. If /etc/ssh/sshd_config has AllowTcpForwarding no, forwarding will be silently rejected. That same file controls whether remote binds from -R are allowed (GatewayPorts). See examples and notes on GatewayPorts and AllowTcpForwarding in practical RDP+SSH how‑tos like devhops.ru.
  • Firewall or IP binding mismatch: your iptables rules look limited to src 100.1.1.1; if the client IP differs, packets will be dropped. Also, binding to 200.1.1.1 only works if that address is present on the VPS; otherwise ssh can’t listen there.

Fix A — recommended: run the tunnel on the VPS and allow remote connects (-g)

If you want clients to connect to 200.1.1.1:3389 on the VPS and have that forwarded, do this on the VPS:

  1. Check the VPS has the public IP:
sh
ip addr show

If 200.1.1.1 is missing, either add it or bind to 0.0.0.0 instead of that specific address.

  1. Confirm the SSH server you connect to (10.10.0.2) allows forwarding. On 10.10.0.2 (the router or Pi/router), edit /etc/ssh/sshd_config:
AllowTcpForwarding yes
# GatewayPorts only needed for server-side bindings (-R); not required for -L with -g
# GatewayPorts yes

Then restart sshd:

sh
sudo systemctl restart sshd

(If that SSH server is your Pi, the same change applies — Pi’s sshd must permit forwarding; see discussion at https://raspberrypi.stackexchange.com/questions/54205/remote-desktop-connection-via-ssh-tunneling.)

  1. Start the local forward on the VPS so it accepts external connections:
sh
# bind to all interfaces; -g allows remote hosts to connect
ssh -N -f -g -L 0.0.0.0:3389:192.168.0.20:3389 user@10.10.0.2

Or explicitly bind to the VPS public IP:

sh
ssh -N -f -g -L 200.1.1.1:3389:192.168.0.20:3389 user@10.10.0.2

Notes:

  • -N = no remote command, -f = background, -g = allow remote connections to the forwarded port.
  • If the SSH server refuses forwarding you’ll see messages in ssh -vvv.
  1. Verify on the VPS:
sh
ss -ltnp | grep 3389
# or
netstat -plnt | grep 3389

You should see the ssh process listening on 0.0.0.0:3389 or 200.1.1.1:3389.

  1. Adjust iptables (next section) so external clients can reach that port.

If you prefer GUI tools or Windows-oriented instructions, there are many examples using plink/Putty; Habr has a practical plink example showing the same idea in a Win → SSH → RDP use case: https://habr.com/ru/sandbox/155672/.


Fix B — alternative: reverse tunnel from Raspberry Pi to VPS (-R)

Reverse tunneling is often cleaner when the home device (Pi) initiates the connection to the VPS:

  1. On VPS, ensure /etc/ssh/sshd_config contains:
AllowTcpForwarding yes
GatewayPorts yes

Restart sshd.

  1. On the Pi (192.168.0.10), run:
sh
# This opens port 3389 on the VPS and forwards incoming connections to 192.168.0.20:3389 via the Pi
ssh -N -f -R 0.0.0.0:3389:192.168.0.20:3389 user@200.1.1.1

Because the Pi initiated the connection, no tricky binding to the VPS interface is required on the VPS side — but GatewayPorts yes on the VPS is needed to make the server listen on 0.0.0.0 instead of only loopback.

  1. On the VPS verify:
sh
ss -ltnp | grep 3389

Now external clients can connect to 200.1.1.1:3389 and the SSH server will forward traffic back through the Pi to your home PC. See a practical how‑to for the -R approach and GatewayPorts notes: https://devhops.ru/windows/network/rdp/ssh_tunnel/.


Firewall, iptables and sysctl (VPS)

Your current iptables rules are too narrow and might be mismatched; revise like this (adjust source (-s) to a single client IP or leave open if you expect many clients):

Accept inbound RDP to VPS (allow NEW/ESTABLISHED):

sh
iptables -I INPUT -p tcp --dport 3389 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -I OUTPUT -p tcp --sport 3389 -m conntrack --ctstate ESTABLISHED -j ACCEPT

If you must restrict to a single remote IP (replace x.x.x.x):

sh
iptables -I INPUT -s x.x.x.x -p tcp --dport 3389 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -I OUTPUT -d x.x.x.x -p tcp --sport 3389 -m conntrack --ctstate ESTABLISHED -j ACCEPT

If you keep the SSH forward listening only on 127.0.0.1 and want external clients to reach it, you can DNAT incoming traffic to the loopback (less preferred than using -g):

sh
# enable forwarding for DNAT to work
sysctl -w net.ipv4.ip_forward=1

# DNAT incoming public:3389 to local 127.0.0.1:3389 (where ssh is listening)
iptables -t nat -A PREROUTING -p tcp -d 200.1.1.1 --dport 3389 -j DNAT --to-destination 127.0.0.1:3389

# make sure INPUT accepts the redirected packets
iptables -I INPUT -p tcp -d 127.0.0.1 --dport 3389 -j ACCEPT

Notes and warnings:


Troubleshooting and verification commands

Run these in order to find what’s blocking the forwarding:

  • Is VPS listening where you expect?
sh
ss -ltnp | grep 3389
  • Does the VPS interface have 200.1.1.1?
sh
ip addr show
  • Do incoming packets reach the VPS?
sh
sudo tcpdump -n -i eth0 'tcp port 3389' # adjust interface name
  • Does ssh report problems with forwarding?
sh
ssh -vvv -N -L 0.0.0.0:3389:192.168.0.20:3389 user@10.10.0.2

Look for messages about “local forwarding listening on …”, or warnings that forwarding is disabled by the server.

  • Test from VPS itself:
sh
telnet 127.0.0.1 3389 # does the local forward accept connections?
  • Test from outside:
sh
telnet 200.1.1.1 3389
# or on Windows: mstsc /v:200.1.1.1:3389
  • Check iptables counters:
sh
iptables -nvL
iptables -t nat -nvL

Common diagnostics:

  • If ss shows the listener on 127.0.0.1 only, use -g or bind to 0.0.0.0 (or change to -R + GatewayPorts).
  • If tcpdump shows SYN packets arriving but no reply, either the SSH process isn’t listening on that interface or iptables is dropping replies.
  • If ssh -vvv shows “Warning: remote port forwarding failed”, read the server sshd_config for AllowTcpForwarding/GatewayPorts.

Sources


Conclusion

You’re close: RDP through your VPS via SSH will work once the VPS actually accepts external connections on the forwarded socket and the SSH server allows forwarding. In practice that means enabling AllowTcpForwarding on the SSH server, starting the forwarding on the VPS with -g (or using a reverse -R with GatewayPorts yes on the VPS), and opening the correct iptables ports (or using DNAT + net.ipv4.ip_forward). After those changes confirm the VPS shows a listener on 200.1.1.1:3389 and the RDP client will connect through the SSH tunnel to 192.168.0.20:3389.

Authors
Verified by moderation
Moderation
How to Setup RDP via SSH Tunnel VPS Raspberry Pi