63

I have Windows 11 with WSL2 (Ubuntu) installed on it.

I've setup a gdb listener server on my Windows localhost and want to access it from Wsl2, but it seems my Windows machine and WSL are using different network adapters.

>ipconfig

Windows IP Configuration

Ethernet adapter vEthernet (Default Switch):

Connection-specific DNS Suffix . : Link-local IPv6 Address . . . . . : fe80::1114:bb:d0ad:93f8%18 IPv4 Address. . . . . . . . . . . : 172.29.192.1 Subnet Mask . . . . . . . . . . . : 255.255.240.0 Default Gateway . . . . . . . . . :

Ethernet adapter vEthernet (WSL):

Connection-specific DNS Suffix . : Link-local IPv6 Address . . . . . : fe80::897:849a:5fed:1c6e%52 IPv4 Address. . . . . . . . . . . : 172.21.128.1 Subnet Mask . . . . . . . . . . . : 255.255.240.0 Default Gateway . . . . . . . . . :

My server is actively listening on the 8888 port and is accessible on Windows but not on Ubuntu/WSL.

I've opened the 8888 port both from the Windows firewall and Ubuntu firewall

What is the solution?

NotTheDr01ds
  • 28,025

5 Answers5

63

localhost doesn't work because WSL2 is running with a virtual network (vNIC) created by the Windows Virtual Machine Platform (a subset of Hyper-V). Inside WSL2, localhost is the address of the vNIC.

WSL2 does set up a virtual router on the Windows host to allow connectivity to both the outside world as well as the Windows host. You can see this via:

ip route

The "default via" address is the address to use for the Windows host.

You could parse it from the above, or from /etc/resolv.conf, but WSL also sets up a convenience mDNS, the .local domain, using the Windows "computer name", which is also used as the hostname of the WSL instance.

Accessing it is by concatenating $(hostname) with .local.

Try:

ping "$(hostname).local"

Or, if ICMP is blocked (seems so on new Windows 11 installs), use netcat. It's available by default in the WSL Ubuntu installation, but may need to be installed in other distributions like openSUSE:

nc -zv "$(hostname).local" <portnumber>

Reference: Access a localhost running in Windows from inside WSL2? answer by NotTheDr01ds.

harrymc
  • 498,455
15

As of the 2.0.0 release of WSL2, there are two good options for this (and several not-as-good). Copying from my Stack Overflow answer on the topic 1:

Short(ish) answers:

  1. NAT (default) WSL2 networking with mDNS

    Concatenating your WSL2 hostname (or the equivalent command/function in your programming/language environment) with ".local" (the host mDNS name) should 2 get you access. For example, in Bash try:

    ping "$(hostname).local"
    

    Or, let's say you are trying to access MongoDB from Python, as in this question:

    import socket
    server = f'{socket.gethostname()}.local'
    host = f'mongodb://{socket.gethostname()}.local'
    
  2. Mirrored Mode WSL2 Networking

    Note: Requires Windows 11 23H2 or later

    In Mirrored mode, localhost should "just work". To enable:

    • 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.

More explanation:

Option 1: NAT with mDNS

The default network mode of WSL2 is NAT'd behind a virtual Hyper-V switch. Up until recently, this was the only networking mode for WSL2. In this mode, WSL2 is running with a virtual network (vNIC) that is created by the Windows Virtual Machine Platform (a subset of Hyper-V). Inside WSL2, localhost is the address of the vNIC rather than that of the Windows host.

In this mode, using the mDNS name for the Windows host 3 is usually the easiest solution.

mDNS has been a feature of WSL2 for a while now. Concatenating your WSL2 hostname (or the equivalent command/function in your programming/language environment) with ".local" should get you access.

As mentioned above, from Bash, try:

ping "$(hostname).local"

For instance, if your hostname is "MyComputer", then the mDNS should be MyComputer.local.

If ICMP is blocked (as it seems to be on new Windows 11 installs), or if you want to test the connection to the actual port, then use netcat instead of ping. It's available by default in the WSL Ubuntu installation, but may need to be installed in other distributions like openSUSE:

