DEV Community

Sanghun Yun
Sanghun Yun

Posted on Originally published at gearflowlab.com

How to Fix Docker DNS Resolution Failure in WSL2 ("Temporary Failure in Name Resolution")

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.
Enter fullscreen mode Exit fullscreen mode

Or inside an Alpine container:

$ docker run --rm alpine ping -c 2 google.com
ping: bad address 'google.com'
Enter fullscreen mode Exit fullscreen mode

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

  1. Hyper-V NAT & VPN Black Holes: In standard WSL2 NAT mode, Windows sets /etc/resolv.conf to 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.
  2. Docker Loopback Stripping: Modern Ubuntu WSL2 distros bind DNS to 127.0.0.53 (systemd-resolved). Inside a container namespace, 127.0.0.1 routes 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.
  3. Alpine musl libc A/AAAA Race: Alpine containers issue parallel A (IPv4) and AAAA (IPv6) queries over concurrent UDP sockets. If the Hyper-V NAT bridge drops or delays IPv6 responses, musl aborts with bad 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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Verify container resolution:

docker run --rm alpine nslookup google.com
Enter fullscreen mode Exit fullscreen mode

Solution 2: Prevent WSL2 from Auto-Generating /etc/resolv.conf

To permanently prevent WSL2's /init process from overwriting /etc/resolv.conf on reboot:

  1. Update /etc/wsl.conf inside WSL2:
sudo tee /etc/wsl.conf << 'EOF'
[network]
generateResolvConf = false
EOF
Enter fullscreen mode Exit fullscreen mode
  1. 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
Enter fullscreen mode Exit fullscreen mode
  1. Restart WSL2 from Windows PowerShell:
wsl.exe --shutdown
Enter fullscreen mode Exit fullscreen mode

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:

  1. Open or create %USERPROFILE%\.wslconfig in Windows:
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
Enter fullscreen mode Exit fullscreen mode
  1. Restart WSL2 from an elevated PowerShell terminal:
wsl.exe --shutdown
Enter fullscreen mode Exit fullscreen mode
  1. Check Hyper-V Firewall Settings: Mirrored mode delegates network traffic to the Hyper-V firewall. Ensure outbound traffic is permitted:
Get-NetFirewallHyperVVMSetting -PolicyStore ActiveStore
Enter fullscreen mode Exit fullscreen mode

If DefaultOutboundAction is Block, allow it:

Set-NetFirewallHyperVRule -DisplayName "Allow WSL2 Mirrored Outbound" -Direction Outbound -Action Allow
Enter fullscreen mode Exit fullscreen mode

Start WSL2 and test container connectivity:

docker run --rm alpine ping -c 2 google.com
docker run --rm ubuntu:22.04 apt-get update
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)