LinuxLinux

Temporary failure in name resolution

DNS resolution failed. How to separate a resolver problem from a network problem in two commands, and the systemd-resolved and container cases.

medium fix5 min read

the linux error
ping: example.com: Temporary failure in name resolution

curl: (6) Could not resolve host: example.com

socket.gaierror: [Errno -3] Temporary failure in name resolution

Could not resolve host: github.com

Do this first3 steps

Run these in order. Each one tells you what its output means before you change anything.

  1. 1

    Separate DNS from general connectivity

    ping -c1 1.1.1.1 && getent hosts example.com || echo "IP works, DNS does not"

    Reaching an IP while name lookup fails narrows it to DNS. If the IP is unreachable too, this is a routing or firewall problem and DNS is a symptom rather than the cause.

  2. 2

    Look at what the resolver is configured to use

    cat /etc/resolv.conf && resolvectl status 2>/dev/null | head -20

    An empty resolv.conf, or one with no nameserver line, means nothing is configured. On systemd hosts resolv.conf often points at 127.0.0.53, in which case resolvectl shows the real upstream servers.

  3. 3

    Test a specific server directly, bypassing the local resolver

    dig +short @1.1.1.1 example.com

    An answer here proves DNS works over the network and the local configuration is at fault. No answer means outbound port 53 is blocked, or the network genuinely has no path out.

All 7 sections

Name resolution failed. The first job is to decide whether DNS is broken or the network is, because they look identical from the application's point of view.

ping -c1 1.1.1.1        # raw IP, no DNS involved
getent hosts example.com
ResultMeaning
IP works, name failsDNS. Continue below
Both failRouting or firewall. DNS is a symptom
Both workIntermittent, or the application has its own resolver

getent hosts is better than ping for testing names, because it uses the same NSS path as the rest of the system, including /etc/hosts and any module configured in nsswitch.conf.

What is the resolver configured to use?

cat /etc/resolv.conf
nameserver 127.0.0.53
options edns0 trust-ad
search .

127.0.0.53 is systemd-resolved's stub listener, so this file is not the real configuration:

resolvectl status
Link 2 (eth0)
    Current Scopes: DNS
         Protocols: +DefaultRoute
Current DNS Server: 10.0.0.2
       DNS Servers: 10.0.0.2

An empty DNS Servers list means the link never received servers, usually because DHCP failed or a static configuration is incomplete.

If /etc/resolv.conf has no nameserver line at all, nothing is configured and every lookup fails immediately.

Test upstream directly

dig +short @1.1.1.1 example.com
dig +short @10.0.0.2 example.com     # your configured server

An answer from 1.1.1.1 but not from the configured server means that server is unreachable or broken. No answer from either means outbound UDP 53 is blocked, which is common on hardened networks and in some cloud security groups.

sudo ss -ulpn | grep :53
sudo nft list ruleset 2>/dev/null | grep -i 53

systemd-resolved

sudo systemctl status systemd-resolved
sudo systemctl restart systemd-resolved
sudo resolvectl flush-caches

A broken symlink is a frequent cause:

ls -l /etc/resolv.conf

It should point at /run/systemd/resolve/stub-resolv.conf. Something that overwrote it with a plain file, often a VPN client or a container tool, breaks the integration. Restore it:

sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf

Set servers explicitly where DHCP does not supply them:

sudo resolvectl dns eth0 1.1.1.1 1.0.0.1

For persistence, use netplan or /etc/systemd/resolved.conf. Editing /etc/resolv.conf by hand does not survive, because it is regenerated.

Containers

Docker copies the host's DNS configuration, with one important exception: it strips loopback addresses, because 127.0.0.53 inside a container refers to the container, not the host. If the host uses systemd-resolved and Docker cannot find a real upstream, it falls back to 8.8.8.8, which fails on networks that block external DNS.

docker run --rm alpine cat /etc/resolv.conf
docker run --rm alpine nslookup example.com

Set it explicitly:

