Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WSL 2] NIC Bridge mode 馃枾 (Has Workaround馃敤) #4150

Open
jkasten2 opened this issue Jun 16, 2019 · 37 comments
Open

[WSL 2] NIC Bridge mode 馃枾 (Has Workaround馃敤) #4150

jkasten2 opened this issue Jun 16, 2019 · 37 comments

Comments

@jkasten2
Copy link

@jkasten2 jkasten2 commented Jun 16, 2019

Issue

WSL 2 seems to NAT it's virtual network, instead of making it bridged to the host NIC. My goal is for a service running in Ubuntu in WSL 2 to be accessible from anywhere on my local network.

Issue Details

  • Your Windows build number: Microsoft Windows [Version 10.0.18917.1000]

  • What you're doing and what's happening:
    Running ipconfig on my Windows 10 host machine

   IPv4 Address. . . . . . . . . . . : 192.168.1.41
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . : 192.168.1.1

Running ifconfig in Ubuntu WSL 2

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.72.60  netmask 255.255.0.0  broadcast 172.18.255.255

Accessing 172.18.72.60 from my Window host does work, however this IP is not accessible from another system on my network.

  • What's wrong / what should be happening instead:
    I would expect to ifconfig in Ubuntu WSL 2 to have an IP address in the same network as my host machine.

  • Searching the docs:
    The only detail I have found about WSL 2 networking is the following that notes that it will have it's own IP and that localhost is something that will be used for WSL 2 in the future.
    https://docs.microsoft.com/en-us/windows/wsl/wsl2-ux-changes
    This is fine, however I would like the IP WSL 2 is getting to be on my local LAN which means I need to configure the virtual NIC to be bridged.

Workaround

See @edwindijas #4150 (comment)

@briandesousa

This comment has been minimized.

Copy link

@briandesousa briandesousa commented Jun 18, 2019

Same issue here.

IP address of Windows machine is 192.168.1.95 and the eth0 interface in Ubuntu on WSL2 is getting 172.18.47.17.

I originally had Ubuntu on WSL1 running and then upgraded the installation to WSL2 but same problem. Then I uninstalled Ubuntu altogether and reinstalled fresh but same issue after reinstall.

Prior to using WSL2 I had an instance of Ubuntu setup as a Hyper-V VM on the same machine (Hyper-V NIC bridge already existed).

@zzz1990771

This comment has been minimized.

Copy link

@zzz1990771 zzz1990771 commented Jun 18, 2019

Same issue. I have a rstudio server running in docker container in WSL2 and wanted to access it from other machine but failed. Really need some fix/idea on it.

@nicolazj

This comment has been minimized.

Copy link

@nicolazj nicolazj commented Jun 18, 2019

I can confirm this issue.
I can no longer access the service running in subsystem from my mobile device, which is within the same wifi network with my windows laptop.

@edwindijas

This comment has been minimized.

Copy link

@edwindijas edwindijas commented Jun 20, 2019

It's not a bug with WSL 2, WSL 2 is running as a hyper-v virtual machine. The hyper-v adapter can be found in network adapters. You can use port forwarding to forward the port with netsh as below.
Example command below will forward tcp from port 3000 of the WSL 2 client to port 3000 of the host OS.
netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=172.18.28.x
Next allow incoming and outgoing ports on port 3000 in firewall.

@zzz1990771

This comment has been minimized.

Copy link

@zzz1990771 zzz1990771 commented Jun 20, 2019

It's not a bug with WSL 2, WSL 2 is running as a hyper-v virtual machine. The hyper-v adapter can be found in network adapters. You can use port forwarding to forward the port with netsh as below.
Example command below will forward tcp from port 3000 of the WSL 2 client to port 3000 of the host OS.
netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=172.18.28.x
Next allow incoming and outgoing ports on port 3000 in firewall.

Hi! Did you try it on your end? It didn't work for me when I was trying to access it from another machine in the same network. Although I did work when I use the windows host.

@edwindijas

This comment has been minimized.

Copy link

@edwindijas edwindijas commented Jun 20, 2019

I tried it. It worked but the craziest thing is happening, the ip address is changing on reboot. Don't forget to add inbound and outbound rules. Microsoft will fix this issue in the future

@edwindijas

This comment has been minimized.

Copy link

@edwindijas edwindijas commented Jun 20, 2019

WSL 2 TPC NETWORK FORWARDING

Introduction

