When systemd‑resolved silently drops a local /etc/hosts entry and the service you can’t reach

systemd‑resolved is the default DNS resolver on most modern distros. It pulls /etc/hosts unless you flip the --no-hosts flag. In 2026 a subtle tweak in its default behaviour started swallowing local hostname lookups, and no one noticed until a service went down.

Why it happens

systemd-resolved now gives the DNS stack a higher priority than the hosts file when you call getaddrinfo(3). If a name shows up in both /etc/hosts and a DNS zone, the DNS answer wins. When the zone is empty or the query times out, it silently falls back to the hosts file. But if the DNS server is unreachable and the hosts entry points to 127.0.0.1 or ::1, the resolver drops that entry and returns ENOTFOUND. The change was meant to stop a compromised DNS server from poisoning local lookups.

Symptoms

  • A service that relies on a local hostname (e.g., db.example.local) refuses to start.
  • systemctl status shows “Failed to resolve db.example.local”.
  • dig db.example.local says NXDOMAIN, even though /etc/hosts has the mapping.
  • No obvious logs in /var/log/syslog or journalctl -u systemd-resolved.

Quick check

# Verify the entry exists
grep db.example.local /etc/hosts

# Test resolution with systemd-resolved
systemd-resolve --status db.example.local

If the second command reports “Address: (none)”, the resolver is discarding the entry.

Work‑arounds

ApproachWhen to useCommand
Disable DNS for the hostnameThe hostname is only used locally.systemd-resolve --no-poll db.example.local
Add a static DNS recordYou control the zone and want consistency.`echo “db.example.local. IN A 127.0.0.1”
Force hosts file usageYou must keep the entry in /etc/hosts.systemd-resolve --no-hosts db.example.local (per‑query) or set DNSStubListener=no in /etc/systemd/resolved.conf and restart.
Tweak /etc/nsswitch.confWant files to win over dns globally.Edit hosts: files dns to hosts: files mdns4_minimal [NOTFOUND=return] dns

The most common single‑service fix is to add a local DNS record in /etc/systemd/resolved.conf.d/local.conf:

[Resolve]
DNS=127.0.0.1
Domains=~.

This forces the resolver to treat the local domain as a search domain and keeps the hosts file in the resolution path.

Security implications

  • DNS spoofing mitigation – By dropping ambiguous hosts entries, systemd‑resolved reduces the risk of an attacker poisoning the /etc/hosts file via DNS.
  • Potential service outages – Legitimate local services can be unintentionally disabled if the hosts file isn’t mirrored in DNS.
  • Audit trail – journalctl -u systemd-resolved now logs “Dropped hosts entry for db.example.local” when the drop occurs. Check those logs regularly.

Checklist for operators

  1. Audit local hostnames – Run grep -E '^[0-9.]+[[:space:]]+[a-zA-Z0-9.-]+' /etc/hosts and compare against your DNS zones.
  2. Enable DNSStubListener only if you need local DNS queries served on 127.0.0.53.
  3. Use systemd‑resolved’s --no-poll for services that must resolve local names regardless of DNS.
  4. Document the change – Add a note in your infrastructure docs that systemd‑resolved may drop hosts entries if DNS is unreachable.

TL;DR

  • systemd‑resolved prefers DNS over /etc/hosts and may silently drop local entries when DNS is unreachable.
  • Check systemd-resolve --status and journalctl -u systemd-resolved for clues.
  • Fix by adding a local DNS record, disabling DNS for the hostname, or tweaking nsswitch.conf.
  • Be aware of the security trade‑off: DNS spoofing protection vs. accidental service outages.

See also