skip to content

How is a WSL2 distribution attached to the network by default, and why can a browser on Windows reach a server listening on localhost inside WSL2 while a process inside WSL2 cannot reach a Windows service the same way?

level: seniorimportance: should knowfreq 50%

answer

  1. the VM has its own address
  2. one direction is relayed, not routed
  3. localhost means two different hosts
  4. second suspect: the host firewall
  5. mirrored mode removes the asymmetry

basics

~20 s

By default the WSL2 utility VM sits behind NAT on its own virtual adapter with its own IP. Windows-to-Linux works because WSL relays Windows localhost connections into the VM; there is no relay in the other direction, so localhost inside the VM means the VM.

solid answer

~50 s

WSL2 runs the distribution in a lightweight VM attached to a virtual switch and NAT'd behind the Windows host, so it has its own private IP, not the host's. The asymmetry comes from a relay, not from routing: WSL forwards connections made to `localhost` on Windows into the same port inside the VM — that is the `localhostForwarding` setting in `.wslconfig`, on by default — which is why `localhost:3000` in a Windows browser reaches a dev server bound inside WSL2. Nothing does the reverse. Inside the VM, `localhost` is the VM's own loopback, so to reach a Windows-hosted service you need the host's address on the WSL network — the address WSL writes as the nameserver in `/etc/resolv.conf` — and Windows Defender Firewall usually still has to be told to allow it. That IP also changes across restarts, so never hard-code it. On Windows 11, `networkingMode=mirrored` removes the asymmetry by mirroring the host's interfaces.

code

bash · 4 lines
bash
# From inside WSL2 (NAT mode): find the Windows host's address
WIN_HOST=$(grep -m1 '^nameserver' /etc/resolv.conf | awk '{print $2}')
echo "$WIN_HOST"
curl -sS --max-time 5 "http://$WIN_HOST:8080/" || echo "blocked or not listening"

go deeper

for a junior

Know that WSL2 runs in a VM with its own IP, that a server you start in WSL2 is normally reachable from a Windows browser at localhost, and that the reverse direction is not automatic.

for a middle

Explain that Windows-to-Linux works through a forwarding relay controlled by localhostForwarding, while the Linux side must use the host's address on the WSL network because its own localhost is the VM's loopback.

for a senior

Debug it methodically: check the bind address, then the host firewall on the WSL adapter, and avoid hard-coded addresses that the platform reassigns. Know that mirrored networking is the structural fix and when it is available.

for a principal

Decide the standard for the organization: whether developer machines run mirrored networking given the Hyper-V firewall implications, how services under development are exposed and secured, and whether WSL should be reachable from the corporate network at all.