With the introduction of WSL 2 Beta, Microsoft has made changes to the system architecture.
The changes include changing from the default bridged network adapter to a hyper-v virtual network adapter.
The implementation was not completed during the launch of the beta program. This makes accessing of network resources under WSL 2 complex.
The work around is to forward the TCP ports of WSL 2 services to the host OS.
The virtual adapter on WSL 2 machine changes it's ip address during reboot which makes it tough to implement a run once solution.
Also a side note, windows firewall will block the redirected port.

The work around is to use a script that does :

  1. Get Ip Address of WSL 2 machine
  2. Remove previous port forwarding rules
  3. Add port Forwarding rules
  4. Remove previously added firewall rules
  5. Add new Firewall Rules

Configuration

The script must be run at login ,under highest privileges to work, and Powershell must be allowed to run external sources.

PowerShell Configuration

Enable power shell to run external scripts, run the command below in power shell with administrative privileges.

How To:
Go to search, search for task scheduler. In the actions menu on the right, click on create task.
Enter Name, go to triggers tab. Create a new trigger, with a begin task as you login, set delay to 10s.
Go to the actions and add the script. If you are using Laptop, go to settings and enable run on power.

Finally:
I am no expert at security nor scripting and technically new to the windows OS.

Update
The update adds the feature to remove unwanted firewall rules.
Here is the script.


$remoteport = bash.exe -c "ifconfig eth0 | grep 'inet '"
$found = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if( $found ){
  $remoteport = $matches[0];
} else{
  echo "The Script Exited, the ip address of WSL 2 cannot be found";
  exit;
}

#[Ports]

#All the ports you want to forward separated by coma
$ports=@(80,443,10000,3000,5000);


#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join ",";


#Remove Firewall Exception Rules
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";

#adding Exception Rules for inbound and outbound Rules
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $ports_a -Action Allow -Protocol TCP";

for( $i = 0; $i -lt $ports.length; $i++ ){
  $port = $ports[$i];
  iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
  iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport";
}


@jkasten2

This comment has been minimized.

Copy link
Author

@jkasten2 jkasten2 commented Jun 21, 2019

@edwindijas Awesome, that worked for me! 馃憤 馃帀 I can access my running Linux service from any system on my network via my Windows host IP!
Thanks for all the detail and Task Scheduler suggestion too.

In addition, this workaround means localhost works too.

I was trying to go down another route by forcing bridge mode of WSL virtual adapter, that didn't work. Just including it here for completeness.

PS C:\WINDOWS\system32> Set-VMSwitch WSL -NetAdapterName 'Name_of_your_phsyical_windows_NIC'
Set-VMSwitch : Failed while adding virtual Ethernet switch connections.
External Ethernet adapter 'Name_of_your_phsyical_windows_NIC' is already bound to the Microsoft Virtual Switch
protocol.
At line:1 char:1
+ Set-VMSwitch WSL -NetAdapterName 'Name_of_your_phsyical_windows_NIC'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Set-VMSwitch], VirtualizationException
    + FullyQualifiedErrorId : InvalidParameter,Microsoft.HyperV.PowerShell.Commands.SetVMSwitch

@edwindijas Linked your comment as a workaround for this issue in my original post #4150 (comment).

@jkasten2 jkasten2 changed the title [WSL 2] NIC Bridge mode [WSL 2] NIC Bridge mode 馃枾 (Has Workaround馃敤) Jun 21, 2019
@edwindijas

This comment has been minimized.

Copy link

@edwindijas edwindijas commented Jun 22, 2019

The script only opens ports you desired. And the ports are redirected to WSL machine.
That said, I am no security expert, if you have a better suggestion, I am open to suggestions.

@frkhit

This comment has been minimized.

Copy link

@frkhit frkhit commented Jun 23, 2019

my method to solve this problem: refresh ip in win10:hosts file

@gstorelli

This comment has been minimized.

Copy link

@gstorelli gstorelli commented Jun 24, 2019

WSL 2 TPC NETWORK FORWARDING

Introduction
....
Configuration

The script must be run at login ,under highest privileges to work, and Powershell must be allowed to run external sources.

PowerShell Configuration

Enable power shell to run external scripts, run the command below in power shell with administrative privileges.

I saved your script in a file called "wslbridge.ps1" and then in Windows Scheduler just set Powershell.exe as Action and as argument I wrote this (instead of setting the Unrestricted ExecutionPolicy):
-ExecutionPolicy Bypass c:\scripts\wslbridge.ps1

Thanks

@shayne

This comment has been minimized.

Copy link

@shayne shayne commented Jun 30, 2019

