Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connecting to WSL2 server via local network

I'm developing a rails app using WSL2/Ubuntu on my Windows 10 machine, which is great! The problem is I can't connect to my server from another computer in the same network.

For further clarity, I am running a Puma server on localhost:3000

I have tried the following:

  1. Directly connecting to the IP address assigned to Ethernet adapter vEthernet (WSL) -> 172.26.208.1:3000
  2. Directly connecting to the host machine's IPv4 address -> 192.168.0.115
  3. Adding a firewall exception (using Bitdefender)
  4. Binding the IPs above rails s -b 172.26.208.1 -p 3000

None of the above have worked thus far... What I'd like to do is:

  • Test the website on another laptop/tablet/phone
  • Use VScode from another computer

Is there anything I'm missing to at least see the website correctly? (and any comments on the VScode part would be appreciated)

like image 871
Sebastian Rivas Avatar asked Apr 02 '20 23:04

Sebastian Rivas


People also ask

How do I access wsl2 host?

While this is not a common scenario, you can follow these steps to make it work. Obtain the IP address of your host machine by running this command from your Linux distribution: cat /etc/resolv. conf Copy the IP address following the term: nameserver. Connect to any Windows server using the copied IP address.

Does wsl2 use NAT?

As for accessing the WSL instance from the local Windows machine or from other devices on the network, because the WSL interface is NAT'd behind the Windows interface, it requires port forwarding.

How do I connect to WSL remotely?

Alternatively, you can open a Remote WSL window directly from VS Code: Start VS Code. Press F1, select Remote-WSL: New Window for the default distro or Remote-WSL: New Window using Distro for a specific distro. Use the File menu to open your folder.


Video Answer


6 Answers

See this video, it helped me:

https://www.youtube.com/watch?v=yCK3easuYm4

netsh interface portproxy add v4tov4 listenport=<port-to-listen> listenaddress=0.0.0.0 connectport=<port-to-forward> connectaddress=<forward-to-this-IP-address>

for example

netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=172.30.16.3

Microsoft has published a little bit of information about this on their WSL1 to WSL2 comparison page

like image 51
Akbar Pulatov Avatar answered Oct 21 '22 07:10

Akbar Pulatov


Option 1: Use port forwarding

This one worked for me:

  1. Run the port forwarding by a script from xmeng1: https://gist.github.com/xmeng1/aae4b223e9ccc089911ee764928f5486

The firewall commands in that script didn't work on my system. So I deactivated the Windows firewall completely and use the following stripped version. (The final users will use a 3d party firewall anyway, so that's ok).

$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=@(123,456);

#[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 ",";

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";
}

#Then so something, e.g.
#bash.exe -c "cd /g-inverter; ./start_docker.sh"

You may need to "apt install net-tools" for ifconfig in the script. There's also a solution with "ip addr" in the internet somewhere that does not need ifconfig" in a great thread, I haven't a link for here and now.

Caveat

This works only for TCP traffic. netsh interface portproxy does not support port forwaarding of UDP traffic.

Option 2: Bridge mode

Solution: Switch from NAT to Bridge mode

WSL2 comes by default in NAT mode. There the wsl2 system has another ip in another subnet than the host. The PC is from external peers only visible by the windows IP and the wsl2 ip/net is hidden/internal. So all traffic would need to be accepted by the windows IP and then forwarded to the wsl2 ip (port forwarding).

There is another mode called bridge mode. In bridge mode your network interface card will be shared to the wsl2 system, and it will get its own IP/Net in wsl2. So in effect your network card is shared to both systems (windows / wsl2) and will have two IPs, as if you'd have two systems with its own network card each. Cool thing: You will never have port conflicts when Windows uses the same port as well, as your wsl2 app (like 111).

Enable bridge mode

Open Hyper-V Manager as administrator

Select your pc, open Virtual Switch Manager

Select WSL

Set to external network

Select the network card the traffic runs through

Then login to wsl2 terminal and configure an IP address. E.g.

sudo ip addr add 192.168.0.116/24 dev eth0

You need to use another free IP (not your Windows IP). If your network has a DHCP server your wsl can get one by:

sudo ip addr flush dev eth0
sudo dhclient eth0

Caveat

I haven't elaborated yet, how to get DNS working in this scenario in case you want to still be able to access the internet (apt etc.). There's some documentation from MS written in /etc/resolv.conf and maybe executing what's written there and installing resolvconf (prior to all steps above, as you have no internet once you start to bridge) might do the trick.

like image 32
Roelof Avatar answered Oct 21 '22 09:10

Roelof


First, you will need to open a port in your machine to be able to access it from your network.

netsh advfirewall firewall add rule name="Allowing LAN connections" dir=in action=allow protocol=TCP localport=5000

After you open the port (5000 in my case) you will need to make port forwarding from this port to the port that your app is listening on in the WSL.

netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=5000 connectaddress=localhost connectport=<the port that your app is listening on>

Notice: I set the connectaddress to localhost not to the IP address of the WSL because by default the requests that go to localhost are forwarded to the WSL. By doing this you won't need to set the port forwarding every time you restart your machine because the IP address of the WSL is dynamic.

