DEV Community

Vishnu
Vishnu

Posted on • Updated on

WSL Port Forwarding

When you start a server in WSL, both Windows and Linux share the same local host. When using a WSL 1 distribution, if your computer was set up to be accessed by your LAN, then applications running in WSL could be accessed on your LAN as well. This isn't the default case in WSL 2.

So, in order to access the server from your local devices, you need to port forward the WSL local IP using netsh.

First, install net-tools in your linux distro.
For Ubuntu,

sudo apt install net-tools
Enter fullscreen mode Exit fullscreen mode

Next, in Windows, create network.ps1 PowerShell script file with the following content.

If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {   
  $arguments = "& '" + $myinvocation.mycommand.definition + "'"
  Start-Process powershell -Verb runAs -ArgumentList $arguments
  Break
}

$remoteport = bash.exe -c "ifconfig eth0 | grep 'inet '"
$found = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if ($found) {
  $remoteport = $matches[0];
}
else {
  Write-Output "IP address could not be found";
  exit;
}

$ports = @(5001, 19000, 19001);

for ($i = 0; $i -lt $ports.length; $i++) {
  $port = $ports[$i];
  Invoke-Expression "netsh interface portproxy delete v4tov4 listenport=$port";
  Invoke-Expression "netsh advfirewall firewall delete rule name=$port";

  Invoke-Expression "netsh interface portproxy add v4tov4 listenport=$port connectport=$port connectaddress=$remoteport";
  Invoke-Expression "netsh advfirewall firewall add rule name=$port dir=in action=allow protocol=TCP localport=$port";
}

Invoke-Expression "netsh interface portproxy show v4tov4";

Enter fullscreen mode Exit fullscreen mode

This script is taken from here, I added command to automatically ask for admin permission, when opening the script, instead of right clicking and clicking run as admin every time you run the script.

Note: The network should be a private network.

The script will ask for admin access.

The script gets the WSL IP address and then executes netsh commands to forward the connection to your Windows' local IP, which you can see by executing ipconfig in either PowerShell or Command Prompt.

The script also resets all previous forwards and at the end displays the list of ipv4 connections forwarded.

You can modify the $ports array with your commonly used ports.

Since WSL2 uses virtual network adapters, its IP address resets after every startup.