I wrote a Windows Service that automatically writes the WSL2 VM's IP address to the Windows hosts file. You can then just always reference "wsl.local" from your host machine and it will resolve to the WSL2 VM.

I've been using this for a week now and just open-sourced it.

https://github.com/shayne/go-wsl2-host

@shayne

This comment has been minimized.

Copy link

@shayne shayne commented Jul 1, 2019

I've collected a few WSL2 hacks into a repo:
https://github.com/shayne/wsl2-hacks

One thing I wanted to point out, relevant to this thread, was "Access localhost ports from Windows", a way to access ports bound to 127.0.0.1 / localhost from the Windows host.

@joaopluigi

This comment has been minimized.

Copy link

@joaopluigi joaopluigi commented Jul 18, 2019

Thanks @edwindijas, it is a great workaround.

For people using Debian, which does not come with ifconfig out of the box, you can try:

$remoteport = bash.exe -c "ip addr | grep -Ee 'inet.*eth0'"

Also, the hint from @gstorelli of using -ExecutionPolicy Bypass inside the arguments of your Task Scheduler script action is awesome!

Thanks, guys!

@QingGo

This comment has been minimized.

Copy link

@QingGo QingGo commented Jul 20, 2019

If there are multi wsl2 in your system, remember use this command on cmd to change the wsl2 which you want to bind these port as the default one, because bash.exe will run command in the default wsl2 environment:

# list the wsl on you system
wslconfig /l
# set Debian as default for example
wslconfig /setdefault Debian
@abnerfreitas

This comment has been minimized.

Copy link

@abnerfreitas abnerfreitas commented Jul 21, 2019

@edwindijas I was hoping to make my Google Chrome (inside my Kali Distro) recognize my Chromecast, but i couldn't find anywhere the actual ports chromecast uses to connect, however now i can access my Kali from anywhere trought SSH.

@sangemaru

This comment has been minimized.

Copy link

@sangemaru sangemaru commented Aug 20, 2019

You can now use localhost to connect in recent WSL2 versions

@ericblade

This comment has been minimized.

Copy link

@ericblade ericblade commented Aug 28, 2019

You can now use localhost to connect in recent WSL2 versions

That's really sort of a different problem -- you can use "localhost" from the host itself, but there's no obvious way to get there from a different machine on the network:

WSL2 is running on Windows host A
WSL2 on Windows host A is running server application B
You can connect to the application from host A by just doing "localhost:port"
You can't connect to the application from Windows Host C in any obvious way.

@xorinzor

This comment has been minimized.

Copy link

@xorinzor xorinzor commented Aug 28, 2019

You can connect to the application from host A by just doing "localhost:port"
You can't connect to the application from Windows Host C in any obvious way.

If you open the port, why would you not be able to connect to host A from host C by just doing "host-A-ip:port"?

This behaviour shouldn't be any different then it is for linux.

@ericblade

This comment has been minimized.

Copy link

@ericblade ericblade commented Aug 28, 2019

I don't know the technical reason for it, but it doesn't work by default, and is what brought me here.

@timesnewmen

This comment has been minimized.

Copy link

@timesnewmen timesnewmen commented Sep 8, 2019

You can connect to the application from host A by just doing "localhost:port"
You can't connect to the application from Windows Host C in any obvious way.

If you open the port, why would you not be able to connect to host A from host C by just doing "host-A-ip:port"?

This behaviour shouldn't be any different then it is for linux.

Although you can open Win app by localhost:port from WSL2, but they are definitely not sharing the same network like WSL1.

This is working in WSL1, but in WSL2 it's not. Still waiting form a solution.

@Dt-Sodium

This comment has been minimized.

Copy link

@Dt-Sodium Dt-Sodium commented Oct 8, 2019

Hi,
Is there any update on this? I can access my apache in wsl2 fine but it seems like it is not on the same company network as Windows which causes some issues.

@ViezeVingertjes

This comment has been minimized.

Copy link

@ViezeVingertjes ViezeVingertjes commented Oct 16, 2019

This only solves it from Windows to WSL i guess? But i am relying on the otherway around, WSL to Windows, which seems to be broken too.

Scenario: I am using the Docker Client within WSL, Docker Desktop (Server) on the Host (Windows). It can only be accessed by tcp://localhost:2375. This worked prior to upgrading to WSL2.

@unfalln

This comment has been minimized.

Copy link

@unfalln unfalln commented Oct 17, 2019

This only solves it from Windows to WSL i guess? But i am relying on the otherway around, WSL to Windows, which seems to be broken too.

