microsoft/WSL

[WSL 2] WSL 2 cannot access windows service via localhost:port

hzhangxyz opened this issue Β· 140 comments

Is your feature request related to a problem? Please describe.
although now windows can access wsl service with localhost:port via "localhostForwarding", but wsl cannot access windows service via localhost:port, please fix it, Thank you.

Describe the solution you'd like
When WSL 2 try to connect to localhost:port and be refused, try to connect to windows again.

I was able to use graphic applications in WSL using XMING and Export DISPLAY=:0.0

However, once I upgraded to WSL2 and switching to Export DISPLAY = 172.28.801:0 (my host#) it failed to connect

Things tried:

downloading VcXsrv
switching to another graphics application
running vcxsrv -ac from bash (command not recognized)
running vcxsrv -ac from powershell (command not recognized)
turning firewall off
My Windows 10 build: 19041.1

Here is a typical error message

QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-lw' qt.qpa.screen: QXcbConnection:
Authorization required, but no authorization protocol specified
Could not connect to any X display.

In #4106 you advise to run "vcxsrv -ac" from the bash command line and at least one user accepted that as a solution. I downloaded vcxsrv.exe from sourceforge as an .exe outside of bash, and I see no way to execute it from bash

Many thanks

gx761 commented

is there any update?

@numeric-lee that's not really solved - that's a workaround. In WSL1 you could hit:

localhost:port

From the WSL environment and that would access the windows service directly without having to:

  • Script extraction of a magic IP address
  • Disable a firewall interface which freaks people (including me) out and doesn't persist on reboot

Use cases are common including:

  • X11 Service running on windows host
  • Shared database access like postgres
  • Access docker on windows host from WSL client

A different IP address, I could live with, though I would suggest that WSL should expose it via WSL_HOST or something like it does for WSL_DISTRO_NAME, but the firewall thing is a big pain point for me. There are a lot of quite similar issues but I'm hoping this is now the central one that will get done, ideally before this gets widespread release.

Uzume commented

This is because despite the name (WSL=Windows Subsystem for Linux), WSL2 is not a Windows subsystem like WSL1 and Interix were. WSL2 is a lightweight Hyper-V-based virtual machine with its own separate network interfaces, IP addresses, etc. Localhost and 127.0.0.1 are host local references and having more than one host, they refer to different things in Windows host and Linux guest host.

WSL2 already supplies some sort of special casing including accessing the Linux guest console/login for Windows terminal access to the Linux guest and means of accessing both the Windows host and Linux guest filesystems from both sides ("9p" Linux mounts vs. IFS redirector and UNC "\wsl$"). The best solution would be to generalize this to allow a configured list of port forwarding options. Then one could forward the server socket to the Linux guest allowing the guest to then believe and refer to the server as if it were local to the Linux guest host. For security and performance reasons, it would be good to use virtual machine specific socket system like that used by wslbridge2 (hvsocket).

Another possibly simpler solution would be to come up with something that uses WSL_INTEROP sockets to create a generalized tunneling solution. I am not sure how stable they are though as they seem to depend on WSL sessions (perhaps a Windows service that opens a WSL session and sets up all the configured tunneling and then keeps the session open).

To anyone needing a workaround, run this on the Windows side:

adb -a -P 5037 nodaemon server

and this on WSL2:

adb kill-server
export ADB_SERVER_SOCKET=tcp:192.168.100.5:5037
adb devices

Replace the IP with your windows IP.

Edit: I may have commented on the wrong issue. It was one on the same error but related to Android studio.

To workaround this on selenium+chromedriver, IΒ΄m running a socat on wsl2 relaying requests to localhost:port to windows-host:port. This workaround can be used in a lot of other cases. :)

Every time that I go back to wsl2 and give it a try, the same happens again. After updating windows, I'm not able to access localhost:port. Not event using wsl internal ip:port. Looks like it is a recurrent problem. Why we need to face it every update?

Uzume commented

@andreialecu That only works for one particular service related to Android Debug Bridge.

@raelmax Yes, that is sort of what I suggesting by my comment about using WSL interop sockets. I had envisioned something with ncat (from nmap) but netcat and socat probably can also work. I thought about ncat because there should be both Windows and Linux versions available (sadly Windows Security identifies this as a "hacker tool" potential threat and quarantines it unless specifically allowed) so it was not too big of a stretch to just use pipes and depend on WSL interop to allow such to automatically cross the host-guest boundary.

What commands are you using? How do you handle the Windows host side of things? Which Linux distribution are you using that has socat or did you compile that yourself? Providing the commands you are using would be helpful. Thank you.

@jordaofranca I believe WSL1 is still available in later versions of Windows 10 but you do need to set the WSL version for each distribution (and you can set the default version for new distributions too). Obviously moving back to WSL1 is also just a workaround and not a solution.

@Uzume IΒ΄m using Ubuntu 18.04 and IΒ΄ve installed socat via apt-get. :)

My use case is as follow:

  • I need to use chromedriver(and chrome) running on Windows(host) and I need to control the chromedriver via selenium running on my Ubuntu(via wsl2).

Since I canΒ΄t update my code to access chromedriver via an IP address, he always tries access chromedriver via the localhost. So to put chromedriver to run on localhost, IΒ΄m using the following command to relay requests from LOCALHOST:PORT to WINDOWSHOST:PORT.

Command: socat -d -d TCP-LISTEN:9515,reuseaddr,fork TCP:$(cat /etc/resolv.conf | tail -n1 | cut -d " " -f 2):9516

