hardware/windows/wsl-lan-access.md
Table of Contents
WSL: LAN Access for Services
Current machine state (2026-09-19)
- Windows WSL version: 2.7.14.0
- Ubuntu is a WSL 2 distro.
- WSL's default distro was
docker-desktop; runwsl --set-default Ubuntuonce so plainwslopens Ubuntu.
Starting Ubuntu
wsl
This starts Ubuntu if it is stopped. exit returns to PowerShell. Use wsl -d Ubuntu when an explicit distro selection is useful.
If WSL returns Catastrophic failure / Wsl/Service/E_UNEXPECTED, the successful recovery sequence was:
wsl --shutdown
Restart-Service WslService -Force
wsl --update
wsl -d Ubuntu
Run the service restart from an elevated PowerShell. wsl --shutdown stops all WSL distros, including Docker Desktop's WSL backend.
Exposing a WSL service on the LAN
Recommended: mirrored networking
Create C:\Users\domin\.wslconfig:
[wsl2]
networkingMode=mirrored
Apply it with:
wsl --shutdown
This also stops WSL/Docker temporarily. Start WSL again afterward with wsl.
Mirrored mode is not broad, automatic port forwarding. It lets WSL participate directly in the host's networking, but the Hyper-V firewall still blocks unsolicited inbound LAN traffic by default.
For each service intended for LAN use:
- Make the service listen on
0.0.0.0:<port>in WSLโnot just127.0.0.1. - Add a narrowly scoped Hyper-V firewall allow rule for the required TCP or UDP port from elevated PowerShell.
- Reach it from another device at
http://<Windows-LAN-IP>:<port>.
Example: allow TCP port 3000 for WSL:
New-NetFirewallHyperVRule `
-Name "WSL-TCP-3000" `
-DisplayName "WSL TCP 3000" `
-Direction Inbound `
-VMCreatorId "{40E0AC32-46A3-4E02-9C4E-9C6F1CEFAF82}" `
-Protocol TCP `
-LocalPorts 3000
For a stricter LAN-only rule, add the local subnet (adjust it to the actual LAN):
-RemoteAddresses "192.168.1.0/24"
Create separate rules for every intentionally exposed TCP/UDP port. Do not disable the WSL/Hyper-V firewall just to make a service reachable.
Alternative: NAT + portproxy
Mirrored mode is not required. In the default NAT mode, a WSL listener is already
reachable on Windows at 127.0.0.1:<port> (WSL localhost forwarding). Forward the LAN
in from there with a Windows portproxy pointing at loopback โ not the WSL IP โ so
it survives the dynamic WSL address across reboots:
New-NetFirewallRule -DisplayName "<svc> (TCP <port>)" `
-Direction Inbound -Action Allow -Protocol TCP -LocalPort <port> -Profile Private
netsh interface portproxy add v4tov4 `
listenaddress=0.0.0.0 listenport=<port> connectaddress=127.0.0.1 connectport=<port>
This needs an elevated shell; the rule and portproxy are persistent. It avoids the
global .wslconfig change (and its WSL restart) that mirrored mode requires.
Still used on this machine for: sshd (port 2204) โ works fine either way, left alone.
No longer used for: pi-web (port 30142) โ retired 2026-09-21 when the whole machine
switched to mirrored mode; a leftover portproxy rule for it had to be deleted because it
conflicted with WSL's own direct bind under mirrored mode. See
../ubuntu-wsl/services/pi-web.md ยง4/ยง9.
When mixing the two approaches on one machine (as here): once mirrored mode is on
globally, any new NAT-style loopback portproxy you add for a service that WSL now
binds directly under mirrored networking will conflict (EADDRINUSE) rather than
coexist. Portproxy rules only make sense here for cases where you deliberately still
want the old relay-via-loopback behavior (e.g. if a service's WSL-side bind address is
finicky) โ check for and remove stale ones first.
Local-only services
For ordinary development, access WSL services from Windows at http://localhost:<port>. No LAN rule is needed unless another device must connect.