Scenario: I am using the Docker Client within WSL, Docker Desktop (Server) on the Host (Windows). It can only be accessed by tcp://localhost:2375. This worked prior to upgrading to WSL2.

That is a different issue and you should search/create a new issue in this list for that.

@gionkunz

This comment has been minimized.

Copy link

@gionkunz gionkunz commented Oct 18, 2019

That is a different issue and you should search/create a new issue in this list for that.

I think this use-case would also be solved with a proper bridged network like in WSL1, wouldn't it?

@CreepyGnome

This comment has been minimized.

Copy link

@CreepyGnome CreepyGnome commented Oct 22, 2019

Wait I am confused, I cannot access my WSL Ubuntu from another computer or even from a Hyper-V VM on the same machine and I have disabled the firewall so changing firewall rules don't fix anything for me.

How do you make this work without a firewall? How can I allow my WSL to get its own IP from the DHCP server on my network so that it can be accessed via that?

Not sure why this is complicated can't it just be a passthrough as well, windows wins first if somethings on the requested port, however, if not just auto bridge/route to the WSL. However I think just like VM's get their own IP if you have bridge mode setup, why can't the WSL instance get its own ip in a similar fashion would be a better out of the box option.

@diqidoq

This comment has been minimized.

Copy link

@diqidoq diqidoq commented Oct 22, 2019

my method to solve this problem: refresh ip in win10:hosts file

WSL 2 TPC NETWORK FORWARDING

Here is the script.

For those who kindly posted solutions I strongly recommend to add advices how to do this manually too. To only post scripts which update a host file etc. is not a very secure official advice, since some users do not understand what the script is doing. For example: try to find a solution on google to manually update the host file and how the line has to look like to bridge to the wsl2 ip and you will find nothing but this issue thread here.

@diqidoq

This comment has been minimized.

Copy link

@diqidoq diqidoq commented Oct 24, 2019

As long as this issue shayne/go-wsl2-host#7 still persists I actually do not recommend to have (Has Workaround) in title of this issue here. From what I understood in other issue comments, it is rather referring to Shaynes addition now than to the original Workaround linked in the OT?`The provided workaround is harming a system slidely with an additional service running and cannot be removed easely for basic users at the moment. I think this needs to be considered before installing it.

@alvitawa

This comment has been minimized.

Copy link

@alvitawa alvitawa commented Nov 4, 2019

If you do not wish to clutter your system with scripts and you have access to a different computer on your network through ssh you can do:

ssh -R 0.0.0.0:8080:localhost:80 -N root@othercomputer

Remember to enable GatewayPorts in sshd_config, as outlined in the following question: https://superuser.com/questions/588591/how-to-make-ssh-tunnel-open-to-public

It is probably possible to forward the port to the same windows machine that is running wsl, but I haven't bothered to check.

This approach can be used to expose the server publicly as well, using a service like serveo.net

@gdevacc12

This comment has been minimized.

Copy link

@gdevacc12 gdevacc12 commented Nov 22, 2019

At least with Windows 10 version 1903 build 19018.1 with WSL2, it appears binding a service to a port on 0.0.0.0 can also be used without having to find the IP address of eth0.
From WSL2 if a service (e.g. httpd) is bound to a port (e.g. 8085) using address 0.0.0.0 (interface sit0@NONE the V6overV4 virtual adapter), then the service can be accessed from Windows using localhost.
Applying the firewall rules above (allowing inbound & outbound rules and portproxy) will disable access via localhost but allow a (remote) host to access the service on WSL2 via the Windows IP address.
Deleting the rules will allow localhost to be used again.
This could make it a little easier for switching between testing on the local Windows OS and a remote machine.,as it would not necessary to spot the service to switch the binding between localhost and the IP address of eth0.

@jbmorgado

This comment has been minimized.

Copy link

@jbmorgado jbmorgado commented Nov 26, 2019

The script by @edwindijas seems to break WinRM. After using it I am stuck with the following error when trying to use WinRM:
WinRM firewall exception will not work since one of the network connection types on this machine is set to Public

Although I am very definitively connected to a Private Network.

WimRm creates an HTTP listener this way, but fails to create the HTTPS listener.

I tried to reboot and to delete the Firewall rule that the script created but the error persists.

@ZenBoy999

This comment has been minimized.

Copy link

@ZenBoy999 ZenBoy999 commented Dec 5, 2019