So each request that I did from my wsl2 machine to "localhost:9515" is relayed to "ipaddress:9516". On the windows side, I just need to open the 9516 port on my firewall.

If I can help you with anything else, reach me out! :)

Uzume commented

@raelmax It seems you are not using WSL interop sockets at all and instead just using socat to forward Linux guest client (selenium) accesses to a localhost port to a Windows host IP and port (which also requires that the chromedriver server allows connections from IPs other than its own localhost).

I imagine you could have just as easily used netcat or ncat (from nmap package). Thank you, I appreciate the feedback.

still same issue as of end of March 2020 ... WSL2 [Ubuntu 18.04] on WINDOWS 10 Pro cannot access a defined DISPLAY (no matter how I define it if via localhost:0, or the WSL2 vEthernet adapter IPv4 address) on X-Server (neither Xming nor VcxSrv with and without -ac parameters) running on WINDOWS host system to display any graphic apps (eg xeyes or xclock).

I added some documentation for the issues that I found while trying to get DISPLAY working with WSL 2:

https://github.com/cascadium/wsl-windows-toolbar-launcher#troubleshooting

Ideally though, yes localhost would work and no firewall exceptions would be required (which I would suggest this ticket is primarily for).

WSL2 networking really is a clusterfuck.

@fquinner I created some scripts, which can be run either when boot or from WSL or from Administrator Powershell.

They launch, in a transparent manner. a windowed KDE, using VcXsrv and the accompanying Xlaunch. It works very well and has no problems with reboots or shutting it down and back again

A working version has been uploaded at:
https://github.com/famelis/wsl2-x11

@Uzume IΒ΄m using Ubuntu 18.04 and IΒ΄ve installed socat via apt-get. :)

My use case is as follow:

  • I need to use chromedriver(and chrome) running on Windows(host) and I need to control the chromedriver via selenium running on my Ubuntu(via wsl2).

Since I canΒ΄t update my code to access chromedriver via an IP address, he always tries access chromedriver via the localhost. So to put chromedriver to run on localhost, IΒ΄m using the following command to relay requests from LOCALHOST:PORT to WINDOWSHOST:PORT.

Command: socat -d -d TCP-LISTEN:9515,reuseaddr,fork TCP:$(cat /etc/resolv.conf | tail -n1 | cut -d " " -f 2):9516

So each request that I did from my wsl2 machine to "localhost:9515" is relayed to "ipaddress:9516". On the windows side, I just need to open the 9516 port on my firewall.

If I can help you with anything else, reach me out! :)

Hey thanks for this solution. What should I change on the code side to get it to use port 9516?

