Connecting to WSL2 server via local network

154,618

Solution 1

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

Solution 2

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.

Solution 3

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.

Solution 4

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.

Solution 5

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

Share:
154,618

Related videos on Youtube

Sebastian Rivas
Author by

Sebastian Rivas

Updated on July 08, 2022

Comments

  • Sebastian Rivas
    Sebastian Rivas almost 2 years

    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)

  • Roelof
    Roelof almost 4 years
    Update: This approach became tedious and threads in the internet get longer and longer where people struggle with it. We decided that WSL2 is not mature enough for stable server hosting and finally decided to install all servers on Windows. WSL2 docker instances put files to Windows folders, that are hosted then with Windows servers. This meant that we needed to license, install and maintain 3d party products on every PC. But we're not convinced enough of WSL2 being industry ready. I'm sure this will get better in a few years. We're 100%ly long term stable now.
  • Mike Slinn
    Mike Slinn almost 4 years
    Bridge mode sounds like it might be a good solution, but my machine running WSL2 does not have the Hyper-V windows extension enabled, and reading the Hyper-V docs makes be worry that this feature might cause problems.
  • The_Immortal
    The_Immortal almost 4 years
    @Roelof Well, the Option 1 actually doesn't work: after executing the above script (exactly as it was posted) I don't see any additional rules at Windows firewall and port forwarding doesn't work. Also I've tried to completely turn off Windows firewall - still no effect. Any help please? Thanks!
  • Mitkins
    Mitkins almost 4 years
    "The firewall scripts didn't work for me, so I completely turned off the firewall" is terrible advice. The firewall scripts did work for me, so please leave your firewalls intact people!
  • Mogzol
    Mogzol over 3 years
    Thanks, this works great. For anyone who doesn't want to watch the whole video, this needs to be run in an elevated powershell prompt, not from WSL, the connectaddress should be your WSL IP, and you'll probably need to allow the port through windows firewall. Side note, this is the same thing the script in the top answer is doing, but it's nice to just see the necessary command rather than the whole script.
  • jmpp
    jmpp over 3 years
    Doesn't works for me unfortunately. I'm trying to connect to my local webserver with my iPhone (to test the mobile version of a website). My code is running in a WSL machine and opens a server after npm start on the port 1337. So I typed this netsh interface portproxy add v4tov4 listenport=1337 listenaddress=0.0.0.0 connectport=1337 connectaddress=127.22.240.165. I though I could try on my iPhone: 192.168.1.32:1337 but maybe I misunderstood the procedure.. Any help?
  • Akbar Pulatov
    Akbar Pulatov over 3 years
    Can you reach your sever from local machine? It should be like: 127.22.240.165:1337, if not, that is your problem related to your server app. If yes, try to disable firewall, or maybe your wsl ip address is wrong, double check it. Try bridge mode, cause this method is for temporary uses, because the ip address changes everytime you restart the host.
  • jmpp
    jmpp over 3 years
    Yes I can reach the app from Windows via http://127.22.240.165:1337. I tried to disable the Windows firewall and test again on the phone, but it still doesn't respond. On the other hand, the netsh ... command didn't output anything ; I expected it would awake the Firewall at the first try, but no. Maybe the "portproxy" didn't have any effect. How can I check what proxies are set up on Powershell?
  • jmpp
    jmpp over 3 years
    I could see what proxies were set up by using netsh interface portproxy show v4tov4 and they were all set. I also tried to clean them all and test again, and I was still able to reach the app via http://127.22.240.165:1337 on Windows (even with no portproxy), but I definitely can't join my app from my iPhone 😥 Maybe that could come from my Internet box ?
  • NotTheDr01ds
    NotTheDr01ds over 3 years
    While there are socat based solutions that work for me, this one causes a "fork storm" as the port 3000 connection forks a connection to 3000, which forks another connection to 3000, and so on until I had so many socat's running before I could interrupt it that my Windows host was brought to a crawl (and it's not a slouch).
  • Charl Botha
    Charl Botha over 3 years
    This is strange, I use this exact formulation, but with port 8000, from WSL1 in order to reach the Django running on my WSL2 with my iPhone. There must be some other difference between our two configurations.
  • NotTheDr01ds
    NotTheDr01ds over 3 years
    Agreed. I was thinking that it might have to do with some leftover forwarding rule from previous attempts (on mine), but I think I cleared everything out (e.g. netsh interface portproxy). I'll try on another port just to make sure, but failure pretty much means a reboot, so I'll have to wait until I'm ready for that.
  • JakeAve
    JakeAve over 3 years
    I'd like to add that I had a weird issue where my ipv4 for WSL in powershell after running ipconfig was different than what my Ubuntu was saying. The IP Ubuntu was saying was correct and for whatever reason the WSL ipv4 in the ipconfig command was not right. Might have to do with the Ethernet port.
  • Oz Solomon
    Oz Solomon about 3 years
    For me, this wasn't enough. I had to uncheck the Hyper-V Extensible Virtual Switch setting on my network card as described here: theitways.blogspot.com/2018/01/…
  • Jos Faber
    Jos Faber about 3 years
    Don't forget to add the listen port to the firewall to be able to connect: netsh advfirewall firewall add rule name= "Open Port 3000" dir=in action=allow protocol=TCP localport=3000
  • jdunk
    jdunk about 3 years
    This sounds great, but the instructions don't work. There is no WSLHostPatcher.exe file. Not many stars on the repo... is this legit?
  • jdunk
    jdunk about 3 years
    Just wanted to say that after attempting every possible fix for > 6 hours while absolutely nothing worked (even disabling defender/firewall entirely), THIS is what finally did it for me. I simply cannot access the WSL2's ip address from outside of the host machine in any other way. Thank you!! 🙏🙏
  • Malcolm Crum
    Malcolm Crum about 3 years
    WSLHostPatcher.exe is in the release.zip file. If you're skeptical you could compile it yourself from the repo after examining the source. Not my repo so I can't guarantee it!
  • ilw
    ilw almost 3 years
    ok , you forward 8000,8001 ports and... ? What next? What the practical use?
  • Константин Ван
    Константин Ван almost 3 years
    You have to allow the port through the Windows firewall, and forward it on your router. And beware that the WSL2 IP address gets reassigned every time you restart the instance.
  • Константин Ван
    Константин Ван almost 3 years
    And you don’t need to do ifconfig. hostname --all-ip-addresses does the job.
  • Hunkoys
    Hunkoys almost 3 years
    I don't know why this isn't the best answer. It's basically two PowerShell pastes and no download needed.
  • Shinebayar G
    Shinebayar G over 2 years
    This is the only working answer!
  • Shinebayar G
    Shinebayar G over 2 years
    By the way it works just fine on HTTP server. However I couldn't get my DNS server working. Pi-Hole is running inside WSL2 and I did the port forward setting. I can see port 53 TCP is listening on both windows and WSL2. However external clients cannot use the DNS server ... Any ideas?
  • DuelistPlayer
    DuelistPlayer over 2 years
    "I can see port 53 TCP is listening on... windows.... However external clients cannot use the DNS server" Interesting scenario! @ShinebayarG are you saying that you are able to use pihole in wsl as your windows nameserver? i.e. Is the problem that even though you configured windows portproxy for 53 and 80, when you configure your other in-network devices' nameserver to point to your windows device (which will use those ports), that doesn't work for them as a nameserver?
  • DuelistPlayer
    DuelistPlayer over 2 years
    @ShinebayarG follwup question about port 53: The example in the answer step 1 includes argument -Protocol TCP. Any chance that your port 53 DNS needs you to allow UDP as well? Ditto the netsh interface portproxy command has optional protocol param.
  • Shinebayar G
    Shinebayar G over 2 years
    yes that's correct. WSL2 + Host Windows can use the Pi-Hole just fine. It's just other network devices like my phone & other laptop can't use it. I checked the firewall + Pi-hole settings, they both look fine. netsh interface protocol only accepts tcp according to their docs docs.microsoft.com/en-us/windows-server/networking/technolog‌​ies/…
  • DuelistPlayer
    DuelistPlayer over 2 years
    @ShinebayarG re "netsh interface protocol only accepts tcp", that's interesting I was distracted by the "protocol: Specifies the protocol to use", but didn't notice that there is only 1 protocol you can specify. Disappointing! Have you looked at superuser.com/a/1637776/93731? It suggests one tool for UDP forwarding on Windows, and has 12 votes plus a comment from a user saying they successfully used it for self-served DNS.
  • Shinebayar G
    Shinebayar G over 2 years
    It has only 1 answer with 1 vote. Did I miss something?
  • DuelistPlayer
    DuelistPlayer over 2 years
    @ShinebayarG You didn't miss something, I pasted the wrong link! I meant to share this one from serverfault: serverfault.com/a/472692/117183
  • gabtzi
    gabtzi over 2 years
    Option 2 is not possible as the Virtual switch manager is unable to change the wsl switch to external. It will throw an error switch port delete failed ...
  • Ben Creasy
    Ben Creasy over 2 years
    Hmm, localhost didn't work for me - I had to specify the WSL ip address directly.
  • Abdull
    Abdull over 2 years
    On my computer, I had to activate the firewall rule also for the Domain and Public profiles additionally to the Private profile.
  • DuelistPlayer
    DuelistPlayer over 2 years
    Correct @Abdull; good point about Domain profile being another safe option, I'll add that to the answer. For Public profile you would want to highlight really a big ⚠️ about “... that also works, but then you're opening a port — running "dev" software — on a Public network.”... really have to ask the question why am I doing network based dev work on a network that I can't trust so I have it configured as "Public"? But yes if there's reasons why that's a safe and good situation, can do it.
  • Hunkoys
    Hunkoys over 2 years
    Would this work with same ports? EDIT: It seems that it doesn't. (localhost to 0.0.0.0).
  • Tashi
    Tashi over 2 years
    After spending hours here and there, this worked like a charm for me. Thank you very much.
  • HughHughTeotl
    HughHughTeotl over 2 years
    Yep, same here. localhost didn't work and had to use the actual IP of the WSL. (Command 'ip addr' inside the Ubuntu WSL gave me the relevant address)
  • james28909
    james28909 over 2 years
    i was able to get it to work. i was able to even get udp ports to work as well. i have a device on my local network that is sending debug output over udp, and socat within wsl2 was able to pick it up. i set this in my /home/user_name/.bashrc echo nameserver 192.168.254.254 | sudo tee /etc/resolv.conf sudo sudo ip addr flush dev eth0 sudo ip addr add 192.168.254.25/24 dev eth0 sudo dhclient eth0 > /dev/null 2>&1 and then use sudo visudo to be able to run sudo command swithout the password (not point in it tbh in wsl)
  • james28909
    james28909 over 2 years
    once you do the above, you do exit bash/wsl and do wsl --shutdown. then go to hyperv and change the adapter to external. then go back to bash, and with the commands entered from the post above, it should be able to sudo apt-get update and socat udp-recv:18194 stdout
  • james28909
    james28909 over 2 years
    but be ready, because once you reboot, it obliterates your windows network adapters to the point that you have to go to control panel -> network and internet ->advanced network settings -> network reset. then reboot. then, heres the kicker. wsl is fried as well so you need to unregister and reinstall. good luck. microsoft has completely screwed this up too. like how tf can you not forward a UDP port to wsl? xd whos fuggin idea was this?
  • james28909
    james28909 over 2 years
    this doesnt work for udp ports
  • Ian Sudbery
    Ian Sudbery over 2 years
    @JakeAve I feel like this information is key. I also have this. My guess is that windows is forwarding traffic for WSL to the IP listed in ipconfig but WSL is listerning on the IP listed by ip addr inside WSL.
  • Naourass Derouichi
    Naourass Derouichi over 2 years
    Only localhost or 127.0.0.1 works for me. Specifying WSL ip doesn't work in my case.
  • Cherrymelon
    Cherrymelon over 2 years
    localhost or wsl actual ip both work for me,because i start up ip helper service when i realized i didn't open it
  • ahmet alp balkan
    ahmet alp balkan over 2 years
    You can also install netcat on Windows directly to forward a port and not need installing ssh server on WSL unix.stackexchange.com/questions/293304/…
  • aXul
    aXul over 2 years
    worked for me on win11 with wsl2 all updated and using localhost as connectaddress
  • ChrisCrossCrash
    ChrisCrossCrash about 2 years
    Setting connectaddress to localhost did the trick for me. I tried following the Microsoft documentation for this exact problem. They said to set the connectaddress to the IP of the WSL2 virtual machine, which didn't work for me.
  • Hazem Essam
    Hazem Essam about 2 years
    The WSL2 IP is changed every reboot so it's not a practical solution for me.
  • LachoTomov
    LachoTomov about 2 years
    That's the proper solution! It works even for the same port, but you'll need to change listenaddress=0.0.0.0 to your actual windows IP.
  • Firsh - justifiedgrid.com
    Firsh - justifiedgrid.com about 2 years
    On Win 11, the manual bridge cripples my host internet speed in half downstream and to 1% upstream. As soon as I delete the bridge, it returns to normal.
  • TobyHijzen
    TobyHijzen almost 2 years
    @gabtzi I ran into the same problem, turns out I need to shutdown wsl wsl --shutdown and run Hyper-V Manager as administrator.
  • gabtzi
    gabtzi almost 2 years
    This worked indeed. It wasn't working for me in previous builds but on latest it worked. I have a question, have you managed to set a static IP for eth0 permanently? I notice there's no /etc/network/interfaces file and it's not read
  • TobyHijzen
    TobyHijzen almost 2 years
    I have not. I'm still working on getting DNS working.
  • gabtzi
    gabtzi almost 2 years
    For the DNS I changed /etc/resolv.conf to use nameserver 8.8.8.8 and then used chattr +i /etc/resolv.conf to make sure wsl won't delete it. It worked pretty fine for me. The issue is assigning the static IP on the startup as the 3 commands in the answer suggest but when the interface goes up @TobyHijzen