For Expo users

  • Include both ports 19000 and 19001 in the $ports array. (Don't include 19002 - dev tool server).

  • In your Android device (connected to the same network as your PC), copy exp://<your-windows-ip-address>:19000 to the clipboard.

  • Open Expo Go, "Open from Clipboard" option will appear.

Notes

  • PowerShell command to view all forwards
netsh interface portproxy show v4tov4
Enter fullscreen mode Exit fullscreen mode
  • Have a desktop shortcut for the script. It could be handy.

  • The network should be a private network.

  • If your primary purpose is to only check your website for responsive design with your mobile, there is a simple way for that in chrome. See Chrome remote debugging

References

Top comments (14)

Collapse
 
mindplay profile image
Rasmus Schultz

Almost 2 years on, and they still don't have a wsl command to open/close ports? 🤦‍♂️

I've spent a ridiculous amount of time on this and still can't get it to work. 😣

Collapse
 
mindplay profile image
Rasmus Schultz

I can't even run this script - it says it's "not digitally signed", and then sends me to an endless documentation page with absolutely nothing I can understand.

Collapse
 
mindplay profile image
Rasmus Schultz

Pardon me, it's 3 years on. 😣

Thread Thread
 
justintaddei profile image
Justin Taddei

4 years....

Collapse
 
drblack profile image
Drblack101 • Edited

Wow, what a great post, saved me lots of time and effort. I was struggling recently about exactly the port forwarding issue. Today saw your post and followed your instruction. It works perfectly. Thanks!

Collapse
 
gargamelism profile image
Gargamel

Great post, really helped me.
I would point out that I changed mine to have target port to 80, I think a common occurrence is using different ports for incoming and outgoing, maybe you can update the script to have a map from incoming to outgoing?

Collapse
 
ptraversee profile image
Pierre Traversee • Edited

That did not work for me as I have several distros and custom machines, and I do not accept to work a admin, so I adapted your script to execute the netsh part elevated and the rest as normal user. I also noted that it is not needed to install net tools if we use the command ip add, and the command bash.exe is deprecated, should use wsl.exe instead

Here is my script if it can help

$WslMachine = 'Ubuntu-20.04'
$Activity = "Forward wsl ports of $WslMachine"

$remoteip =wsl.exe -d $WslMachine /usr/sbin/ip add `| /usr/bin/grep 'eth0'

[string]$found = $remoteip -match 'inet (\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})/';

if( $found ){
$start=9
$end=$found.IndexOf("/")
$connectaddress=$found.substring($start, $end - $start)
} else{
Write-Error "The Script Exited, the ip address of $WslMachine cannot be found";
exit;
}

$ports=@(80);
$connectports=@(80)

$adminscript = "$env:programdata/wsl$env:computername/forward.ps1"

if (-not (Test-Path $adminscript)) {
New-Item -Path $adminscript -ItemType File -Force
}
Set-Content -Path $adminscript -Encoding UTF8 -Value @"

please note : replace backslashes by backticks, as backticks would not be displayed correctly here

\$connectaddress='$connectaddress'
\$ports=@($ports)
\$connectports=@($connectports)

Invoke-Expression 'netsh interface portproxy reset';

for( \$i = 0; \$i -lt \$ports.length; \$i++ ){
\$port = \$ports[\$i];
\$connectport=\$connectports[\$i];
Invoke-Expression \"netsh interface portproxy add v4tov4 listenport=\$port connectport=\$connectport connectaddress=\$connectaddress\";
}

Invoke-Expression 'netsh interface portproxy show v4tov'

start-sleep -seconds 2
"@

If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{

$arguments = $adminscript
Start-Process powershell -Verb runAs -ArgumentList $arguments -Wait 
Enter fullscreen mode Exit fullscreen mode

} else {

Start-Process powershell -ArgumentList $arguments -Wait 
Enter fullscreen mode Exit fullscreen mode

}

Invoke-Expression 'netsh interface portproxy show v4tov'

Collapse
 
timhass6 profile image
Tim Hass • Edited

Great post, thank, this script is very handy until WSL finds a way to do it as built-in or at least provide a way to set "static" ip for the wsl.
after your permission if you will, I just modified your code so it would map host port to different ports on WSL
*don't forget to enable host ports on windows firewall ;)
*install net-tools on wsl , $sudo apt install net-tools

If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))

{

$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}

$remoteip =bash.exe -c "ifconfig eth0 | grep 'inet '"
$found = $remoteip -match '\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}';

if( $found ){
$connectaddress = $matches[0];
} else{
echo "The Script Exited, the ip address of WSL 2 cannot be found";
exit;
}

$ports=@(3388,3306);
$connectports=@(3389,3306)

iex "netsh interface portproxy reset";
for( $i = 0; $i -lt $ports.length; $i++ ){
$port = $ports[$i];
$connectport=$connectports[$i];
iex "netsh interface portproxy add v4tov4 listenport=$port connectport=$connectport connectaddress=$connectaddress";
}
iex "netsh interface portproxy show v4tov4";

Collapse
 
alvinlee001 profile image
Red Pill Factory

TLDR: This post is underrated AF, WSL 2 users should save this script up as a gist.

I did not know that this issue exist, spent hours if not days trying to figure why my microservices are not reachable from one app to another.. This code saved my life, now all my services between WSL 2 and windows can communicate perfectly.

Collapse
 
davidfm profile image
DavidFM

Great! Thanks

Collapse
 
arifimran5 profile image
Arif Imran

This helped me a lot to understand this. Thanks

Collapse
 
sc7639 profile image
Scott Crossan

Thank you the powershell script worked for me. Been trying to get this working for ages

Collapse
 
mjcarnaje profile image
Michael James Carnaje

Wow, Thank you so much!!!

Collapse
 
pauloch8 profile image
Paulo Henrique

Hello! Thank you for sharing this. Is there any problem in listening to port 80? I have a Gitlab docker container running on port 80. I ran your script but it is not being reached in my local network