@craigloewen-msft - Am I wrong in saying that the cause of this problem is that Windows Defender Firewall rules is blocking access (see #4139)? If so, then either this issue, or the other can be closed.

I had similar troubles and the only way I could get it working was to excluding vEthernet (WSL) from my list of Windows Defender public protected network connections. Ideally I would like to have a firewall rule that allows access to all Windows ports from my WSL instance but it does not appear to work.

@smcenlly The cause for this problem is that WSL 2 has a virtualized ethernet adapter with a different IP address, and as of right now we don't relay connections from localhost in the guest VM to the host machine. This is different than the firewall issue, as there even if you use the IP address of the host you can still be blocked by default firewall settings. So for us on the team it's valuable to have both of these issues open so we can track them.

This is an important use case that 'just worked' in WSL1. I'm running a service in a docker container that I'd like to access from WSL2, but I can't connect to it, and it's not clear where any of the network stack is configured for the WSL2 VM. I've completely disabled the Windows Defender Firewall, but that doesn't change anything.

There is also an issue when running a VPN on the host and accessing Internet from WSL2 described here. The combination of these two issues is preventing me from adopting WSL2, and I'll have to switch back to WSL1 for the time being.

I'd like to (1) be able to access localhost: from WSL2 without having to jump through config hoops, and (2) be able to run a VPN on the host and not lose Internet connectivity in the WSL2 guest.

jvik commented

@aressler38

This is an important use case that 'just worked' in WSL1. I'm running a service in a docker container that I'd like to access from WSL2, but I can't connect to it, and it's not clear where any of the network stack is configured for the WSL2 VM. I've completely disabled the Windows Defender Firewall, but that doesn't change anything.

I believe your docker issue can be solved by enabling "Experimental WSL 2 based engine"

image

Did anyone find a proper solution yet?

This gist worked for me https://gist.github.com/matthiassb/9c8162d2564777a70e3ae3cbee7d2e95 in order to get WSL2 connecting to the network when Windows is connected to a VPN. I also shared the network adapter as described here: #416 (comment). I still can't figure out how to get WSL2 to access a docker service running in Windows.

What I found is that I can't seem to get netcat to work with WSL2 when my Windows host is connected to a VPN. I noticed that I'd periodically get an error saying "nc: getnameinfo: Temporary failure in name resolution." However, when I used Python's http.server to serve a simple index.html file, it worked. I was able to connect from the WSL2 environment to the docker container and localhost:8080 did work. I had to enable the WSL2 based backend in the Docker settings.

image

So, summing up, to solve the problem I was having I had to do three things:

  1. Enable WSL2 backend in Docker.
  2. Setup this service in the WSL2 VM https://gist.github.com/matthiassb/9c8162d2564777a70e3ae3cbee7d2e95
  3. Go into the network adapter setting, find my WiFi Internet adapter and then share it with the VPN adapter.

image

Now, I can connect to local services that run in Docker, but I still can't connect to services running in Windows. In order to connect to those services, I have to specify the IP address in my /etc/hosts file that Docker must have entered. In my /etc/hosts file, I see a few entries like this:

192.168.1.130   gateway.docker.internal
127.0.0.1       kubernetes.docker.internal

They weren't there until I enabled the WSL2 backend in Docker. If I try to access a Python SimpleHTTPServer running on 8999, then I have to curl http://192.168.1.130:8999 inside WSL2. That seems to work. If I add "localhost 192.168.1.130" to the /etc/hosts file, then I can curl localhost:8999, but I'm not sure if that's a good idea.

Update:
As far as my VPN connection goes, when I restart the computer and reconnect to VPN, WSL2 can't get to the Internet. I have to unshare and reshare the Internet connection as above to get WSL2 to connect to the Internet -- even after the /etc/resolv.conf file has been updated.

How is this going on ? Windows 10 2004 is in the way at the end of this month, this issue is definite a key problem should be solved in advance .

Solution as we speak

  • Check your WSL2 network adapter
  • copy the ipv4 address in the details
  • add the ipv4 address in your host files

Solution as we speak

  • Check your WSL2 network adapter
  • copy the ipv4 address in the details
  • add the ipv4 address in your host files

On host files on both Windows and Linux or just one of them? I guess I have to make the ipv4 static on the wsl adapter, it changes every reboot.

This article helped me out.

Key steps:

  1. set windows firewall defender, add a new in bound rule.
  2. use netsh to add portproxy.

My case is to access mysql on windows from wsl2, so my netsh command would be:

netsh interface portproxy add v4tov4 listenport=3306 listenaddress=0.0.0.0 connectport=3306 connectaddress=127.0.0.1

@vipzhicheng Is your solution the reverse of OP's? Your solution lets windows access mysql on wsl2. I think OP (and I) are trying to access a DB on windows from WSL 2.

I recently got this working with Local Lightning, a Windows application which serves WordPress sites locally. You should be able to tweak my script's port numbers to work with any other application: https://anchor.host/local-lightning-and-upgrading-to-wsl2/.

It worked.

It did not work, but I solved it by "restart"....

Now today, it suddenly does not work again, and the "restart" couldn't fix it.

What's wrong ?

http://realtechtalk.com/iptables_how_to_forward_localhost_port_to_remote_public_IP-1788-articles

This article helped me forwarding ports to windows host.

To get windows ip I used $(cat /etc/resolv.conf | tail -n1 | cut -d " " -f 2) from #4619 (comment)

One caveat here, if your windows app is listening on 127.0.0.1 interface instead of 0.0.0.0, you'll need to do a port forwarding on Windows too:
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=3306 connectaddress=127.0.0.1 connectport=3306 (or whatever port and listenaddress you need).

You'll also need to add a firewall rule for WSL: #4585 (comment)

garyo commented

Can anyone summarize this? All I want to do is display an X program in WSL on my Windows machine (I'm using vcxsrv). So just connect from WSL process to Windows port 6000. This was trivial in WSL1, and in WSL2 -- well I can't even figure out what the recommendation is.

garyo commented

I eventually got X11 working: turns out already vcxsrv adds firewall rules, and (sensibly) prohibits public access. But somehow WSL2 is considered "public"! Once I deleted those rules, X11 connections started working. I had to use this to get the WSL2 bridge address (can't just use the actual IP addr of Windows, that would be too simple): export WSL_HOST_IP=$(ipconfig.exe | awk '/WSL/ {getline; getline; getline; getline; print substr($14, 1, length($14)-1)}')
So from WSL at 172.29.108.54, have to connect to 172.29.96.1 (same subnet, it's a /20), which somehow gets to Windows at 192.168.0.41.

At the risk of seeming stupid, if WSL2 is really just a VM, couldn't it just get a DHCP address from my DCHP server? Then it'd be on my subnet and things would at least be semi-normal.

@garyo - regarding getting real IP from DHCP into WSL2, check this one -- #5368 (comment)

I got it working by allowing common ports that my ASP.NET apps use on windows host through the windows firewall. A blunt way is to turn firewall off for public networks, but that is risky.
WSL2 on Windows 10 2004
image

Solved

do ipconfig on your cmd and you will get the IPV4 address. Instead of localhost:port try your_ipv4_adress:port

This worked when I was trying to access a server started on windows through another app started from WSL system

same problem
when I run vagrant wanting to connect virtualbox which installed on the windows, the ssh would be connected refused.
image

cmd command make it
image

but wsl2 fail,even though I try to use HOSTIP and close firewall

image

So why there isn't a way to make the network static?

Why windows IP for WSL changes every reboot?

Why WSL update resolv.conf on boot but not just edit /etc/hosts?

Having the same issue with WSL2 accessing localhost:1433 of MSSQL running on Windows.
Running my Node.js app producing these errors:

TypeORM connection error: ConnectionError: Failed to connect to localhost:1433 - Could not connect (sequence)
or running sqlcmd:
Sqlcmd: Error: Microsoft ODBC Driver 17 for SQL Server : TCP Provider: Error code 0x2749.

I've managed to partially solve it by using the port of WSL virtual network adapter (f.e. 172.23.128.1), but got the deprecation warning:
(node:472) [DEP0123] DeprecationWarning: Setting the TLS ServerName to an IP address is not permitted by RFC 6066. This will be ignored in a future version.
, what is definitely not ok.

At the same time WSL1 is able to connect properly to localhost:1433.

Networking changes in WSL2 are really a big pain in the ass, for me WSL is not usable anymore. Can we expect any comprehensive solution, not only a workarounds?

The same issue this is a big reason in order to not use wsl2. Just for more details I'm running IIS in port 80 and I can't curl from wsl2 to localhost. I hope one earlier solution...

I just wanted to say THANK YOU to garyo: All I wanted to do was to connect to a SQL Server running on Windows using WSL2. This was a breeze using WSL1. Never in a million years I'd've expected WSL2 to be considered "public". Prior to this issue I was also trying to run X11 (Xming). My solution was very similar:

Until MS WSL2 comes up with a better way to connect to Windows apps

export WSL_HOST_IP=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')

For X-server (Xming) to work

export DISPLAY=$WSL_HOST_IP:0.0
Anyway, once I allowed for "public" access (Windows firewall) for the default SQL Server port (1433), my python scripts were able to access the SQL Server successfully!! This is a toy/developing environment, This wouldn't fly in a production environment.

export WSL_HOST_IP=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')

The cat + grep + awk chain can be replaced with a single grep invocation:

export WSL_HOST_IP=$(grep -Po '(?<=nameserver ).*' /etc/resolv.conf)

If you use Docker Desktop, which I'd highly recommend since it automates the entire WSL2 install from scratch, for each VM you enable docker integration for, it adds the host IP to /etc/hosts as per here, so you can use:

export DISPLAY=host.docker.internal:0.0

I'm not sure if Docker keeps it up to date, I'm sure it does.

If you want use windows service in WSL2

Run this in Admin privilage:

netsh interface ip add address "vEthernet (WSL)" 192.168.1.155 255.255.255.0

This will set new ip 192.168.1.155 for WSL 2. You can save this in bat file and run when the machine starts using windows task scheduler.

image

You can use this ip from WSL2 to access windows service.

It worked for me.

Just lost my morning trying to understand why I couldn't reach my local MongoDB Instance, because of this... Rolled back to V1 on my Debian and now everything works flawlessly.

I was pretty appalled to see complicated workarounds to grab the IP address of the Windows hosts and dangerous suggestion to disable X server access control. After a bit of research, I think the following is the best workaround to communicate from WSL2 back into the host that I haven't seen documented yet.

The idea is to use the ability to communicate over stdio.

Prerequisite

  • Just so we can use socat in Windows host, you need a distribution running WSL1. I am sure you can do this in powershell but I didn't have time to research this. Maybe someone can write a stdio->tcp redirector in powershell.

How to forward X-server connection

  1. Have your favorite X server running on Windows. By default they would listen to port 6000.
  2. In the WSL2 distro, run the following command in the background (ubuntu is the name of the WSL1 distro with socat installed):
mkdir -p /tmp/.X11-unix/
socat UNIX-LISTEN:/tmp/.X11-unix/X0,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d Ubuntu socat - TCP\:localhost\:6000"

Basically this sets up a tunnel from the normal X unix domain socket into the host's port 6000.

How to forward any TCP connection back to host

Let's assume there is a tcp service running at port 5555 on Windows. In the WSL2 distro, run the following command in the background (ubuntu is the name of the WSL1 distro with socat installed):

socat TCP-LISTEN:5555,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d ubuntu socat - TCP\:localhost\:5555"

How to forward any TCP connection from host into WSL2

This is simply doing the same thing, but in the opposite direction. You can run the following in your WSL1 distro:

socat TCP-LISTEN:5555,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d ubuntuwsl2 socat - TCP\:localhost\:5555"

Performance

On my PC, it can handle up to 150MB/s of data so it's not the fastest but fast enough for most applications.

@therealkenc @craigloewen-msft I think this deserves a mention in the official documentation πŸ˜‰

Am I the only one using ZeroTier for WSL and host communication? It's a very simple solution.

I was pretty appalled to see complicated workarounds to grab the IP address of the Windows hosts and dangerous suggestion to disable X server access control. After a bit of research, I think the following is the best workaround to communicate from WSL2 back into the host that I haven't seen documented yet.

The idea is to use the ability to communicate over stdio.

@wbkang this looks like a brilliant solution!

I just tested it, and my WSL2 gedit X11 session survived a network change (I unplugged laptop from docking station) and it also survived a suspend / resume cycle.

(so far I've been using ssh X11 forwarding, but that dies whenever the WSL2 network connection changes, which is too often for this mode of operation to be truly useful. Because of this, I've been favouring xrdp, but your solution seems to be much faster.)

@wbkang That's an interesting approach thanks - one that seems surprisingly resilient too. You can avoid the need for a wsl1 distro too by running one of the socat ports for windows directly instead too, e.g.

socat UNIX-LISTEN:/tmp/.X11-unix/X0,fork EXEC:"/mnt/d/Downloads/socat-1.7.3.2-1-x86_64/socat.exe - TCP\:localhost\:6000"

So yes this is a noteworthy workaround... until we get a proper fix.

Thank you guys, I tried to download an unofficial socat-for-windows and run:

socat tcp-listen:7890,fork exec:"/mnt/c/ProgramData/my-programs/socat/socat.exe - tcp\:localhost\:7890"

Then I can access the proxy server running on Windows at port 7890 easily by connect to localhost:7890 on WSL.

Edit:

And when I want to use this work around to solve proxy problem, I got a new problem that no systemd is available to elegantly run this command as daemon in the background. I'm currently putting this command into ~/.zprofile. But this will blocks vscode's intergrated terminal and version control panel if vscode-remote-wsl is the one who first fires up the WSL distro (and therefore the socat command). If you want to use this way and also use VSCode, you may want to invoke a login shell for your WSL distro before running VSCode with Remote-WSL.

Edit again:

I finally ended up with creating a powershell script containing:

wsl -- socat tcp-listen:7890,fork exec:"/mnt/c/ProgramData/my-programs/socat/socat.exe - tcp\:localhost\:7890" "&"

and add a shortcut to powershell.exe inside shell:startup folder (which you can access by Win+R and shell:startup) to run this script with -File argument. You can use -Command argument, too. If you experience execution policy issue, you can investigate -ExecutionPolicy argument.

It will be a very important feature for us, waiting for.

@wbkang That's an interesting approach thanks - one that seems surprisingly resilient too. You can avoid the need for a wsl1 distro too by running one of the socat ports for windows directly instead too, e.g.

I just tested the WSL2 direct to Windows path by using the cygwin socat v1.7.3.4, thinking that it might be even better to cut out WSL1, but this was visibly substantially slower.

WSL1 is doing some optimization here which causes, at least on my setup, socat from WSL2 via WSL1 to X410 to be significantly faster than the exact same use-case (Emacs) from WSL2 directly to Windows.

WSL 2 networking is still PITA, can confirm

garyo commented

This is a showstopper issue for me. The time sync thing can be worked around without too much hassle, but lack of a stable, accessible IP address on my subnet is just impossible to deal with in a general way. The workarounds here are clever but are all just more things to break when you're trying to get a product out. I could not recommend WSL2 at this point just due to this issue.

Tried all described above options during 2 days. Neither of them worked for me

I was pretty appalled to see complicated workarounds to grab the IP address of the Windows hosts and dangerous suggestion to disable X server access control. After a bit of research, I think the following is the best workaround to communicate from WSL2 back into the host that I haven't seen documented yet.

The idea is to use the ability to communicate over stdio.

Prerequisite

  • Just so we can use socat in Windows host, you need a distribution running WSL1. I am sure you can do this in powershell but I didn't have time to research this. Maybe someone can write a stdio->tcp redirector in powershell.

How to forward X-server connection

  1. Have your favorite X server running on Windows. By default they would listen to port 6000.
  2. In the WSL2 distro, run the following command in the background (ubuntu is the name of the WSL1 distro with socat installed):
mkdir -p /tmp/.X11-unix/
socat UNIX-LISTEN:/tmp/.X11-unix/X0,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d Ubuntu socat - TCP\:localhost\:6000"

Basically this sets up a tunnel from the normal X unix domain socket into the host's port 6000.

How to forward any TCP connection back to host

Let's assume there is a tcp service running at port 5555 on Windows. In the WSL2 distro, run the following command in the background (ubuntu is the name of the WSL1 distro with socat installed):

socat TCP-LISTEN:5555,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d ubuntu socat - TCP\:localhost\:5555"

How to forward any TCP connection from host into WSL2

This is simply doing the same thing, but in the opposite direction. You can run the following in your WSL1 distro:

socat TCP-LISTEN:5555,fork EXEC:"/mnt/c/Windows/System32/wsl.exe -d ubuntuwsl2 socat - TCP\:localhost\:5555"

Performance

On my PC, it can handle up to 150MB/s of data so it's not the fastest but fast enough for most applications.

@therealkenc @craigloewen-msft I think this deserves a mention in the official documentation πŸ˜‰

This works great!! Might there also be a way to use this to solve internet connectivity issues in WSL2? With WSL1, it worked fine on company VPN, while, on WSL2 I need to change the nameserver entry in resolv.conf to bring back internet connectivity and yet, it's hard to use sometimes because it has its own IP and I can't access windows VPN.

export WSL_HOST_IP=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')

The cat + grep + awk chain can be replaced with a single grep invocation:

export WSL_HOST_IP=$(grep -Po '(?<=nameserver ).*' /etc/resolv.conf)

I meet a strange problem here.

On WSL:

$ cat /etc/resolv.conf
# This file was automatically generated by WSL. To stop automatic generation of this file, add the following entry to /etc/wsl.conf:
# [network]
# generateResolvConf = false
nameserver 192.168.2.1
nameserver fe80::1
nameserver fec0:0:0:ffff::1

On Windows:

Wireless LAN adapter Wi-Fi 3:

   Connection-specific DNS Suffix  . :
   IPv6 Address. . . . . . . . . . . : 2409:8a00:7867:22d0::2
   Link-local IPv6 Address . . . . . : fe80::495b:92ab:7ba1:4583%24
   IPv4 Address. . . . . . . . . . . : 192.168.2.15
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : fe80::1%24
                                       192.168.2.1

Both windows' and WSL's DNS is set to my windows' wireless router.

Both windows' and WSL's DNS is set to my windows' wireless router.

That has come up in other posts. Conditions under which it happens remain unexplained. It is particularly problematic since the docs suggest using the /etc/resolv.conf address. Use the default gateway address from route -n. [If you can't ping the default gateway either that's a separate thing.]

Does Microsoft have any plans to fix this soon??? Or fix it at all????? It is utterly ridiculous that windows can access ports in WSL2 with localhost:port but the same does not work if WSL2 wants to access a port in windows......

If you want use windows service in WSL2
Run this in Admin privilage:
netsh interface ip add address "vEthernet (WSL)" 192.168.1.155 255.255.255.0
This will set new ip 192.168.1.155 for WSL 2. You can save this in bat file and run when the machine starts using windows task scheduler.

You can use this ip from WSL2 to access windows service.
It worked for me.

Could you explain more details about it?

This is very painful for my WebApp development.
Its a huge hassle connecting my Localhost hosted mongodb server from wsl2.

Same issue here. We have a corporate proxy listening on 127.0.0.1. So with wsl1, it is not difficult to use it, but sadly it is another story with wsl2 😭

Same issue here. We have a corporate proxy listening on 127.0.0.1. So with wsl1, it is not difficult to use it, but sadly it is another story with wsl2 😭

For proxy, check this work around #4619 (comment)

For proxy, check this work around #4619 (comment)

Then I can access the proxy server running on Windows at port 7890 easily by connect to localhost:7890 on WSL.

@escape0707 - How should I connect from WSL2? I ran the following command from windows:

wsl -- socat tcp-listen:7890,fork exec:"/mnt/c/socat/socat.exe - tcp\:localhost\:7890"

@alarya All this comment do is like forward requests and responses between Windows local host:7890 and WSL(2) local host:7890. If you do have the same configuration like mine, which is a proxy server running in Windows and listening at local host:7890, then you can just access the same local potato in WSL(2), too. Such as you set HTTP_PROXY etc to local host:7890, then start a download. On Linux, how should you configure for proxy depends on which software you want to apply the proxy. But the point is that you can treat the port opened by so at as the proxy server’s listening port.
Of course, this proxy server process should be running in the background when you want to use a proxy, that’s why a added a & at the end of the command.

Hope my comment from other reported issue (which I guess is the same) helps you: #5211 (comment)

I personally ended up running containers with the WSL2 integration for services that can run on Docker (Mongo for example)

What I ended up doing, is running this in my .bashrc

Add routing rules for the windows processes I need.

# enable packet forwarding
sysctl -w net.ipv4.ip_forward=1 > /dev/null

# enable routing of packets generated by localhost
sysctl -w net.ipv4.conf.all.route_localnet=1 > /dev/null

# get the ip address of windows machine
winip=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')

# remove exisiting iptables rules
iptables -t nat -D OUTPUT -p tcp -d 127.0.0.1 --dport 8000 -j DNAT --to-destination $winip:8000

# setup port forwarding and packet masquerading
iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport 8000 -j DNAT --to-destination $winip:8000
iptables -t nat -A POSTROUTING -p tcp -d $winip --dport 8000 -o eth0 -j MASQUERADE

This solution suggested and created by RedaAouad

It would be good to know what the WSL team thinks of this issue. Accessing a local port on a local system shouldn't require running complicated bash scripts on startup or disable firewalls. Are there any plan to fix this issue?

Chiming in to say yes we are investigating fixing this issue! One of our overall goals is to improve the networking story in WSL 2, and we agree you should be able to access a local port on Windows without complicated bash scripts. We don't yet have a timeline for this feature but I'm keeping up to date on these threads and I'll be sure to post here when we have any news.

What I ended up doing, is running this in my .bashrc

Add routing rules for the windows processes I need.

# enable packet forwarding
sysctl -w net.ipv4.ip_forward=1 > /dev/null

# enable routing of packets generated by localhost
sysctl -w net.ipv4.conf.all.route_localnet=1 > /dev/null

# get the ip address of windows machine
winip=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')

# remove exisiting iptables rules
iptables -t nat -D OUTPUT -p tcp -d 127.0.0.1 --dport 8000 -j DNAT --to-destination $winip:8000

# setup port forwarding and packet masquerading
iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport 8000 -j DNAT --to-destination $winip:8000
iptables -t nat -A POSTROUTING -p tcp -d $winip --dport 8000 -o eth0 -j MASQUERADE

This solution suggested and created by RedaAouad

Small detail to improve:

winip="$(grep nameserver /etc/resolv.conf | grep -v ':' | awk '{ print $2 }' | head -1)"

Also, sysctl and iptables need root permissions, how did you get it to run on your user?

@Uzume IΒ΄m using Ubuntu 18.04 and IΒ΄ve installed socat via apt-get. :)

My use case is as follow:

  • I need to use chromedriver(and chrome) running on Windows(host) and I need to control the chromedriver via selenium running on my Ubuntu(via wsl2).

Since I canΒ΄t update my code to access chromedriver via an IP address, he always tries access chromedriver via the localhost. So to put chromedriver to run on localhost, IΒ΄m using the following command to relay requests from LOCALHOST:PORT to WINDOWSHOST:PORT.

Command: socat -d -d TCP-LISTEN:9515,reuseaddr,fork TCP:$(cat /etc/resolv.conf | tail -n1 | cut -d " " -f 2):9516

So each request that I did from my wsl2 machine to "localhost:9515" is relayed to "ipaddress:9516". On the windows side, I just need to open the 9516 port on my firewall.

If I can help you with anything else, reach me out! :)

After running your socat command it just stays there frozen. I can't get it to ever complete.

Hope this issue get solved soon, this is currently almost impractical to work with wsl2 efficiently just because of this particular problem, for instance, one cannot run a VM in Windows and access it through wsl2 with port forwarding simply because wsl2 doesn't handle networking yet.

Crossing fingers that it will be solved very soon.

Looking for a solution aswell.
Currently (I use wsl for only 2 days) I have only the use case with curl and I'm using this workaround , maybe it can help someone too https://superuser.com/questions/1527835/windows-10-wsl-curl-cant-access-localhost-with-error-failed-to-connect-to-loca

To workaround this on selenium+chromedriver, IΒ΄m running a socat on wsl2 relaying requests to localhost:port to windows-host:port. This workaround can be used in a lot of other cases. :)

Could I ask how do you connect to selenium webdriver on WSL 2? I kept failing and get message 'Can not connect to the Service chromedriver'

installed WSL2, installed vcxsrv, disabled access control on the last config tab, allowed all firewall access and was able to launch:

sudo apt-get install net-tools traceroute x11-apps
sudo ifconfig
traceroute google.com
DISPLAY=192.168.4.47:0.0 xeyes

My debian WDL2 system and the windows system have different IP addresses. Traceroute shows that the system is running a little network mshome.net.

installed WSL2, installed vcxsrv, disabled access control on the last config tab, allowed all firewall access and was able to launch:

sudo apt-get install net-tools traceroute x11-apps
sudo ifconfig
traceroute google.com
DISPLAY=192.168.4.47:0.0 xeyes

My debian WDL2 system and the windows system have different IP addresses. Traceroute shows that the system is running a little network mshome.net.

Thank you for response! I believe that's the cause of my problem, I forgot that WSL 2 could not show windows if no third-party tools like vcxsrv. Others had suggest to install that, but it's not easy to install new software on my workplace PC, so I just set webdriver options to headless, then everything works fine.

Thank you anyway!

Yeah, this is a showstopper for me, to the point I might have drop out of Windows entirely and use Linux natively. I'm using Ansible and testing deployments on VirtualBox VMs, and Ansible requires WSL (it won't run on Windows at all) and after being nagged to update, I finally did, only to find that all the networking is borked. I get that a NAT-type model is more secure, but nobody is going to be using WSL as a security layer, so this is just outright frustrating. Since I'm attempting to connect to a range of ports on VMs, the bash scripting method really isn't viable, and I'll attempt to back out of WSL2 until there's a working solution to this problem.

