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.
