-
-The Windows Subsystem for Linux (WSL) is great for development. WSL gives you the functionality of UNIX with only a fraction of the resources required for a traditional VM. It also runs alongside your Windows environment, allowing you to access Windows files inside Linux. Microsoft continues to improve WSL like with the release of WSL2 in 2019
WSL2 noticeably does not share an IP address with your computer. Because WSL2 was implemented with Hyper-V, it runs with a virtualized ethernet adapter. Your computer hides WSL2 behind a NAT where WSL2 has its own unique IP. Although WSL2 can be accessed on your machine through localhost
thanks to recent updates, these ports will not be open on your LAN.
You can fix this with port forwarding. First find WSL's IP address. Open WSL and run ifconfig
or ip addr show
or hostname -I
depending on your distro.
Now open PowerShell. For every port you need to forward to your LAN, run this netsh
command in PowerShell, replacing [PORT]
and [WSL_IP]
.
netsh interface portproxy add v4tov4 listenport=[PORT] listenaddress=0.0.0.0 connectport=[PORT] connectaddress=[WSL_IP]
You can view all forwarded ports with netsh interface portproxy show v4tov4
.
The Windows firewall might block these ports. To ensure WSL ports can be reachable, you can make a new inbound firewall rule. Open PowerShell as Administrator and run the following command. Replace -LocalPort
with the list/range of ports you need.
New-NetFirewallRule -DisplayName "WSL2 Port Bridge" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 80,443,10000,3000,5000
Congrats! Your WSL ports are now reachable through your Windows computer's IP address.
However, there is a catch. WSL changes its IP on every Windows reboot. If you're looking for a one time solution, you'll need to automate this process.
We port forward WSL using a PowerShell script. Save the script below as Bridge-WslPorts.ps1
. Change $ports
to your desired ports.
$ports = @(80, 443, 10000, 3000, 5000);
$wslAddress = bash.exe -c "ifconfig eth0 | grep -oP '(?<=inet\s)\d+(\.\d+){3}'"
if ($wslAddress -match '^(\d{1,3}\.){3}\d{1,3}$') {
Write-Host "WSL IP address: $wslAddress" -ForegroundColor Green
Write-Host "Ports: $ports" -ForegroundColor Green
}
else {
Write-Host "Error: Could not find WSL IP address." -ForegroundColor Red
exit
}
$listenAddress = '0.0.0.0';
foreach ($port in $ports) {
Invoke-Expression "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$listenAddress";
Invoke-Expression "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$listenAddress connectport=$port connectaddress=$wslAddress";
}
$fireWallDisplayName = 'WSL Port Forwarding';
$portsStr = $ports -join ",";
Invoke-Expression "Remove-NetFireWallRule -DisplayName $fireWallDisplayName";
Invoke-Expression "New-NetFireWallRule -DisplayName $fireWallDisplayName -Direction Outbound -LocalPort $portsStr -Action Allow -Protocol TCP";
Invoke-Expression "New-NetFireWallRule -DisplayName $fireWallDisplayName -Direction Inbound -LocalPort $portsStr -Action Allow -Protocol TCP";
If your WSL distro doesn't have ifconfig
, set the variable $wslAddress
with another command like ip addr
or hostname
.
If you have multiple WSL distros, make sure to set your default so bash.exe
will execute under the correct WSL. You can list and set distros with wslconfig /l
and wslconfig /s <name>
We can now run this script either on demand or through a scheduled task.
The command below can be run as administrator. Replace [PATH_TO_SCRIPT]
with the directory of the script, like C:\Users\John\Documents
.
powershell.exe -File "[PATH_TO_SCRIPT]\Bridge-WslPorts.ps1"
Not only does powershell.exe
run in PowerShell and cmd, but also in WSL. Therefore you can try running this in WSL's .bashrc
to open ports on launch, just as long as you always run WSL as administrator.
Rather than running the script after every reboot, we can rely on a Windows Task to run the script automatically. Since WSL changes IP during reboots, we'll trigger the task upon logon.
Create the task by running the following commands in PowerShell as administrator. Replace [PATH_TO_SCRIPT]
with the absolute directory of the script, like C:\Users\John\Documents
. Now, ports will be forwarded always to the correct WSL IP across reboots.
$a = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-File `"[PATH_TO_SCRIPT]\Bridge-WslPorts.ps1`" -WindowStyle Hidden -ExecutionPolicy Bypass"
$t = New-ScheduledTaskTrigger -AtLogon
$s = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$p = New-ScheduledTaskPrincipal -GroupId "BUILTIN\Administrators" -RunLevel Highest
Register-ScheduledTask -TaskName "WSL2PortsBridge" -Action $a -Trigger $t -Settings $s -Principal $p
If you need to change the port list later on, feel free to change $ports
and rerun the script using the command above. The task will also use the updated script.
The script's output window will be hidden when running. If you want logs, add to the top of the script Start-Transcript -Path "C:\Logs\Bridge-WslPorts.log" -Append
. This will record all logs to the file passed in.
Now, you won't have to think about WSL port forwarding every time you restart your PC!