I had to switch back to WSL2 for performance.

So I had to treat this problem as a network issue. First I need to have a convention, if I want to access the HOST ports, It should be thru "winhost" instead of "localhost".

Then, that's why my .bashrc right now

# wsl get windows host ip
export winhost=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
if [ ! -n "$(grep -P "[[:space:]]winhost" /etc/hosts)" ]; then
	printf "%s\t%s\n" "$winhost" "winhost" | sudo tee -a "/etc/hosts"
fi

Having this support natively would be nice for a temporary/remedy solutions for this issue.

I had to switch back to WSL2 for performance.

So I had to treat this problem as a network issue. First I need to have a convention, if I want to access the HOST ports, It should be thru "winhost" instead of "localhost".

Then, that's why my .bashrc right now

# wsl get windows host ip
export winhost=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
if [ ! -n "$(grep -P "[[:space:]]winhost" /etc/hosts)" ]; then
	printf "%s\t%s\n" "$winhost" "winhost" | sudo tee -a "/etc/hosts"
fi

Having this support natively would be nice for a temporary/remedy solutions for this issue.

run ping winhost timeout

I had to switch back to WSL2 for performance.
So I had to treat this problem as a network issue. First I need to have a convention, if I want to access the HOST ports, It should be thru "winhost" instead of "localhost".
Then, that's why my .bashrc right now

