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
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";
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
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
Top comments (14)
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. 😣
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.
Pardon me, it's 3 years on. 😣
4 years....
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!
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?
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"))
{
} else {
}
Invoke-Expression 'netsh interface portproxy show v4tov'
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";
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.
Great! Thanks
This helped me a lot to understand this. Thanks
Thank you the powershell script worked for me. Been trying to get this working for ages
Wow, Thank you so much!!!