Linux – localhost and 127.0.0.1 working but not ip address in wsl windows 10

iplinuxlocalhostnode.jswindows-subsystem-for-linux

I recently switched from Linux to WSL2 (Ubuntu 20.04) on Windows 10. When I run any NodeJs application or a server like Apache or Nginx everything works fine on localhost or 127.0.0.1 but doesn't work when I use my local IP address (192.168.1.65).

netstat -tupln when running node js application

I have tried turning off firewall in windows and wsl but it didn't work.

I enabled the IIS from "Program and Features" and it seems to work fine on localhost and ip. So, I figured it wasn't a problem with the network.

IIS for test purpose

All the post I have read suggest that if the site is accessible through 127.0.0.1 and not through ip then you can configure the server config files for Apache or Nginx. But I reinstalled wsl and am hosting through NodeJs / Express only.

The code for the express app's server.js is:

const express = require("express");
const next = require("next");

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  const server = express();
  server.use(express.static("public"));

  server.all("*", (req, res) => {
    return handle(req, res);
  });

  server.listen(port, "0.0.0.0", (err) => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${port}`);
  });
});

All I want to do is access the site on my mobile on the same network.

/etc/hosts

ipconfig on windows

Best Answer

The core issue here is that WSL2 operates in a Hyper-V VM with its own virtual NIC, running NAT'd behind the Windows host. WSL1, on the other hand, ran bridged with the Windows NIC.

On localhost, Windows does seem to do an automatic mapping, but for the host IP address (and thus, on the local network), it does not.

You'll find a lot of information on this particular topic on this Github thread, along with several workarounds:

Option 1: WSL1

First, and the simplest, is to use WSL1 if you can for this particular application. You can convert the WSL2 instance to WSL1 by either doing (from PowerShell) a wsl --set-version <distroname> 1 or by cloning the existing with a wsl --export <distroname> <archivename>.tar and then wsl --import <distroname> <installlocation) <archivename>.tar. I prefer cloning since it gives you a backup.

Option 2: Windows port forwarding using netsh

Port forward under Windows using netsh per this comment on that thread. Note that the virtual NIC for the WSL2 instance gets a new address on each reboot, so you'll have to either repeat the netsh command on each reboot or set it up in a script as described and set it to run on each boot via Task Manager. Note also that you'll need ot modify Windows firewall rules.

Option 3: Port forward through WSL1 with socat

  • Set up a basic WSL1 instance alongside your WSL2 instance
  • Install socat on both
  • From the WSL1 instance, run socat -d -d TCP-LISTEN:3000,reuseaddr,fork EXEC:'wsl.exe -d <WSL2DistroName> "socat -d -d TCP-CONNECT:127.0.0.1:3000 -"', making sure to replace with the correct name (without brackets).

That will basically port forward anything on port 3000 on WSL1 to 3000 on WSL2, and since WSL1 runs "bridged" anyway, connections to port 3000 on the Windows host are going to go through that route as well.

This has the advantage over the netsh option of not needing to worry about the WSL2 IP changing on each boot, since it works over stdout of the wsl.exe command.

Option 4: Bridge Mode

If you are running on Windows 10 Pro or higher, there are instructions in that thread on how to run the WSL2 NIC in bridge mode. I've never gone this route, since I've been able to use the other three methods.

Related Question