# wsl get windows host ip
export winhost=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
if [ ! -n "$(grep -P "[[:space:]]winhost" /etc/hosts)" ]; then
	printf "%s\t%s\n" "$winhost" "winhost" | sudo tee -a "/etc/hosts"
fi

Having this support natively would be nice for a temporary/remedy solutions for this issue.

run ping winhost timeout

@theprimone delete the winhost line from your /etc/hosts file and then reload your terminal. This will update the winhost entry to be the most recent host IP.

I had to switch back to WSL2 for performance.
So I had to treat this problem as a network issue. First I need to have a convention, if I want to access the HOST ports, It should be thru "winhost" instead of "localhost".
Then, that's why my .bashrc right now

# wsl get windows host ip
export winhost=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
if [ ! -n "$(grep -P "[[:space:]]winhost" /etc/hosts)" ]; then
	printf "%s\t%s\n" "$winhost" "winhost" | sudo tee -a "/etc/hosts"
fi

Having this support natively would be nice for a temporary/remedy solutions for this issue.

run ping winhost timeout

@theprimone delete the winhost line from your /etc/hosts file and then reload your terminal. This will update the winhost entry to be the most recent host IP.

It still timeout after I delete winhost line and reboot my computer _(:3J∠)_

I had to switch back to WSL2 for performance.
So I had to treat this problem as a network issue. First I need to have a convention, if I want to access the HOST ports, It should be thru "winhost" instead of "localhost".
Then, that's why my .bashrc right now