## The default: a NAT'd utility VM Under WSL2 the distribution runs inside a Hyper-V utility VM with a virtual network adapter on a virtual switch created for WSL. Windows holds an interface on that same internal network, and outbound traffic from the VM is **network-address-translated** behind the host. Practically: - The VM has its own private IP address, distinct from any address Windows shows for its physical NIC. - Outbound connections from Linux to the internet work transparently, appearing to come from the Windows host. - Inbound connections from the LAN do **not** reach the VM, because nothing on the outside knows it exists. WSL1 behaved completely differently: it had no VM and shared the Windows network stack directly, so `localhost` was the same `localhost` on both sides. Everything below is a consequence of that change. ## Windows → Linux: a relay, not routing Start a dev server inside WSL2 on port 3000 and a browser on Windows can usually open `http://localhost:3000`. That is not routing — a Windows `localhost` connection cannot traverse into a separate VM by itself. WSL runs a **forwarding relay** on the Windows side that accepts connections to `localhost:<port>` and proxies them into the VM on the same port. It is governed by `localhostForwarding` in `%UserProfile%\.wslconfig`, enabled by default, and it works even when the Linux service is bound only to `127.0.0.1` inside the VM. ```ini [wsl2] localhostForwarding=true ``` Because it is a relay rather than a route, it has relay-shaped failure modes: it applies to the running distribution, it can miss ports opened at unusual moments, and a `wsl --shutdown` plus restart is the standard remedy when a port stops forwarding. ## Linux → Windows: no relay exists There is no symmetric relay. Inside the VM, `127.0.0.1` is the VM's own loopback interface, so a Linux process pointing at `localhost:8080` is asking for a Linux service on 8080 and gets `ECONNREFUSED` if none is listening. To reach a service hosted on Windows you must use the **host's address on the WSL network**. When `generateResolvConf` is left enabled, WSL writes that address into `/etc/resolv.conf` as the `nameserver`, which makes it the conventional way to discover it at runtime: ```bash WIN_HOST=$(grep -m1 '^nameserver' /etc/resolv.conf | awk '{print $2}') curl "http://$WIN_HOST:8080/health" ``` Then expect a second obstacle: **Windows Defender Firewall**. The WSL adapter is a separate network the firewall evaluates on its own, and inbound rules commonly block traffic from it, so a service that works from a Windows browser still times out from Linux until a rule permits it. Note too that a Windows service bound only to `127.0.0.1` is unreachable from the VM no matter what the firewall says — it must listen on the interface the VM can see. ## The address is not stable Both the VM's address and the host's address on the WSL network can change when WSL shuts down and restarts. Hard-coding either into a config file, a hosts entry or a container definition is a classic bug that works all afternoon and breaks the next morning. Derive it at runtime, as above. ## Exposing a WSL service to the rest of the LAN Other machines see the Windows host, not the VM. To publish a WSL2 service externally you forward the port on the Windows side — `netsh interface portproxy` is the built-in mechanism — and add a firewall rule for it. Because the VM's IP moves, that mapping needs refreshing, which is exactly why people script it or avoid the arrangement altogether for anything long-lived. ## Mirrored networking removes the asymmetry Current WSL on Windows 11 offers an alternative mode, set in `.wslconfig`: ```ini [wsl2] networkingMode=mirrored ``` In mirrored mode the VM mirrors the host's network interfaces instead of sitting behind NAT. `localhost` then works in **both** directions, the Linux side sees the host's addresses including IPv6, and services in WSL become reachable from the LAN. It also brings related options such as DNS tunnelling and a Hyper-V firewall applied to the VM. Mention the version dependency when you recommend it — it is not available on older Windows 10 builds, where NAT is all you have. ## What the interviewer is checking That you explain the asymmetry with a mechanism — a one-way relay on top of NAT — instead of calling it a quirk; that you know `localhost` means different things on the two sides; that you reach for the firewall as the second suspect; and that you do not hard-code an address the platform reassigns.

  • A colleague hard-codes the WSL2 VM's IP address into a config file. What goes wrong?
    The address is assigned when the utility VM starts and can change after `wsl --shutdown`, a reboot or a Windows update. The configuration then points at nothing, producing intermittent connection failures that look random. Derive the address at runtime, use the localhost-forwarding path from Windows, or switch to mirrored networking where the question does not arise.
  • You can curl a Windows service from a Windows browser but not from WSL2. What do you check first?
    Two things. Whether the service is bound to 127.0.0.1 on Windows — if so, the VM cannot reach it at all and it must listen on an interface the WSL network can see. And Windows Defender Firewall, which evaluates the WSL adapter as its own network and commonly blocks inbound traffic from it until a rule allows the port.
  • How would you make a service running in WSL2 reachable from another machine on the LAN?
    In default NAT mode the LAN sees only the Windows host, so you forward the port on Windows — `netsh interface portproxy` — to the VM's current address and add an inbound firewall rule. Since that address can change, the mapping needs refreshing. On Windows 11, mirrored networking makes the service reachable directly and avoids the bookkeeping.

saying these in an interview costs you the question

  • Assuming localhost is shared between Windows and WSL2
  • Believing the VM has the same IP as the Windows host
  • Hard-coding the WSL2 address in configuration
  • Ignoring Windows Firewall when Linux-to-Windows fails
  • Thinking LAN machines can reach WSL2 services by default

context