On Ubuntu (and many other distributions), name resolution goes through systemd-resolved: a local DNS resolver and cache. That’s why /etc/resolv.conf contains nameserver 127.0.0.53 instead of your provider’s DNS servers. Knowing how it works saves time when DNS breaks, or when you want to run your own DNS server on port 53.

How it fits together

app → /etc/resolv.conf (nameserver 127.0.0.53) → systemd-resolved (stub on 127.0.0.53:53)
                                                   → upstream DNS servers (from netplan/DHCP/config)
  • 127.0.0.53 is a local “stub” listener. It caches answers, and forwards queries upstream.
  • The real upstream servers come from the network configuration (netplan, DHCP, NetworkManager), or from /etc/systemd/resolved.conf.
ls -l /etc/resolv.conf
# → ../run/systemd/resolve/stub-resolv.conf

See what’s actually used

resolvectl status          # global and per-interface DNS servers, DNSSEC, DoT
resolvectl dns             # just the servers
resolvectl query example.com
resolvectl statistics      # cache hits/misses

dig and nslookup query 127.0.0.53 by default. Query an upstream server directly to compare: dig @1.1.1.1 example.com.

Set DNS servers

Per interface (recommended), via netplan:

# /etc/netplan/50-cloud-init.yaml (excerpt)
network:
  ethernets:
    eth0:
      nameservers:
        addresses: [1.1.1.1, 9.9.9.9]
sudo netplan try      # then: sudo netplan apply

See static IP with netplan and change DNS server on Linux.

Globally, via resolved.conf:

# /etc/systemd/resolved.conf (or a drop-in in /etc/systemd/resolved.conf.d/)
[Resolve]
DNS=1.1.1.1 9.9.9.9
FallbackDNS=8.8.8.8
DNSOverTLS=opportunistic
sudo systemctl restart systemd-resolved

Temporarily (until reboot): sudo resolvectl dns eth0 1.1.1.1 9.9.9.9.

DNS over TLS

DNSOverTLS=yes encrypts queries to the upstream resolver (port 853). The upstream must support DoT. Cloudflare, Quad9 and Google do. opportunistic tries TLS, and falls back to plain DNS. See DNS over HTTPS.

Flush the cache

sudo resolvectl flush-caches
resolvectl statistics

Useful after DNS changes. See DNS propagation.

Port 53 conflicts

Running your own DNS server (Pi-hole, AdGuard Home, BIND, dnsmasq, or Unbound) fails with “address already in use”, because resolved’s stub listens on 127.0.0.53:53. Disable the stub:

# /etc/systemd/resolved.conf.d/no-stub.conf
[Resolve]
DNSStubListener=no
sudo systemctl restart systemd-resolved
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf    # point to the real upstreams

See Pi-hole on a VPS and AdGuard Home.

Troubleshooting

Symptom Check
“Temporary failure in name resolution” resolvectl status: any DNS servers? Is systemd-resolved running?
Works with dig @1.1.1.1 but not normally Upstream config, or a broken stub. Restart resolved, check /etc/resolv.conf symlink
Docker containers can’t resolve Containers can’t use 127.0.0.53; Docker reads the upstream file. Set "dns" in /etc/docker/daemon.json if needed
Old answers after a DNS change resolvectl flush-caches
/etc/resolv.conf keeps changing It’s managed. Change DNS via netplan or resolved.conf instead

Logs: journalctl -u systemd-resolved. See journalctl.

Should you disable it?

For most servers, no. resolved’s cache speeds up repeated lookups (APIs, package mirrors, database hosts), and the per-interface configuration works well with netplan and VPNs. Disable or bypass it only when you run your own resolver on the server, or an application insists on reading real upstream servers from /etc/resolv.conf. If you do disable the service entirely, write a static /etc/resolv.conf with your chosen servers, and make sure nothing else (cloud-init, DHCP hooks) overwrites it.

Quick reference

Task Command
Status resolvectl status
Test a lookup resolvectl query example.com
Flush cache resolvectl flush-caches
Set DNS (permanent) netplan nameservers, or resolved.conf DNS=
Free port 53 DNSStubListener=no

Related: Linux DNS server configuration and ping, traceroute and mtr.

  • Linux
  • DNS
  • systemd