# wsl get windows host ip
export winhost=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
if [ ! -n "$(grep -P "[[:space:]]winhost" /etc/hosts)" ]; then
	printf "%s\t%s\n" "$winhost" "winhost" | sudo tee -a "/etc/hosts"
fi

Having this support natively would be nice for a temporary/remedy solutions for this issue.

run ping winhost timeout

@theprimone delete the winhost line from your /etc/hosts file and then reload your terminal. This will update the winhost entry to be the most recent host IP.

It still timeout after I delete winhost line and reboot my computer (:3J∠)

Try:
Check your /etc/hosts if winhost has the correct ip.

Try to check if you have tee installed.

and/or

Update your windows build to 20H2,
Update wsl2 to 5.4.72-microsoft-standard-WSL2 or higher

ps: you don't need to reboot your computer, only wsl by running wsl --shutdown on any command prompt.

@nivranaitsirhc Try to update kernel to 5.4.91-microsoft-standard-WSL2, still failed..., it's so hard _(:3J∠)_

@nivranaitsirhc Try to update kernel to 5.4.91-microsoft-standard-WSL2, still failed..., it's so hard _(:3J∠)_

Try this.

  1. Does restarting wsl ask for one-time sudo password?

If no. Then something is wrong.

  1. Try to run those script in wsl terminal see if it will update the /etc/hosts winhost entry.

