Docker Error Guide: 'Temporary failure in name resolution' Container DNS Failures
Fix Docker 'Temporary failure in name resolution' and 127.0.0.11 DNS errors: repair host resolv.conf, set daemon DNS, use user-defined networks, and handle IPv6.
- #docker
- #troubleshooting
- #errors
- #dns
Exact Error Message
Inside a container, any hostname lookup fails. An apt update, curl, or application connection prints:
curl: (6) Could not resolve host: registry-1.docker.io
ping: bad address 'github.com'
Temporary failure in name resolution
When the failure is observed by Docker or a Go program using the embedded resolver, the host and resolver IP are spelled out:
dial tcp: lookup api.internal.example.com on 127.0.0.11:53: server misbehaving
127.0.0.11 is the giveaway that the request reached Docker’s embedded DNS resolver but the resolver could not get an answer from upstream.
What It Means
Containers do not query your host’s DNS servers directly. On a user-defined network, Docker injects an embedded resolver listening on 127.0.0.11:53 inside the container’s network namespace. That resolver handles container-name service discovery and forwards everything else to upstream servers — taken from the daemon’s --dns config or, by default, copied from the host’s /etc/resolv.conf.
“Temporary failure in name resolution” (EAI_AGAIN) means the resolver could not reach a working upstream. The chain is: container → 127.0.0.11 → upstream nameserver. A break anywhere — a bad host resolv.conf, an unreachable corporate/VPN DNS, a 127.0.0.53 systemd-resolved stub that isn’t reachable from the container namespace, or broken IPv6 — surfaces as this error.
The EAI_AGAIN class is specifically “try again later,” which is why the word “temporary” appears even when the failure is in fact permanent until you fix configuration. It is distinct from Could not resolve host / NXDOMAIN, which means an upstream was reached and authoritatively said the name does not exist. If you see NXDOMAIN, the resolver path is healthy and the problem is the name or search domain; if you see Temporary failure or server misbehaving, the resolver never got a usable answer and the path itself is broken. Keeping that split in mind saves time: one points at your DNS records, the other at your network and daemon DNS config.
Common Causes
- Embedded resolver can’t reach upstream — the forwarded nameservers are unreachable from the container’s namespace.
- Host
/etc/resolv.confpoints at127.0.0.53— the systemd-resolved stub is loopback on the host and meaningless inside the container, so Docker may copy an unusable server. - No daemon DNS configured — Docker fell back to a default (e.g.
8.8.8.8) that a locked-down network blocks. - Corporate DNS / VPN — internal names only resolve via a VPN resolver the daemon doesn’t know about.
- Default bridge vs user-defined network — the legacy
bridgenetwork has no automatic container-name DNS; only user-defined networks do. - Broken IPv6 — the resolver tries AAAA over a blackholed IPv6 path and times out.
How to Reproduce the Error
Run a container with a deliberately broken upstream DNS server and try to resolve a public name:
docker run --rm --dns 203.0.113.254 alpine sh -c 'nslookup github.com'
The lookup forwards to an unreachable server and returns server misbehaving / Temporary failure in name resolution. You can also reproduce host-config bleed-through by pointing the host at a stub the container can’t use:
docker run --rm alpine cat /etc/resolv.conf # if it shows nameserver 127.0.0.53, lookups will fail
Diagnostic Commands
Start inside the container — see what resolver and upstreams it was given, then test resolution:
docker exec -it <container> cat /etc/resolv.conf
docker exec -it <container> nslookup github.com
docker exec -it <container> nslookup github.com 1.1.1.1 # bypass embedded resolver
A failure on the first nslookup but success against 1.1.1.1 directly points at the forwarded upstream. Inspect the network to see if it is the default bridge or user-defined:
docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{end}}' <container>
docker network inspect <network> | grep -i 'name\|driver\|subnet'
Confirm the host itself can resolve and check the daemon’s DNS config:
dig +short github.com
cat /etc/resolv.conf
grep -i dns /etc/docker/daemon.json 2>/dev/null
Step-by-Step Resolution
-
Set explicit DNS for the daemon so every container inherits working upstreams regardless of the host stub. Edit
/etc/docker/daemon.json:{ "dns": ["1.1.1.1", "8.8.8.8"] }sudo systemctl restart docker -
Override per container when only one workload needs different resolvers:
docker run --dns 1.1.1.1 --dns-search example.com myimage -
Fix the host
resolv.confstub. If the host uses systemd-resolved, point Docker at the real upstreams rather than127.0.0.53, or use the resolved-managed file:ls -l /etc/resolv.conf # if it links to stub-resolv.conf, set daemon.json dns instead -
Use a user-defined network so container-name resolution works and you get the embedded resolver:
docker network create appnet docker run --network appnet --name api myimage -
Add corporate/VPN resolvers to
daemon.jsondns(anddns-searchfor internal domains) when internal names fail but public ones work. -
Disable broken IPv6 lookups if AAAA queries hang. Restrict the daemon or container to IPv4 upstreams and avoid publishing on a blackholed IPv6 path.
After any daemon.json change, sudo systemctl restart docker, recreate the container, and re-test with docker exec ... nslookup. Note that existing containers keep the /etc/resolv.conf they were created with — a daemon DNS change only affects containers started afterward, so you must recreate (not just restart) running containers for new upstreams to take effect.
A subtle but frequent trap is the default bridge versus a user-defined network. On the legacy default bridge, containers do not get the 127.0.0.11 embedded resolver for container-name lookups, and they inherit DNS more directly from the host. If your symptom is that public names resolve but container names like db or api do not, the fix is not DNS servers at all — it is moving the containers onto a shared user-defined network (step 4), which is also why Docker Compose, which creates one automatically, rarely hits the name-discovery half of this problem.
How to Prevent the Issue
- Configure
dns(anddns-searchfor internal zones) in/etc/docker/daemon.jsonon every host so containers never depend on a loopback stub. - Prefer user-defined networks over the default
bridge; they provide automatic name resolution and a predictable embedded resolver. - Document VPN/corporate resolver requirements in your host provisioning so air-gapped or split-horizon DNS works from containers.
- Avoid copying
127.0.0.53/127.0.0.1into container DNS; those loopback stubs are not reachable from the container namespace. - Monitor for
127.0.0.11:53errors in application logs as an early signal of upstream DNS or VPN breakage.
Related Docker Errors
- Docker Error Guide: ‘net/http: TLS handshake timeout’ — once names resolve, the next registry-path failure is often a TLS/MTU/proxy timeout.
- Browse more Docker troubleshooting guides for networking, registry, and startup errors.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.