// /etc/docker/daemon.json
{ "dns": ["10.0.0.2", "1.1.1.1"] }
sudo systemctl restart docker

Or per container:

docker run --dns 10.0.0.2 myapp

In Kubernetes the equivalent is CoreDNS:

kubectl -n kube-system get pods -l k8s-app=kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50
kubectl run -it --rm dnstest --image=busybox:1.36 --restart=Never -- nslookup kubernetes.default

A Pod's /etc/resolv.conf points at the cluster DNS Service, so a failure there affects everything at once.

The search domain trap

search internal.acme.com acme.com
options ndots:5

With ndots:5, any name containing fewer than five dots is first tried with each search domain appended. example.com becomes example.com.internal.acme.com, then example.com.acme.com, then finally example.com. Each failed attempt costs a round trip.

This is the default inside Kubernetes Pods and is a well-known source of slow external lookups. Fix it per Pod:

spec:
  dnsConfig:
    options:
      - name: ndots
        value: "2"

Or use a fully qualified name with a trailing dot, example.com., which skips the search list entirely.

A checklist

  1. ping 1.1.1.1 versus getent hosts example.com. Separate DNS from the network.
  2. cat /etc/resolv.conf. No nameserver line means nothing is configured.
  3. 127.0.0.53resolvectl status for the real servers.
  4. dig @1.1.1.1 example.com to test upstream directly.
  5. No answer from anything → outbound port 53 is blocked.
  6. ls -l /etc/resolv.conf should be a symlink on systemd hosts.
  7. Containers → check /etc/resolv.conf inside; set dns in daemon.json.
  8. Slow external lookups in Kubernetes → ndots, or a trailing dot on the name.

Frequently Asked Questions

How do I tell whether DNS or the network is broken?

Ping a raw IP such as 1.1.1.1, which involves no name resolution, and then resolve a name with getent hosts example.com. If the IP responds and the name does not, the problem is DNS. If neither works, it is routing or a firewall and DNS is simply the first thing to notice. Use getent rather than ping for the name test, because it follows the same NSS path as the rest of the system, including /etc/hosts.

Why does /etc/resolv.conf show 127.0.0.53?

That is the systemd-resolved stub listener, a local resolver that forwards to the real upstream servers. So the file tells you very little; resolvectl status shows the actual DNS servers per link. Editing /etc/resolv.conf by hand on such a system does not persist, because it is a symlink to a generated file. Configure servers with resolvectl dns <link> <ip>, or persistently through netplan or /etc/systemd/resolved.conf.

Why does DNS work on the host but not inside my container?

Docker copies the host's resolver configuration but strips loopback addresses, since 127.0.0.53 inside a container refers to the container itself rather than the host's resolver. On a systemd-resolved host that can leave Docker with nothing usable, so it falls back to 8.8.8.8, which fails on any network that blocks external DNS. Set real upstream servers in /etc/docker/daemon.json under dns, or pass --dns on individual containers.

What is ndots and why does it make lookups slow?

ndots sets how many dots a name must contain before the resolver tries it as-is rather than appending each search domain first. Kubernetes defaults Pods to ndots:5, so example.com, having one dot, is first tried as example.com.<namespace>.svc.cluster.local and several other variants before the real query happens. Each attempt is a round trip. Lower it with a dnsConfig option on the Pod, or use a fully qualified name with a trailing dot to bypass the search list.

What should I check first in a Kubernetes cluster?

CoreDNS. kubectl -n kube-system get pods -l k8s-app=kube-dns shows whether it is running, and its logs usually explain a cluster-wide failure. Test from a throwaway Pod with kubectl run -it --rm dnstest --image=busybox:1.36 --restart=Never -- nslookup kubernetes.default, which resolves an in-cluster name and so tests the whole path. Because every Pod's resolver points at the same Service, a CoreDNS problem breaks name resolution everywhere at once, which makes it look like a network outage.

Reference and practice

Learn the underlying concept

Other Linux errors