This will narrow down the problem.

/etc/hosts has changed, but not work
image

@craigloewen-msft Hello, is there any update news?

I installed the OpenSSH Server on my host, then I forward ports as I like to my wsl box.

From wsl:

 ssh `awk '/nameserver/ { print $2 } < /etc/resolv.conf'` -L 9222:127.0.0.1:9222

/etc/hosts has changed, but not work
image

Sorry for the late reply, hope this is still relevant.

If winhost reflects on your /etc/host

Try:

  1. Pinging winhost
    or
  2. Pinging the IP address of the reflected winhost.

If 1 fails but 2 does not. Your host file changes has not been read by the system yet.

If both 1 & 2 fails.
-It might be a routing error.
-The IP read by the command is not valid.
-Firewall issue.

I had to switch back to WSL2 for performance.

So I had to treat this problem as a network issue. First I need to have a convention, if I want to access the HOST ports, It should be thru "winhost" instead of "localhost".

Then, that's why my .bashrc right now

# wsl get windows host ip
export winhost=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
if [ ! -n "$(grep -P "[[:space:]]winhost" /etc/hosts)" ]; then
	printf "%s\t%s\n" "$winhost" "winhost" | sudo tee -a "/etc/hosts"
fi

Having this support natively would be nice for a temporary/remedy solutions for this issue.

