Buy @ Amazon

Understanding the WSL2 Mirrored Networking Conflict

When optimizing your development environment on Windows, you might encounter a frustrating "silent failure" where Docker containers appear to run but remain unreachable via their assigned ports. This conflict typically stems from how WSL2 and Docker Desktop negotiate network traffic. (I had been through this when I tried to set-up my development environment for ReactNative/Expo application in Docker container.)

The Architecture: Mirrored vs. NAT

By default, WSL2 uses Network Address Translation (NAT). In this mode, WSL2 lives behind a virtual switch with its own IP address. While reliable, it adds a layer of complexity for local networking. (Spoiler Alert: I resorted to this legacy convention for reliability reasons, at the time of this writing having latest stable version of Docker Desktop). 
  • Reasons: Good default for general, isolated development; avoids complex network setup.
  • Downsides: Requires port forwarding to access localhost services from Windows; VPNs can break connectivity.

Mirrored Networking (`networkingMode=mirrored`) was introduced to solve this by "mirroring" the Windows network interfaces directly into WSL2. This allows Linux applications to see the actual Windows IP addresses. Mirrors physical/virtual network adapters into Linux (e.g., WiFi appears in Linux).
  • Reasons: 
    • VPN Compatibility: WSL2 directly uses Windows VPN routes.
    • Localhost Sharing: Use localhost in Linux to connect to Windows servers (and vice-versa).
    • LAN Connectivity: Other machines on your LAN can access services running in WSL2.
    • IPv6 Support: Native IPv6 support.
  • Downsides: This is the very purpose of this post, to elaborate on it. The reasons for its adoption as listed above is tempting enough to try it and I gave it a shot only to experience disappointment. It perhaps is still not ready as of April 2026.

The Root Cause of the Conflict

The conflict arises because both WSL2 (in Mirrored Mode) and Docker Desktop’s proxy services (like `vpnkit`) attempt to bind to the same Windows host ports simultaneously.
  • Docker Desktop expects to manage port forwarding from the host to the utility VM.
  • Mirrored Mode attempts to bind the Linux socket directly to the host interface.
When these two mechanisms collide, the port binding often fails silently, leaving the port "unowned" and unreachable. :/ (The amount of time I spent debugging this leveraging Gemini and Googling, to get to this conclusion is frustrating.)

The Diagnostic Experiment

To verify if your system is suffering from this specific conflict, follow these steps to reproduce the issue.

Step 1: Enable Mirrored Mode
Ensure your .wslconfig file (located in %USERPROFILE%\.wslconfig) contains the following configuration:
```
[wsl2]
networkingMode=mirrored
```

Step 2: Clear the State
You must ensure no stale processes are holding onto the network stack. Run the following in PowerShell:
```
# Shutdown WSL
wsl --shutdown

#Verify Termination: (Ensure status is "Stopped")
wsl -l -v 
```
Now, restart Docker Desktop: Use the system tray icon to "Restart".

Step 3: Deploy a Test Container
Launch a simple web server (Nginx) and attempt to map port 8081 on all host interfaces (0.0.0.0):
```
docker run --rm -d -p 0.0.0.0:8081:80 --name test-nginx nginx
```

Step 4: Verify the Binding Failure
Check if Windows actually recognizes an active listener on that port. Run this in PowerShell:
```
Get-NetTCPConnection -LocalPort 8081 | Select-Object LocalAddress, State, OwningProcess
```

Results Analysis:

  • Empty Result: This confirms the Mirrored Networking Conflict. Docker thinks the container is up, but Windows has no record of the port being bound.
  • Successful Binding: You would see entries for 127.0.0.1, 0.0.0.0, or your specific VPN/Tailscale IP addresses.

The Recommended Fix

If you require the stability of Docker Desktop port forwarding more than the benefits of Mirrored Mode, the most effective fix is to revert to NAT mode.
  1. Open %USERPROFILE%\.wslconfig.
  2. Comment out the line: # networkingMode=mirrored.
  3. Restart WSL via `wsl --shutdown`.
By reverting to NAT, you allow Docker Desktop to take full control of the port-proxying logic, which is the standard behaviour for the application.