like image 45
Hazem Essam Avatar answered Oct 21 '22 08:10

Hazem Essam


WSL2 exposes ports on the local interface (which is why in Windows you can access localhost:8080 when your 8080 service is running in WSL2), but they listen on 127.0.0.1 (which is why you can't access yourhostname:8080 on other computers your LAN).

There's a tool to fix this called WSLHostPatcher, which you can find here (download via the Releases section): https://github.com/CzBiX/WSLHostPatcher

WSLHostPatcher changes the behaviour to listen on all IPs, exposing any WSL2 services to all computers on your network.

  1. Download the latest release from https://github.com/CzBiX/WSLHostPatcher/releases (I tested v0.1.0)
  2. Unzip the file
  3. Run the WSLHostPatcher.exe
  4. (Re)start your service in WSL2

The service should now be accessible via other computers on your network.

like image 24
Malcolm Crum Avatar answered Oct 21 '22 07:10

Malcolm Crum


Getting your WSL2 distro to behave like any other client on your network

Building on Roelofs suggestion no.2, here's what made everything tick in my case. I'm too fresh to just leave a comment unfortunately.

My starting point:
Win 10 Pro
Ubuntu under WSL2
(Docker with Linux containers)

My goal:
Getting an rtmp stream from a client on the network into and back out of an nginx server running on the Ubuntu machine.

Building the bridge

In my case, I could not get Hyper-V to set the bridge up properly. After selecting External network for the WSL switch in the Virtual switch section of Hyper-V Manager and hitting apply, it eventually failed with error 0x80070490. Don't know why and didn't have the time to investigate. WSL was not running and neither was the Docker service.

Instead, I just left the setting on Internal network and bridged the interfaces the manual way, under Network Connections (run->ncpa.cpl). In my case, the WiFi connection and vEthernet (WSL). Immediately after doing this, I lost internet connectivity and it took me an embarrassingly long time to find out that a reboot was needed. (Windows for once did not ask me to!)

Getting the VM in shape

After the reboot, I now had internet access from the host, the bridge was set to DHCP and had inherited the IP of the WiFi interface (192.168.1.246). Great.

The VM however was still getting the IP of the virtual switch (or however you want to view it, the random 172.x.x.x address that windows seems to assign to the switch as well as the VM).

Firing up Ubuntu, I decided to do a:

sudo ip addr flush dev eth0

Continuing with:

sudo dhclient eth0

threw a handful of errors at me since I was using the vanilla Ubuntu distro from Windows store, no systemd, no fun. Despite that, it did manage to add the IP of the bridge to eth0. As this was not very handy, I got rid of that with:

sudo ip addr del 192.168.1.248/24 dev eth0

but not before taking a sneak peek at the routing table:

user@vm:~$ route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         192.168.1.1     0.0.0.0         UG    0      0        0 eth0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0

After deleting the old IP, I added a unique one from outside of my DHCP range:

sudo ip addr add 192.168.1.50/24 dev eth0

I checked the routing table again and the first entry was gone. At this stage I could ping LAN but not WAN.

Added the entry back with:

sudo ip route add default via 192.168.1.1 dev eth0

Pinging WAN IPs was now possible, but no DNS resolution. LMGTFM: Adding permanent DNS In case the solution goes missing, here it is, credit to non-static:

Create a file: /etc/wsl.conf.
Put the following lines in the file

[network]
generateResolvConf = false

In a cmd window, run wsl --shutdown
Restart WSL2
Create a file: /etc/resolv.conf. If it exists, replace existing one with this new file.
Put the following lines in the file

nameserver 8.8.8.8

Or the IP of whatever DNS server you want to use, repeat step 3 and 4.

So, to conclude, check your routing and setup your DNS-conf properly. Unfortunately, the IP settings are reverted every time you restart WSL. If you are not ok with doing this manually every time there are discussions on how to automate it here and here. I haven't had the time to find my favorite.

Best regards Alexander

like image 11
AlexanderL Avatar answered Oct 21 '22 08:10

AlexanderL


Taking into consideration the above (correct) solutions this is a simplified one liner version that works for me:

  1. Use "ifconfig" to find your wsl2 public IP address. Have in mind that The Hyper-V Switch IP change everytime when the Windows reboot, so the Public IP in wsl2 also changes. enter image description here
  1. Run the following command using the IP found in the previous step in connectaddress parameter:

    netsh interface portproxy add v4tov4 listenport= listenaddress=0.0.0.0 connectport= connectaddress=172.24.26.277

Parameters explanation:

  • listenport: the port that Windows will listen

  • listenaddress: the address that your Windows will listen. Usually 0.0.0.0 should do.

  • connectport: the port that your Linux Distro through wsl2 will listen.

  • connectaddress: the public IP of your Linux wsl2 instance (found in step 1)

Use cmd or PowerShell as Administrator to run the above command.

like image 11
Pavlos Klonis Avatar answered Oct 21 '22 07:10

Pavlos Klonis