'Temporary Failure in Name Resolution': Fixing Ubuntu DNS Without Fighting systemd-resolved
Everything was fine until it was not. You installed a VPN client, or ran netplan apply, or edited /etc/resolv.conf to "just add a nameserver", and now nothing resolves. apt update fails. ping google.com fails. But ping 8.8.8.8 works perfectly, which is the tell: your network is up, your DNS is down.
The advice you will find first is to hand-edit /etc/resolv.conf and paste in nameserver 8.8.8.8. It appears to work. Then you reboot, or the next netplan apply runs, and it silently reverts, and you spend an hour blaming the VPN, the router, your ISP, anything except the real cause. On modern Ubuntu that file is not a file you own. It is a symlink managed by systemd-resolved, and editing it is like writing your grocery list on a whiteboard someone wipes every morning.
On Ubuntu 18.04 and later, /etc/resolv.conf is a symlink to a file systemd-resolved regenerates. Do not hand-edit it. Set DNS the supported way in your netplan YAML under nameservers:, then sudo netplan apply. If the symlink itself was broken by a VPN or the resolvconf package, restore it: sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf. Then flush the cache with sudo resolvectl flush-caches.
The error, verbatim
ping: google.com: Temporary failure in name resolution
You will see the same underlying failure in different clothes depending on the tool:
curl: (6) Could not resolve host: github.com
E: Temporary failure resolving 'archive.ubuntu.com'
getaddrinfo() failed: Temporary failure in name resolution
All of these mean one thing: the C library asked the system to turn a hostname into an IP address, and the system had no working resolver to ask. It is never a problem with the remote host. It is your machine not knowing who to ask for DNS.
Why this happens: the symlink you keep fighting
On modern Ubuntu, DNS resolution is handled by systemd-resolved, a system service that runs a tiny stub resolver listening on 127.0.0.53. Your applications read /etc/resolv.conf to find a nameserver, and on a healthy system that file is a symlink pointing at a file the service owns:
$ ls -l /etc/resolv.conf
lrwxrwxrwx 1 root root 39 ... /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf
Inside, it contains a single nameserver line pointing at the stub:
nameserver 127.0.0.53
options edns0 trust-ad
systemd-resolved is the thing that actually forwards your query to a real upstream DNS server (8.8.8.8, your router, whatever). The real upstream servers are configured elsewhere: in netplan, or handed out by DHCP, or set per-interface. The stub is just the local front door.
Now the two ways this breaks:
- You hand-edited the target file.
systemd-resolvedregenerates/run/systemd/resolve/stub-resolv.confon every relevant network change and on boot. Your edit lasts until the next regeneration, then vanishes. The "fix that stopped working" is this. - The symlink got clobbered. A VPN client, or installing the old
resolvconfpackage, or a manualrmplus a plain-file rewrite, replaces the symlink with a static file (or a different symlink) that points at nothing useful. Now nothing forwards your queries and every lookup dies.
Diagnose before you touch anything
Three commands tell you exactly which link in the chain is broken.
Step 1: Check the symlink
ls -l /etc/resolv.conf
Healthy output is a symlink arrow to stub-resolv.conf (or on some setups resolv.conf) under /run/systemd/resolve/. If it is a plain file (-rw-r--r-- with no arrow), or points somewhere else, that is your problem. Understanding what a symlink actually is helps here; I cover the fundamentals in files, folders and ownership in Linux.
Step 2: Check the resolver's own view
resolvectl status
Look at the Current DNS Server and DNS Servers lines per link. If they are empty, systemd-resolved has no upstream to forward to, so even a perfect symlink resolves nothing. If they list a server, the resolver is configured and the problem is downstream (the symlink) or a stale cache.
Step 3: Check the service is actually running
systemctl status systemd-resolved
It should be active (running). If it is dead or masked (sometimes a VPN installer masks it), the stub on 127.0.0.53 is not listening and nothing resolves.
The fix
If the symlink is broken: restore it
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
The -f forces the symlink to replace whatever is there now. Re-run ls -l /etc/resolv.conf and confirm the arrow is back.
If the resolver has no upstream: set DNS in netplan, the supported way
This is the correct permanent home for your nameservers, and it survives reboots and applies. Edit the relevant file in /etc/netplan/ (the name varies; it is often something like 50-cloud-init.yaml or 01-netcfg.yaml). Add nameservers under the interface:
network:
version: 2
ethernets:
eth0:
dhcp4: true
nameservers:
addresses: [1.1.1.1, 8.8.8.8]
Netplan YAML is whitespace-sensitive; use spaces, never tabs. Then apply:
sudo netplan apply
This pushes the nameservers into systemd-resolved, which regenerates the stub file and starts forwarding to them. Because it is the supported path, the next netplan apply or reboot keeps it.
If a conflicting resolvconf package is installed: remove it
The legacy resolvconf package fights systemd-resolved for ownership of /etc/resolv.conf. On a systemd-resolved system it is redundant and a frequent cause of the symlink being hijacked. Check and remove:
dpkg -l resolvconf
sudo apt purge resolvconf # only if it is installed and you use systemd-resolved
Flush the cache
After any of the above, clear stale entries so you are testing the new config, not a cached failure:
sudo resolvectl flush-caches
Verification
Prove each layer works, bottom to top:
# 1. Raw connectivity (should already work): numeric IP, no DNS
ping -c1 1.1.1.1
# 2. The resolver stub itself can resolve
resolvectl query github.com
# 3. Normal name resolution through libc
getent hosts github.com
# 4. A real request end to end
curl -sSI https://github.com | head -1
resolvectl query github.com returning an address with a line like -- Data was acquired via local or encrypted transport tells you the resolver chain is healthy. getent hosts proves the C library path (the one your apps use) works, not just the systemd tool. If all four pass, you are done.
What people get wrong
"Just put your nameservers in /etc/resolv.conf." This is the single most repeated and most wrong piece of advice for modern Ubuntu. It works for exactly one boot on a managed symlink and then reverts, and it teaches you to distrust everything except the actual cause. If you truly must bypass systemd-resolved, you have to disable the service and take ownership of the file deliberately, not paste a line into a symlink and hope.
"Reinstall resolvconf to fix DNS." On a systemd-resolved system this makes it worse by adding a second manager for the same file. One machine, one DNS manager.
"Reboot and see." A reboot on a broken symlink either changes nothing or, worse, regenerates state that masks the real cause temporarily. Diagnose the chain with the three commands above instead of power-cycling and praying.
When it is still broken
- VPN split-DNS. Some VPN clients push their own DNS onto a specific link and route only internal names to it. Run
resolvectl statusand check the per-link DNS. You may need to add a global fallback or fix the VPN's~DNS domainsrouting. - Firewall blocking port 53. If the resolver is configured but queries time out, a firewall (ufw, a cloud security group, or an egress policy) may be blocking outbound UDP/TCP 53 to your upstream. Test with
dig @8.8.8.8 github.com; if that also fails, it is the network path, not resolv.conf. - Containers are different. Inside Docker or Kubernetes, DNS does not go through host
systemd-resolvedthe same way. If your symptom is in a pod, the cause is usually ndots and conntrack, which I cover in Kubernetes DNS timeouts. - Service keeps dying. If
systemd-resolvedwill not stay running, treat it as any crashing service and read its journal, the way I lay out in keeping a service actually running under systemd.
The lesson that outlives this one bug: on modern Linux, DNS is a managed chain, not a text file. Learn the three-command diagnosis, set nameservers where the manager expects them, and you stop fighting a whiteboard that gets wiped every morning.
Frequently asked questions
- Why does editing /etc/resolv.conf stop working after a reboot on Ubuntu?
- On Ubuntu 18.04 and later, /etc/resolv.conf is a symlink to a file that systemd-resolved regenerates on boot and on every network change. Any nameserver you hand-write into it is overwritten the next time the resolver regenerates the file. Set your DNS servers in the netplan YAML under nameservers and run netplan apply, which is the supported path that survives reboots.
- How do I permanently set DNS servers on Ubuntu with systemd-resolved?
- Edit the relevant file in /etc/netplan/, add a nameservers block with addresses under the interface, for example addresses: [1.1.1.1, 8.8.8.8], then run sudo netplan apply. This feeds the servers to systemd-resolved, which regenerates the resolv.conf stub and forwards queries to them. Confirm with resolvectl status.
- A VPN broke my DNS and /etc/resolv.conf is now a plain file. How do I fix it?
- The VPN or the resolvconf package replaced the managed symlink with a static file. Restore it with sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf, then restart the service with sudo systemctl restart systemd-resolved. If the resolvconf package is installed alongside systemd-resolved, purge it, since two DNS managers fighting over one file is a common cause.
- Ping to 8.8.8.8 works but ping to a hostname fails. What does that mean?
- It means your network connectivity is fine but DNS resolution is broken. The numeric IP needs no name lookup, so it succeeds, while the hostname needs a working resolver, which you do not have. Check the resolution chain with ls -l /etc/resolv.conf, resolvectl status, and systemctl status systemd-resolved.