Cannot communicate with Windows localhost from WSL2

Cannot communicate with Windows localhost from WSL2

I have an application running on Windows on localhost (127.0.0.1) port 8545. My goal is to be able to communicate with this application from within WSL2. However, whenever I try to access the address from within WSL2 I get a connection timeout.

Here is a summary of what I have tried:

  1. disabled the Windows defender firewall for WSL according to the answer here:

    WSL2 connect to host without disabling the windows firewall

  2. found what my host’s (windows) local IP is by running this command in a WSL terminal (returns 172.22.144.1):

    echo $(ip route list default | awk '{print $3}')

  3. pinged the running Windows application from a WSL terminal using:

    nc -zv 172.22.144.1 8545

After step 3 nothing happens for a while and then I get a connection timed out error.

From a Windows powershell I am able to successfully ping the same application like this:

Test-NetConnection 127.0.0.1 -p 8545

Does anyone know what the solution could be? What do I need to do to allow WSL2 to communicate with Windows localhost? I am using windows 10 home and WSL2.

答案1

As of release 2.0.0 of WSL2, there is a new networking feature available that circumvents the need for almost all of my original answer. That said, both techniques are still useful. I'm revising this answer to list the new mode ("Mirrored Networking") first.

Mirrored Mode

Note: Only available in release 2.0.0 of WSL2 with Windows 11 22H2 or higher

In this mode, the Windows network interfaces are mirrored into WSL2. When you run ip addr, for example, you'll see (mostly) the same interfaces as when you run ipconfig /all from PowerShell/CMD.

As a result, this negates the need for the three items mentioned in the NAT section:

  • localhost can be used from WSL2 to connect to the loopback address for Windows
  • Firewall rules between Windows and WSL2 are not needed 1, since Windows will see WSL2 traffic as "local"
  • The bind address for your Windows service can still be the localhost address, rather than 0.0.0.0
To enable Mirrored mode:
  • Add the following to your <windows_user_profile>/.wslconfig:

    [wsl2]
    networkingMode=mirrored
    
  • Exit your WSL distribution

  • Run wsl --shutdown from PowerShell then restart WSL

You should then be able to access services running in Windows via localhost.

Note that when running in Mirrored mode, mDNS will not work.

NAT (default/original) Mode

To access a network service/application running on the Windows host from inside WSL2, you need to do three things:

  • *Configure the service to listen on the correct Windows network interface (not localhost), a.k.a. the "bind address".

  • Open the necessary firewall port(s)

  • Use the correct address from WSL2 (again, not localhost)

For you, the OP of this question, it appears that you already had the 2nd and 3rd correct, and only need to change the first.

More detail provided below on each of these:

Bind address

Many applications or services default to binding to localhost, which (obviously) means that you can only connect to them from the host on which the service is running. Because WSL2 runs on a "separate network", you won't be able to access the a service that in Windows that is listening only on localhost. As @DanielB mentioned, you'll probably want to bind to 0.0.0.0 (for IPv4) and/or :: (for IPv6) to listen on all interfaces.

The method of configuring the service will, of course, vary for different applications, but usually you'll find the setting labeled something like "Bind Address", "Listen On", or something similar.

Make sure to restart the application/service after changing this setting.

Firewall configuration

By default, Windows Defender Firewall (and others) will block incoming connections to the host from another network. Since we've already established that WSL2 is running in a separate network, you'll need to open a firewall port for your service.

The OP of this question has disabled the firewall entirely when coming through the WSL2 network interface, which is fine. You can also do this selectively from PowerShell (in an Administrative shell) with something like:

New-NetFirewallRule -DisplayName "Spring App Testing" -InterfaceAlias "vEthernet (WSL)" -Direction Inbound -Protocol TCP -LocalPort 8545 -Action Allow 

Of course, you can drop either:

  • the InterfaceAlias, in which case it will open 8545 from all networks
  • or the LocalPort, in which case it will act like the "disable" option above and always accept incoming traffic from the WSL network interface.

Finding the correct Windows address to use from WSL2

There are several methods (and IP addresses) you can use. The easiest way is simply to use the IP address of the Windows host, if you know it. However, if it is dynamically assigned and changes frequently (which is, I believe, fairly unusual nowaways), then you may need to change your WSL2 code each reboot.

It's probably best, however, to use a mDNS name that will (usually) resolve correctly.

Assuming that you haven't overridden the default /etc/resolv.conf that WSL generates, this can be done by taking the Windows computer name and simply appending .local. For instance, if your computer name is bubblegum, then bubblegum.local should be the correct address.

You should find that this is the same address as found with:

echo $(ip route list default | awk '{print $3}')

If, however, you have overridden the /etc/resolv.conf (necessary in some cases due to VPNs or other networking configurations), then you may need something more complicated like:

echo $(host `hostname --long` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r')

(Credit to @ChaiAng's answer on Ask Ubuntu for this method).

However, note that it is substantially slower than mDNS.


1 Note that Mirrored mode also makes your WSL2 instance available to other devices on your network, and for this reason, there's also a new WSL2/Hyper-V firewall feature that, by default, blocks that traffic. Enabling traffic between the local network and WSL2 is a different topic.

答案2

This answer is outdated. For recent versions of Windows and WSL, check the other one by NotTheDr01ds, which covers the new Mirrored Mode.


localhost/127.0.0.1/::1 networking is special. Every computer has its own localhost. You cannot connect to other computers’ localhost over the network.

Virtual machines (like WSL 2) are considered different computers. There’s also network namespaces, which also work like different computers regarding this topic.

If you want to reach your service running on Windows from WSL 2, you must not let it bind to localhost. The “next best” thing is binding to the Hyper-V virtual network adapter for WSL, but its IP address is dynamic. You can also bind to 0.0.0.0/::, but that makes your service available on all interfaces (firewall rules still apply).

From WSL 2, you could then connect using $(hostname).local (or any of the other ways you already found to get the host IP).


There is one special exception when trying to connect to services running in WSL 2 from Windows (so the other way around): Microsoft has implemented a software solution making WSL 2 localhost listeners available from Windows (also on localhost). It is relatively unreliable.

相关内容