My script to set up port forwarding to WSL 2 SSH fails

All we need is an easy explanation of the problem, so here it is.

I used to be able to connect by using a SSH script and setting the IP to 127.0.0.2, but now it no longer works on every startup. I am not sure why. I tried localhost or 127.0.0.1, but it doesn’t work. I can access websites on localhost. How do I get the port number and IP I can connect to through SecureCRT on my own machine that hosts the WSL2?

try {
## Port forward WSL virtual machine ports to host firewall for remote access
## !! this script must be run as Administrator !!
##  powershell -executionpolicy bypass -file "c:\docker\WSL-portproxy.ps1"

## ip -o -4 -f inet addr show eth0 | awk '{ split($4, ip_addr, "/"); print ip_addr[1]; }'
##   print out is "4:  eth0  inet  172.20.x.x/20  brd  ..." string
$remoteport = bash.exe -c "ip -o -4 -f inet addr show eth0";
$remoteport = ($remoteport -split "\s+")[3];
$remoteport = $remoteport.substring(0, $remoteport.LastIndexOf("/"));
$found      = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
if(!$found){
  echo "WSL ip address not found";
  exit;
}
echo "WSL ip address $remoteport";

# Port forwards from WSL virtual machine to Win10 host firewall
# Bind a specific host ip addr or use 0.0.0.0 default
[email protected](2222);
$addr='127.0.0.2';

# Remove firewall exception rules, add inbound and outbound rules
$ports_a = $ports -join ",";
echo "Firewall inbound/outbound rules";
iex "Remove-NetFireWallRule -DisplayName 'WSL Firewall Unlock' ";
iex "New-NetFireWallRule -DisplayName 'WSL Firewall Unlock' -Description 'Remote access to WSL services' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL Firewall Unlock' -Description 'Remote access to WSL services' -Direction Inbound  -LocalPort $ports_a -Action Allow -Protocol TCP";

for( $i = 0; $i -lt $ports.length; $i++ ){
  $port = $ports[$i];
  echo "portproxy ${addr}:${port} to ${remoteport}:${port}";
  iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
  iex "netsh interface portproxy add    v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport";
}

    # Do your script's stuff
}
catch
{
    Write-Error $_.Exception.ToString()
    Read-Host -Prompt "The above error occurred. Press Enter to exit."
}

Was able to set it up by using this, but it no longer works.

I get the following error:

C:\Users\admin\Downloads\f.ps1 : System.Management.Automation.RuntimeException: You cannot call a method on a
null-valued expression.
   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception
exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
At line:1 char:91
+ ... tionPolicy -Scope Process Bypass }; & 'C:\Users\admin\Downloads\f.ps1'
+                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
    + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,f.ps1

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

How do I get the port number and IP I can connect to through SecureCRT on my own machine that hosts the WSL2?

Perhaps I’m massively misunderstanding your question, but this should be very straightforward and should not require a script at all.

If you are connecting:

  • From SecureCRT on the machine that hosts WSL2
  • To a WSL2 instance on that machine

Then WSL2 provides a feature known as "localhost forwarding" (since build 18945, according to this website.

The script you are using is apparently very old, not just because you shouldn’t need it any longer, but because it uses the bash.exe command, which was superseded by the much-more-flexible wsl.exe several years ago as well. For a while, Microsoft listed bash.exe as a "historical command", but in the latest doc it is labeled as deprecated.

Anyway, regarding your core question, per the WSL doc:

If you are building a networking app (for example an app running on a NodeJS or SQL server) in your Linux distribution, you can access it from a Windows app (like your Edge or Chrome internet browser) using localhost (just like you normally would).

However, if you are running an older version of Windows (Build 18945 or less), you will need to get the IP address of the Linux host VM (or update to the latest Windows version).

That applies not just to "building an app", but also to existing apps/services such as SSH.

What it means is that, when you attempt to connect to a localhost port in Windows, if the port isn’t bound by an app/service in Windows itself, then it automatically attempts to forward the connection to that port in WSL2 (any and all instances, since they share the same networking stack).

So really, if your WSL2 instance is running SSH on port 2222, then you should just be able to connect from SecureCRT to localhost:2222 without any additional effort.

There are a few reasons why this might not work:

  • If you have a %userprofile%\.wslconfig file with localhostForwarding explicitly set to false (unlikely)

  • Localhost forwarding is known to stop working whenever Windows hibernates. Hibernation can also be unknowingly triggered by the "Fast Startup" option, which is the default in Windows. See my answer on Stack Overflow for more information.

Other than that, it (again) should work without any complicated forwarding scripts.

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply