tailscale up defaults to --accept-dns=true. The docs describe MagicDNS as a convenience feature — resolve Tailscale nodes by short name instead of IP. Every Tailscale setup guide treats it as harmless. On laptops, it is. On servers, it replaces your only DNS resolver with a userspace forwarder that isn’t ready at boot and intermittently fails on public queries.

TL;DR: MagicDNS silently rewrites /etc/resolv.conf to 100.100.100.100. On servers, this causes intermittent SERVFAIL on public domains and crash loops after reboot. Fix: disable DNS acceptance and set your own resolver.

The Symptoms #

Several Linux servers running Tailscale for mesh networking exhibited puzzling behavior:

  • Outbound requests randomly timing out, 2-3 seconds before returning an error
  • Refreshing works; the problem comes and goes with no pattern
  • Scattered SERVFAIL and i/o timeout entries in service logs
  • After a reboot, multiple services simultaneously fail to start, all reporting DNS resolution failures

If it were a network outage, all requests would fail. If it were an application bug, a reboot wouldn’t break multiple unrelated services at once. This points to something more fundamental — DNS.

Checking resolv.conf #

On the affected server:

cat /etc/resolv.conf
# resolv.conf(5) file generated by tailscale
# For more info, see https://tailscale.com/s/resolvconf-overwrite
# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN

nameserver 100.100.100.100
search your-tailnet.ts.net

If you see 100.100.100.100 with the Tailscale header — that’s your culprit. MagicDNS is enabled by default. It takes over /etc/resolv.conf, making Tailscale’s built-in forwarder the sole DNS resolver for the entire system. Every DNS query — your app resolving api.example.com, apt checking security.debian.org — goes through it.

# Verify MagicDNS is active
tailscale debug prefs 2>/dev/null | grep CorpDNS

"CorpDNS": true confirms it.

The Forwarder Is Unreliable #

MagicDNS was designed for client devices. On servers as the sole resolver, it intermittently returns SERVFAIL for perfectly valid public domains:

# Check for DNS failures in the last 24 hours (run as root)
journalctl --since "24 hours ago" | grep -i "SERVFAIL\|server misbehaving\|i/o timeout.*:53"

What showed up:

ERROR lookup app.example.com: (exchange6: SERVFAIL | exchange4: SERVFAIL)  [2.17s]
ERROR lookup app.example.com: (exchange6: SERVFAIL | exchange4: SERVFAIL)  [2.25s]
ERROR lookup cdn.example.com: (exchange4: SERVFAIL | exchange6: SERVFAIL)  [2.16s]

Multiple public domains failing simultaneously, each taking 2+ seconds. These are ordinary domains with no relation to Tailscale — collateral damage from routing everything through MagicDNS.

The Boot Race Condition #

The worst failure mode. Timeline reconstructed from journalctl after a provider maintenance reboot:

21:58:44  System boots, tailscaled starts
21:58:44  resolv.conf overwritten → nameserver 100.100.100.100
21:58:44  Other services begin starting
21:58:55  Service A starts, attempts DNS:
          ERR lookup app.example.com on 100.100.100.100:53: i/o timeout
21:59:00  ERR: server misbehaving → Service A crashes
21:59:05  systemd restarts Service A → DNS fails again → crash
21:59:11  systemd restarts again → DNS fails → crash
  ... (every 5 seconds for 5 minutes)

tailscaled writes resolv.conf immediately at startup, but the MagicDNS forwarder needs time to initialize — connect to the Tailscale control plane, fetch config, establish upstream DNS. During this window, 100.100.100.100 is in resolv.conf but can’t resolve anything. Every service that starts during this gap enters a crash loop.

Root Cause #

MagicDNS was designed for client devices — laptops, phones. Occasional DNS hiccups are invisible there.

On servers as the sole resolver, the design assumptions break:

  1. Single point of failure: all DNS depends on a userspace process. It crashes or isn’t ready → all DNS gone
  2. Intermittent unreliability: occasional SERVFAIL on public queries — hard to trace back to DNS
  3. Boot race condition: resolv.conf points to Tailscale before Tailscale is ready
  4. Silent takeover: tailscale up defaults to --accept-dns=true without warning

With resolv.conf pointing to 1.1.1.1 or 8.8.8.8, availability is far higher. Even if Tailscale crashes entirely, DNS continues working.

Fix #

Disable MagicDNS on the server (run as root):

tailscale set --accept-dns=false

Then set your own DNS. For systems without systemd-resolved:

cat > /etc/resolv.conf << 'EOF'
nameserver 1.1.1.1
nameserver 8.8.8.8
EOF

For systems running systemd-resolved, configure it through /etc/systemd/resolved.conf instead — writing to /etc/resolv.conf directly will be overwritten.

To prevent resolv.conf from being overwritten by other processes:

chattr +i /etc/resolv.conf

chattr +i may not work on OpenVZ 7 containers — the filesystem doesn’t support it. On those systems, also check if your provider’s DHCP client is overwriting resolv.conf.

Verification #

# DNS no longer goes through Tailscale
cat /etc/resolv.conf        # Should show 1.1.1.1, not 100.100.100.100
dig +short google.com       # Should return instantly

# Tailscale itself is unaffected
tailscale status
tailscale ping <other-node>

--accept-dns=false persists across reboots.

What You Lose #

CapabilityAffected?
Tailscale mesh networkingUnaffected
SSH to this server via TailscaleUnaffected
tailscale status / tailscale pingUnaffected
All outbound DNS from appsUnaffected (now uses 1.1.1.1)
Resolving Tailscale nodes by short name on this serverMust use IP

For servers, the last item is almost never needed. If you do need it, add specific entries to /etc/hosts.

Quick Check for Your Servers #

grep -c "100.100.100.100" /etc/resolv.conf

Returns 1? You’re on MagicDNS. Check if it’s already causing damage:

journalctl --since "24 hours ago" --no-pager | grep -c "SERVFAIL\|server misbehaving"

Non-zero means MagicDNS is already impacting your services.

Docker Users #

Containers can inherit the host’s broken DNS depending on network mode:

SetupRisk
Bridge + explicit dns: [1.1.1.1]Safe
Bridge + default DNSMay inherit host DNS
Host networkFully exposed
# Check all running containers (run as root)
docker inspect --format '{{.Name}} dns={{.HostConfig.Dns}} net={{.HostConfig.NetworkMode}}' \
  $(docker ps -q)

MagicDNS is disabled on all my servers now. Two weeks, zero DNS-related incidents. The previous average was two or three per week — I just hadn’t connected them to Tailscale.