Running Docker on top of Windows Subsystem for Linux 2 (WSL2) provides near bare-metal Linux performance for Windows workstations. However, because WSL2 relies on a virtualized Hyper-V network interface, DNS routing between the Windows host, the WSL2 utility VM, and nested Docker containers frequently breaks without warning.
You boot up a development stack or run a build step, and you are hit with:
Err:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Temporary failure resolving 'archive.ubuntu.com'
W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/jammy/InRelease Temporary failure resolving 'archive.ubuntu.com'
E: Some index files failed to download.
Or inside an Alpine container:
$ docker run --rm alpine ping -c 2 google.com
ping: bad address 'google.com'
Below is the complete architectural breakdown of why this happens, how corporate VPNs black-hole Hyper-V packets, and 3 production-tested fixes.
The Network Architecture Breakdown
Here is what your packet traversal looks like across Windows 11, WSL2, and Docker:
flowchart TD
subgraph Host["Windows 11 Host"]
NIC["Physical Wi-Fi / Ethernet"]
VPN["Corporate VPN Adapter<br/>(Cisco AnyConnect / GlobalProtect / Zscaler)"]
WFP["Windows Filtering Platform (WFP)<br/>(Blocks Non-VPN Outbound UDP 53)"]
end
subgraph HyperV["Hyper-V NAT Switch Layer"]
vSwitch["Hyper-V Virtual Switch<br/>Gateway Proxy: 172.x.x.1:53"]
end
subgraph WSL2["WSL2 Linux VM (Ubuntu)"]
Resolv["/etc/resolv.conf<br/>nameserver 172.x.x.1"]
Systemd["systemd-resolved Stub<br/>127.0.0.53:53"]
end
subgraph Docker["Docker Engine Namespace"]
Daemon["dockerd (Strips 127.0.0.0/8)"]
Fallback["Blocked Fallback:<br/>Public Google DNS 8.8.8.8"]
EmbeddedDNS["User-Defined Bridge<br/>127.0.0.11:53"]
end
NIC --> vSwitch
VPN -.->|Locks down network| WFP
WFP -.->|Drops packets from| vSwitch
vSwitch --> Resolv
Resolv --> Systemd
Systemd --> Daemon
Daemon --> Fallback
Daemon --> EmbeddedDNS
Fallback -.->|Fails: Temporary failure in name resolution| Docker
Why It Fails Under the Hood
-
Hyper-V NAT & VPN Black Holes: In standard WSL2 NAT mode, Windows sets
/etc/resolv.confto the virtual switch IP (172.x.x.1). When corporate VPNs (Cisco AnyConnect, GlobalProtect, Zscaler) connect, strict Windows Filtering Platform (WFP) rules drop untracked Hyper-V interface packets. -
Docker Loopback Stripping: Modern Ubuntu WSL2 distros bind DNS to
127.0.0.53(systemd-resolved). Inside a container namespace,127.0.0.1routes to the container itself. Docker detects this and strips all loopback addresses, falling back to hardcoded Google DNS (8.8.8.8). If your corporate network or firewall blocks raw outbound UDP 53, container DNS immediately hangs. -
Alpine
musl libcA/AAAA Race: Alpine containers issue parallelA(IPv4) andAAAA(IPv6) queries over concurrent UDP sockets. If the Hyper-V NAT bridge drops or delays IPv6 responses,muslaborts withbad address.
Solution 1: Explicit Upstream DNS in Docker Daemon (Fastest)
If you use standard WSL2 NAT mode and don't need complex VPN tunneling, instruct Docker Engine to query known reachable DNS resolvers directly:
Create or edit /etc/docker/daemon.json inside your WSL2 terminal:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json << 'EOF'
{
"dns": ["1.1.1.1", "8.8.8.8"]
}
EOF
Enterprise tip: If your workplace blocks public DNS, replace
"1.1.1.1", "8.8.8.8"with your company's internal DNS servers. You can find them in Windows PowerShell via:Get-DnsClientServerAddress -AddressFamily IPv4
Restart Docker daemon:
sudo systemctl restart docker
# or if using SysV init:
sudo service docker restart
Verify container resolution:
docker run --rm alpine nslookup google.com
Solution 2: Prevent WSL2 from Auto-Generating /etc/resolv.conf
To permanently prevent WSL2's /init process from overwriting /etc/resolv.conf on reboot:
- Update
/etc/wsl.confinside WSL2:
sudo tee /etc/wsl.conf << 'EOF'
[network]
generateResolvConf = false
EOF
- Replace the dynamic symlink with an immutable static file:
# Delete existing dynamic symlink
sudo rm -f /etc/resolv.conf
# Write static nameservers
sudo tee /etc/resolv.conf << 'EOF'
nameserver 1.1.1.1
nameserver 8.8.8.8
options edns0 ndots:1
EOF
# Lock file to prevent systemd-resolved overwrite
sudo chattr +i /etc/resolv.conf
- Restart WSL2 from Windows PowerShell:
wsl.exe --shutdown
Solution 3: Windows 11 Mirrored Mode & DNS Tunneling (The Ultimate VPN Fix)
If you are on Windows 11 (build 22H2 / 23H2+ with WSL 2.0.0+), Microsoft introduced Mirrored Networking and DNS Tunneling.
Instead of routing raw UDP packets across a virtual Hyper-V NAT switch, WSL2 mirrors Windows network adapters directly and intercepts DNS queries via virtualization socket APIs, executing them through the Windows host network stack.
Implementation:
- Open or create
%USERPROFILE%\.wslconfigin Windows:
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
- Restart WSL2 from an elevated PowerShell terminal:
wsl.exe --shutdown
- Check Hyper-V Firewall Settings: Mirrored mode delegates network traffic to the Hyper-V firewall. Ensure outbound traffic is permitted:
Get-NetFirewallHyperVVMSetting -PolicyStore ActiveStore
If DefaultOutboundAction is Block, allow it:
Set-NetFirewallHyperVRule -DisplayName "Allow WSL2 Mirrored Outbound" -Direction Outbound -Action Allow
Start WSL2 and test container connectivity:
docker run --rm alpine ping -c 2 google.com
docker run --rm ubuntu:22.04 apt-get update
Fix for Alpine Linux Containers (musl libc)
If Ubuntu containers resolve DNS fine but Alpine-based images (alpine, node:alpine, python:alpine) still fail with ping: bad address, pass query serialization flags:
In docker run:
docker run --rm \
--dns-opt="single-request-reopen" \
--dns-opt="ndots:1" \
alpine ping -c 2 google.com
Or inject it into your Alpine Dockerfile:
FROM alpine:3.19
RUN echo "options single-request-reopen ndots:1" >> /etc/resolv.conf
RUN apk add --no-cache curl ca-certificates
Summary Checklist
| Strategy | Best For | VPN Friendly | Maintenance |
|---|---|---|---|
/etc/docker/daemon.json |
Local development | Moderate | Very Low |
Static /etc/resolv.conf |
General WSL2 fix | Poor | Moderate |
| Mirrored + DNS Tunneling | Windows 11 + AnyConnect / GlobalProtect | Best in Class | Zero |
Alpine dns_opt |
CI/CD & Alpine images | N/A | Low |
For deep-dive diagnostic flowcharts and container performance notes, check out our full technical guide on GearFlow Lab.
Top comments (0)