Just found something interesting related to SEO, our web page: https://tech.yj777.cn/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3-wsl2/
was referer from this page. Because our page referred this page. So for those can read Chinese, you can also take a look into that article. Sorry, not that much related.

@nickweavers

This comment has been minimized.

Copy link

@nickweavers nickweavers commented Dec 8, 2019

On WSL-1 I could have an apache web server using vhosts to serve a number of websites. In my windows hosts file I just needed to have entries to the vhost domains assigning them the loopback IP address 127.0.0.1.

This was great, I could replicate setup's like for example, having two websites using services form a third; a couple of Wordpress sites, say, my-wp-site-1.local and my-wp-site-2.local that use a plugin to communicate with a rest based API service hosted at, say, my-api-site.local. I could set my hosts file to resolve all of those domains to 127.0.0.1, then setup the corresponding vhosts.conf files in WSL-1 /etc/apache2/sites-available, a2ensite them, reload apache and hey presto my wp sites would appear in my browser for http://my-wp-site-1.local or http://my-wp-site-2.local and their plugin could use the web services at http://my-api-site.local.

I addition, the web files could be in the windows file system so my windows based coding IDE worked as normal, but also accessed in WSL-1 via /mnt so the webserver running there could access them (vhosts.conf's) and I could use git commands there in the bash terminal to push/pull code to origin.

It wasn't a very portable setup, but still better than anything I'd had before.

Then came WSL-2 and I saw that it could use Linux containers. This looked even better; there is potential for a portable setup. I can have my vhosting wp server in one container for my-wp-site-1.local and my-wp-site-2.local, my rest api server my-api-site.local in another (they have different php mods and stuff) and I imagined each container could run with it's own IP address assigned so I can again use the windows hosts file to resolve domains so that http requests go to the correct container.

And better still, this setup would mirror what I could implement, say, in AWS under ECS or Fargate.

Sadly, I was soon to be frustrated at how difficult this was to achieve and disappointed that such a promising development fell short of providing what I needed.
I can't seem to find a way of setting this up that is within the limits of my basic networking knowledge. I also think that my use case is very probably a common one so for WSL-2 to be useful to people with it, it should not be this hard to achieve what I have described.

I hope cleverer minds that mine can find a way to make this happen so that I don't need an elaborate setup to achieve it.

Things I've noticed while trying to make it work:
ifconfig in my my WSL-2 session shows:
eth0: inet 172.19.71.88
docker0: inet 172.17.0.1

and in my container when I start the apache daemon I see:
root@a50e655f4b8c:/# service apache2 start

  • Starting Apache httpd web server apache2
    AH00558: apache2: Could not reliably determine the server's fully qualified domain name,
    using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message

So the container is getting allocated another IP address in WSL-2's network by incrementing the last octet , and I guess each new container would get the same.

If I try to browse to 72.17.0.2 from windows, the request times out as the address can't be reached. I understand that a fix for this was to add magic that caused localhosts to give you access, but that doesn't allow me to use my local dev domain names as was the case when using 127.0.0.1 under WSL-1.

I have no idea if the following suggestion I'm going to make is possible, but from an end user perspective it would make this kind of setup easier.
I would configure my router to reserve an IP address range to be excluded from DHCP (say 192.168.0.1 to 192.168.0.50), and then add my dev domain names to my hosts file using ip address from within that range.
I would then use the docker run command using, the --ip option, like --ip 192.168.0.1

Better still would be a flag that let me pass a local domain name and which and updated docker run command could do the lookup on my hosts file to get the corresponding ip address.

@hwasoocho

This comment has been minimized.

Copy link

@hwasoocho hwasoocho commented Dec 14, 2019

Until this issue is solved, I am using ngrok. It allows you to expose localhost with public ngrok urls.

@gmorenz

This comment has been minimized.

Copy link

@gmorenz gmorenz commented Dec 17, 2019

One liner forward ports. Listenport is the world visible port, connectport is the port on the linux (and windows localhost) side of things.

 netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=80 connectaddress=localhost connectport=8888

If you're using the windows firewall you're going to need to open the port in that before other computers can access it still.

@sinapis

This comment has been minimized.

Copy link

@sinapis sinapis commented Dec 23, 2019

@gmorenz does this workaround persist after restart?

@luxzg

This comment has been minimized.

Copy link

@luxzg luxzg commented Jan 18, 2020

Please note that in case of multiple distros running as WSL2, you still need network bridging, and workaround using port forwarding would quickly become unusable (and not "just" awkward as is), eg. running same service type on multiple WSL2 distros, using same ports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can鈥檛 perform that action at this time.