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)


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

Don't forget to put feedback after.


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.


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.