Reputation: 1340
I've been tinkering around with WSL-2 for a while now and don't exactly understand how traffic is routed between the host and WSL-2 dist.
In some sources it seems like all ports used by WSL-2 automatically become available to the host machine. Such as in this tutorial by Microsoft.
Similarly I managed to host a Jupyter instance which is available directly on my host machine through localhost:8888
.
However, when trying other services, such as ssh (also tried on a non-standard port) the port does not automatically become available through localhost and I have to use the IP address assigned to my WSL distro (the one from wsl hostname -I
)
To make the services available through localhost I found this portforwarding script, which worked. But I would like to understand why it was needed.
Why is port forwarding needed for some services, but not all?
Upvotes: 68
Views: 169072
Reputation: 55
I will leave my solution for the issue with WSL port forwarding to windows, what happened to me. After WSL update I had problem with accessing anything what was hosted in WSL via localhost:PORT from my windows system. I checked the .wslconfig file and recognized that I had networkingMode set to mirrored. I changed it to NAT and restarted WSL VM and port forwarding started to work again.
Not sure if update changed this configuration or I made it myself in the past, but if you ever have problems with connecting to WSL districution, its good to check your wsl.conf or .wslconfig files.
Upvotes: 0
Reputation: 781
I tried everything in this thread to forward to port 50111
, which I was doing without issue on Windows 10. I could only connect to it by using the wsl address directly.
Get your hostname:
<WINDOWS CMD PROMPT>$ wsl.exe hostname -I
172.20.48.194 172.17.0.1
For this example, I will use my host IP:172.20.48.194
, remember to substitute your host IP.
Add a rule in C:\Windows\System32\drivers\etc\hosts
172.20.48.194 wsl
<WINDOWS CMD PROMPT>$ curl http://localhost:25001
--- WORKS: got expected output
<WINDOWS CMD PROMPT>$ curl http://localhost:50111
curl: (7) Failed to connect to localhost port 50111 after 2208 ms: Could not connect to server
Lesson: try other port numbers. There is some information out there referring to ports past 50000 as ephemeral ports used mostly for output.
This was all without any port forwarding. However, if I want to refer to my own IP (instead of localhost), I get this:
curl http://192.168.1.100:25001
curl: (7) Failed to connect to 192.168.1.100 port 25001 after 2035 ms: Could not connect to server
To fix this I needed to do 2 things:
netsh interface portproxy set v4tov4 listenport=25001 listenaddress=* connectport=25001 connectaddress=wsl
Wait for a little bit before testing less than 2-3 minutes at most.
After opening the port:
<WINDOWS CMD PROMPT>$ curl http://192.168.1.100:25001
--- WORKS: got expected output
So:
WSL
via localhost
on your machine with no configuration. But there seem to be ports that do not automatically work, avoid them.Upvotes: 0
Reputation: 1784
Why is the port forwarding needed for wsl2? After I watched this youtube video, and read through this thread, I learned that wsl1 used to just work, and port forwarding was not necessary; but beyond that I haven't gone too in far depth (something to do with wsl2 being hyper-v now).
In any case, I created this powershell script, below, inspired by this famous script.
I was trying to port forward the Expo port, to be able to run my react native app on my physical android device by connecting to my windows pc's wifi network address. The port exposed by expo start --dev-client
is 8081
so that is what is in the script below (but any port could be used).
echo "Running WSL Port Forward Script...";
$wslAddrTxt = bash.exe -c "ip addr | grep -Ee 'inet.*eth0'"
$found = $wslAddrTxt -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
if( !$found ){
echo "The Script Exited, the ip address of WSL 2 cannot be found";
exit;
}
$wslAddr = $matches[0];
$PCWifiNetworkAddr = (Test-Connection -ComputerName (hostname) -Count 1 | Select -ExpandProperty IPv4Address).IPAddressToString;
#[Ports]
#All the ports you want to forward separated by coma
$ports=@(8081);
$ports_a = $ports -join ",";
for( $i = 0; $i -lt $ports.length; $i++ ){
$port = $ports[$i];
# This deletion and re-adding below is required, even if they were the same as before.
# This is because the rules applied by the netsh command don't seem to apply after the PC is rebooted.
# Even if you run `netsh interface portproxy show all` and it shows the correct rules, it doesn't seem to work after the PC is rebooted, unless you delete and re-add the rule.
# NOTE: The above comment doesn't seem to be a problem if the listenaddress omitted entirely, or is set to a static value of "0.0.0.0" (which means all IPv4 address for the PC)
# Omitting the listenaddress entirely sets its value to "*", or, according the documentation, "the local computer" https://learn.microsoft.com/en-us/windows-server/networking/technologies/netsh/netsh-interface-portproxy#add-v4tov4.
netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$PCWifiNetworkAddr;
netsh interface portproxy add v4tov4 listenport=$port listenaddress=$PCWifiNetworkAddr connectport=$port connectaddress=$wslAddr;
Write-Output ("Successfully forwarded WSL Port " + $wslAddr + ":" + $port + " to PC Host Port " + $PCWifiNetworkAddr + ":" + $port);
}
The above code:
An odd thing about the listenaddress:
If listenaddress
is set to a specific ip address, then the port forward rule will stop working after reboot, even though running netsh interface portproxy show all
command shows that the rule still exists. If the rule is deleted and re-added again though, then it starts working again.
If the listenaddress
is, instead, set to 0,0.0.0
(or if listenaddress
is omitted entirely) then rebooting is no longer an issue that causes the rule to stop applying. From a quick online search, it seems the reason is more or less that the netsh interface portproxy
command has a few quirks, in some scenarios; but I'm still not sure of the cause, exactly.
I'm also not sure if setting listenaddress
to 0.0.0.0
(which means all addresses), or omitting listenaddress
entirely, is "bad". Most of the tutorials I've seen set the listenaddress
to 0.0.0.0
(microsoft documentation calls it setting it to "the local computer").
Alas, I felt there were several reasons it would be nice to run this script, automatically, on Startup:
netsh
not persisting rules with specific listenaddress
defined was annoying to deal with.I put the above script in a powershell file, then created a windows Task Scheduler task to run it on startup (or user logon, rather, as it was easier). Here's how I configured the Task:
C:\projects\wslPortForwardStartup.ps1
)Task Scheduler
, and select itWSL Port Forwarding Startup Task
powershell
(note: do not put the path to your powershell script here)-command C:\projects\wslPortForwardStartup.ps1
netsh interface portproxy show all
to check that the port forwarding rule hasn’t already been applied.Running WSL Port Forward Script...
netsh interface portproxy show all
command.WSL Port Forwarding Startup Task
(or whatever you named it) and double click on itOf course, I also had to open port 8081 on windows firewall, to allow inbound connections, if I wanted to connect to my PC's port 8081 over my home wifi network. Here's a quick powershell script I made to do that (though opening the windows firewall settings is almost just as easy).
Note, this firewall script below only needs to be run/applied once (and you may need to run as administrator):
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort 8081 -Profile Private -Action Allow -Protocol TCP
Upvotes: 2
Reputation: 374
From the official documentation as of May 2024
https://learn.microsoft.com/en-us/windows/wsl/wsl-config
It seems that port forwarding is enabled by default. Therefore, any open port in the WSL-2 VM is accessible from the Host machine via 'localhost'
If you wish to disable this feature then you have to create a .wslconfig
file under your %USERPROFILE%
folder (typically C:\Users\youruser
) and write down the following
[wsl2]
localhostForwarding = false
Upvotes: 9
Reputation: 1225
There may be conflicts between netsh interface portproxy
and the WSL "magic" port forwarders attempting to start listening on the same (TCP) port, according to output of netstat -an | findstr ":PORT_NUMBER"
.
Let's say a Linux service is started. It listens to a TCP port 443. WSL wires the Windows's localhost:443
to the Linux service's port 443. This is visible to netstat
showing a listener on localhost:443
that is not wired as a connection.
PS C:\WINDOWS\system32> netstat -an | findstr ":443"
[...]
TCP 127.0.0.1:443 0.0.0.0:0 LISTENING
Attempting to forward from any other network interface's port 443 to localhost:443
with netsh
does not show an error but is seen in netstat
as an unexpected listener on a different TCP port. I consider this a bug of netsh interface portproxy
.
PS C:\WINDOWS\system32> netsh interface portproxy set v4tov4 listenport=443 listenaddress=0.0.0.0 connectport=443 connectaddress=127.0.0.1
PS C:\WINDOWS\system32> curl.exe -iskS https://10.X.Y.Z/
curl: (7) Failed to connect to 10.X.Y.Z port 443 after 2022 ms: Connection refused
PS C:\WINDOWS\system32> netsh interface portproxy show v4tov4
Listen on ipv4: Connect to ipv4:
Address Port Address Port
--------------- ---------- --------------- ----------
[...]
0.0.0.0 443 127.0.0.1 443
I believe I caught netsh interface portproxy
red-handed after seeing a TCP connection from an unexpectedly random TCP port on the unexpected interface 127.0.0.1
to 127.0.0.1:443
,
PS C:\WINDOWS\system32> netstat -an | findstr ":443"
[...]
TCP 127.0.0.1:443 0.0.0.0:0 LISTENING
TCP 127.0.0.1:63916 127.0.0.1:443 TIME_WAIT
If the above theory of a bug in netsh
is correct, I can understand why my earlier intuitive separation of port numbers worked. That is, the Linux service can be configured to listen to a different port number such as 10443, and then the Windows side can be set up to forward from port 443 to localhost:10443
.
I guess the same conflict might have caused the original post's situation if a netsh interface portproxy
forwarding is set up before starting the Linux service.
Update. It seems my current woes are due to a corprorate-enforced firewall manager on my laptop. My answer above is not credible.
Upvotes: 1
Reputation: 499
When you run WSL-2, a machine like a vitural machin run on your window device. Windows will create a local network, same your LAN, and connect WLS-2 to this network.
5: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 inet 172.27.5.124/20 brd 172.27.15.255 scope global eth0
Ethernet adapter vEthernet (WSL):
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::1532:a8ea:6b34:8df2%73
IPv4 Address. . . . . . . . . . . : 172.27.0.1
Subnet Mask . . . . . . . . . . . : 255.255.240.0
Default Gateway . . . . . . . . . :
WSL-2 and Windows device on a same network, and WSL-2 not connect to your LAN.
My solution (use port forwarding on Windows)
Open terminal with Admin on Windows, and run script:
netsh interface portproxy set v4tov4 listenport=8888 listenaddress=0.0.0.0 connectport=8888 connectaddress=$(wsl hostname -I)
Upvotes: 49
Reputation: 71
Following these steps helped me connect to my ports locally on Windows:
sudo apt install net-tools
type ".\script.ps1" | powershell.exe -c -
. This is to run the file. Right-clicking the file to "Run with powershell" won't work.netsh interface portproxy show v4tov4
Upvotes: 7
Reputation: 1340
My confusion came from firewall issues with WSL-2.
What I have found is:
localhost:<port>
netstat interface portproxy
or other portforward tools using the ip address of the WSL instance.The firewall did not allow acces to the WSL ports by just listing the ports. I had to specifcally select the iphlpsv
service (IP Helper service) in my firewall rules to allow traffic through to the WSL instance.
Upvotes: 32