This is great! However it seems that password must be provided for sudo after every reboot, because WSL generates /etc/hosts every time by default. This behavior can be disabled, as it suggests, by adding the following two lines to /etc/wsl.conf

[network]
generateHosts = false

Then I slightly modified the script as follows, for updating the existing winhost.

export winhost=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
old_winhost=$(grep -P "[[:space:]]winhost" /etc/hosts | awk '{ print $1 }')

if [ -z $old_winhost ]; then
    echo "write winhost to /etc/hosts"
    echo "$winhost\twinhost" | sudo tee -a "/etc/hosts"
elif [ $old_winhost != $winhost ]; then
    echo "update winhost in /etc/hosts from $old_winhost to $winhost"
    sudo sed -i "s/$old_winhost\twinhost/$winhost\twinhost/g" /etc/hosts
fi
garyo commented

If you're running Insider builds, don't do this stuff from your .bashrc. Anything with sudo in .bashrc will cause you headaches later. Instead, create/edit /etc/wsl.conf (See docs) and add a distro startup script in there. That will run as root. As of build 21286 /etc/wsl.conf supports boot.command to run any command on wsl2 startup.

/etc/hosts has changed, but not work
image

Sorry for the late reply, hope this is still relevant.

If winhost reflects on your /etc/host

Try:

  1. Pinging winhost
    or
  2. Pinging the IP address of the reflected winhost.

If 1 fails but 2 does not. Your host file changes has not been read by the system yet.

If both 1 & 2 fails.
-It might be a routing error.
-The IP read by the command is not valid.
-Firewall issue.

Yes, I think so, I'm working on it now

@nivranaitsirhc Thanks for your help, I resovled firewall issue by #4139 (comment)

@function2-llx Something wrong with "\t"? resolved by https://stackoverflow.com/a/525875/8335317

export winhost=$(cat /etc/resolv.conf | grep nameserver | awk '{ print $2 }')
old_winhost=$(grep -P "[[:space:]]winhost" /etc/hosts | awk '{ print $1 }')

if [ -z $old_winhost ]; then
    echo "write winhost to /etc/hosts"
-   echo "$winhost\twinhost" | sudo tee -a "/etc/hosts"
+	echo -e "$winhost\twinhost" | sudo tee -a "/etc/hosts"
elif [ $old_winhost != $winhost ]; then
    echo "update winhost in /etc/hosts from $old_winhost to $winhost"
    sudo sed -i "s/$old_winhost\twinhost/$winhost\twinhost/g" /etc/hosts
fi

In the end, if somebody use Qv2ray, Sharing Proxy over Local Network (LAN) can help you.

@theprimone Thanks for pointing this out. Seems because I'm using zsh, the issue does not exposed.

image

In my case, the problem just happens sometimes and returns to work when I reboot the whole Windows, which is quite annoying. Does anyone know what it might be?

I'm using WSL for Java develpment projects. Some of these projects require access to a database via localhost running in Vagrant/Virtualbox VM's on the Windows host.

With WSL1 I had no problems in setting up such a development environment but it's impossible with the current behavior of WLS2.

I think this is a show stopper for many scenarios that would otherwise be ideal for using WSL2 with its performance benefits.

Are there any plans to change this behavior?

Was using WSL2 for an Vue project , I was trying to connect to a Java API using axios but it's giving me a network error I guess wsl is unable to access the windows localhost .
Hope there is a solution to this.

@AkikJana This comment above is useful.