Sitemap

SSH Tunnel in Windows and WSL2

alex_ber
3 min readApr 24, 2025

If you set up an SSH tunnel in one terminal and need to close it from another, here’s how to do it on Windows:

Note:

1. ssh under Windows is available on Windows 10 and later as builtin.

2. While I assume you’re not using putty.exe, but ssh the main idea is the same, just change ssh to putty.

1. Find the SSH Tunnel Process

List processes using your local tunnel port (replace 3333 with your port if needed):

netstat -ano | findstr :3333

Sample output:

 TCP    0.0.0.0:3333           0.0.0.0:0              LISTENING       9208
TCP 127.0.0.1:3333 127.0.0.1:49277 ESTABLISHED 9208
TCP 127.0.0.1:3333 127.0.0.1:49278 ESTABLISHED 9208

Here, 9208 is the process ID (PID).

2. Identify the Process

Check which program is running with that PID:

tasklist /FI "PID eq 9208"

Sample output:

Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
ssh.exe 9208 Console 1 17,928 K

3. Kill the SSH Tunnel Process

Terminate it by PID (this will close your tunnel):

taskkill /PID 9208 /F /T

That’s it!
Your tunnel is now closed. Remember to substitute the port and PID numbers with the ones from your own environment.

Appendix

Script to open ssh tunnel should look something like

@echo off
echo [INFO] Starting SSH tunnel...
ssh -i dev-key.pem ^
-N ^
-L 0.0.0.0:3333:dev-rfp-generator.cluster-cibapoyisuig.us-east-2.rds.amazonaws.com:5432 ^
-o ServerAliveInterval=60 ^
-o ServerAliveCountMax=3 ^
hadar_gabbay@bastion.dev.kinesso.ninja

echo [WARN] Tunnel disconnected. Reconnecting in 3s...

Note:
1. SSH will send a keepalive every 60 seconds (-o ServerAliveInterval=60). If the server misses 3 in a row ( -o ServerAliveCountMax=3), the client closes the connection and, in your script, tries to reconnect.

2. Using 0.0.0.0 is crucial if you want to use this SSH Tunnel opened in Windows (as HOST OS) in Docker Container under WSL2. Then postgresql://user:password@localhost:3333/db-namelocalhost:3333 (regular way on Windows to use SSH Tunnel) will not work, but
postgresql://user:password@host.docker.internal:3333/db-name will. This should be accompanied with binding to 0.0.0.0 in opening SSH tunnel.
If you do not have use to use SSH Tunnel from WSL2 you can use putty like this:

@echo off
set key="your-key.ppk"
START /B putty.exe -ssh username@domain.com -i %key% -L 3333:db-name.cluster-cibapoyisuig.us-east-2.rds.amazonaws.com:5432 -m mie_tunnel.sh

where mie_tunnel.sh will be run on the server as is looks like something like this:

export TERM="xterm"
export TMOUT=86400
readonly TMOUT
while :; do echo "APP - POSTGRES"; sleep 5; done

Just to print something on the screen on Windows in order to see that SSH Tunnel is still opened.

Note:
1.
putty.exe doesn’t support -o ServerAliveInterval and -o ServerAliveCountMax natively.
2. You should use
PPK, not PEM format with putty.

Caveat

In order to use ssh your need to set permission for your-key.pem in very specific narrow way. They should look something like:

Where SYSTEM is SYSTEM user (this is fine). Alexander Berkovich is Windows account user (type echo %USERNAME% in CMD to find out yours), Administrators are also fine.

NO Users or Authenticated Users!

In order to remove Users you should Disable inheritance first:

After clicking on “Disable inheritance” button click on “spread” inherited settings.

Optionally, you can also change owner to yourself.

Once you will finish with you can remove Users.

--

--

alex_ber
alex_ber

Written by alex_ber

Senior Software Engineer at Pursway

No responses yet