nc -zv "$(hostname).local" <portnumber>

See also "Other NAT/mDNS considerations" 2.

Option 2: Mirrored Network Mode

Release 2.0.0 of WSL2 introduced a new Mirrored networking mode that can simplify many of the network access issues.

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.

Because of this, localhost is routing through the mirrored Windows loopback adapter.


Footnotes:

1 Duplicated (and new) information

  • While I hate to duplicate part of the currently accepted answer, as noted, the currently accepted answer was based on my Stack Overflow version in the first place. In fairness, @harrymc did ask in the comments if I'd like to repost it here, but I declined at the time.

  • Over the years, though, I've added new information to the SO version which hasn't made it over to this SU question. Given the (now) massive changes accumulated, I feel the information needs to be here as well.

  • The SO version is technically off-topic and currently closed there. This SU question is on-topic and should be the canonical question where new information on the topic is posted.


2 Other NAT/mDNS considerations

  • mDNS is reliant on the Windows host to resolve the name. If you have changed your /etc/resolv.conf under WSL, then this will likely not work.

  • Remember to open any necessary firewall ports. WSL2 is considered a separate network from that of the Windows host. Windows will consider network connections from WSL2 to be coming from an external source. (Credit to @RamilGilfanov for a comment pointing this out)

    The first time a connection is made from WSL2 to a particular port, Windows Defender (if that is your firewall) will typically display a dialog asking if you want to grant access. However, in my experience, this dialog often gets buried under the main window due to timing of mouse-clicks, keyboard, etc., so it's easy to miss.

  • Remember to have your Windows service accept connections from remote hosts.

    Many servers are configured by default to bind to localhost/127.0.0.1. Because WSL2 appears to Windows as a remote network, you'll typically need to update your configuration to bind to 0.0.0.0 or a specific address.

    Note that, since the address for WSL2 changes after each reboot, it can be difficult to update your configuration each time. If at all possible, use 0.0.0.0 unless there are security concerns. Since WSL is designed for development rather than production, this shouldn't be an issue.


3 Technically, this is the IP address of the virtual switch that WSL2 uses to interface with Windows and the outside world.

You can see this via:

ip route

This is the address you need to use for the Windows host.

You could, of course, parse it from the route (or, as in an earlier answer, from /etc/resolv.conf), but since WSL sets up the convenience mDNS (the .local domain) it's easier to just use that.

NotTheDr01ds
  • 28,025
7

Further elaborating on the answer from @harrymc and @NotTheDr01ds:

Generally, you can contact Windows services from wsl2 command line using "$(hostname).local" as the host name. If such connections seem to be blocked, you can try the following:

  • Check whether Windows Firewall blocks the traffic. One easy check would be to turn it off for a few seconds and repeat the test. If that works, add appropriate Firewall rules.

  • Issue nslookup "$(hostname).local". This will give you a bunch of IPs. By default, the first one will be used, but that might not be the one which works. Try the other ones as well. If you find one that works, you can tailor a short script for your own system which will always return the correct IP.

malamut
  • 261
5

"Localhost" always refers to system itself. When you're running a host OS and a virtualized OS, you're running 2 systems, both of which refer to themselves as "localhost". So you can never access "localhost" of another system, you need to use its external IP.

In your case if you want to access from the Ubuntu system a service that's running on your host Windows listening to port 8888, you have to access 172.29.192.1:8888. Only the system that's actually offering the service must listen to the port and allow new incoming connections through that port.

Because the Ubuntu is a separate system, you won't have anything there listening to port 8888 unless you install a service that listens to that port.

Peregrino69
  • 5,004
5

Other answers have solved this by using "$(hostname).local".

However, for my case at least (Ubuntu 23.10 on WSL 2), running the command ping "$(hostname).local" errored:

ping: <myhostname.local: Name or service not known

I managed to fix this by installing libnss-mdns, letting the ping command run normally. (Run sudo apt install libnss-mdns to install on Ubuntu)

Source for the fix: https://github.com/microsoft/WSL/issues/10077#issuecomment-1736181588