WireGuard split DNS on macOS: search domains and resolvers

Why your Mac sends every name to the WireGuard tunnel, how search domains differ from per-domain resolvers, and how to check what macOS really uses.

On a Mac, a WireGuard configuration whose DNS = line names a server usually sends every name lookup to that server while the tunnel is up: the remote network’s names, and everything else. Split DNS is the alternative. A resolver is chosen for particular domains, and every other name keeps the DNS you normally use. Search domains are a third, separate mechanism: they complete short names, and they do not choose a resolver. Telling the three apart explains most of the symptoms people run into.

This guide covers macOS and IPv4 networks.

Official app status, 7 October 2026: the published WireGuard app for macOS is version 1.0.16, and it has no per-domain DNS setting. An opt-in split DNS patch has been proposed upstream, but our check found no upstream merge or published release containing it. See the official app source and macOS App Store listing.

The problem: one resolver for the whole machine

The examples below use fictional names and addresses. A remote network runs a DNS server at 10.20.0.53, the only server that knows server.corp.example.com. Your own network, 192.168.50.0/24, has names that only your router’s DNS knows: a printer, a NAS.

With one resolver for every name, one of those two sets fails. Point everything at 10.20.0.53 and your local names stop resolving, while every other lookup takes a detour through the remote network. Keep your router’s DNS and server.corp.example.com never resolves, even though 10.20.0.20, the address behind it, is perfectly reachable.

In the official WireGuard app

A configuration like this one is common:

[Interface]
DNS = 10.20.0.53, corp.example.com

The app’s network settings read it as follows:

  • 10.20.0.53, an address, becomes the tunnel’s DNS server.
  • corp.example.com, or any other entry that is not an address, becomes one of the tunnel’s search domains.
  • As soon as at least one server is given, the app sets the tunnel’s match-domain list to a single empty entry. The source comment reads: “All DNS queries must first go through the tunnel’s DNS.”

The published app has no setting to send only some domains to the tunnel’s DNS. The search domain does not narrow anything: it completes names, while every query still goes to 10.20.0.53 first.

With wg-quick on macOS

wg-quick, from wireguard-tools, splits the same line into server addresses and search domains. Its macOS script then works on the whole machine, not on a tunnel interface:

  • If at least one server address is given, it sets those servers and search domains on every network service listed by networksetup, replacing their existing values. If the line has no search domain, it clears the services’ search domains.
  • While the tunnel is up, it re-applies those settings when the routing table changes.
  • When the tunnel goes down, it restores the values it recorded before changing them.
  • A DNS = line with search domains but no server address changes no DNS setting at all.

This is a machine-wide DNS change, not split DNS.

Search domains are not resolver selection

What a search domain does

A search domain lets a short name be tried with a suffix: server can be looked up as server.corp.example.com. It helps complete and search for names. It does not decide which DNS server answers for corp.example.com.

That is consistent with the reports of search domains that “only autocomplete”: completing the name is the whole of a search domain’s job. Whichever resolver received the completed name still had to know it.

What split DNS does

Split DNS chooses a resolver for a domain. Lookups for names under corp.example.com go to 10.20.0.53; every other name stays with the resolver you normally use. The domain that selects the resolver is often called a match domain.

A client can take its match domains and its search domains from the same list, but they remain two mechanisms. One rewrites a short name; the other chooses the server that answers for a domain. A configuration can have either one without the other.

It is not the same thing as split tunnelling

Split tunnelling decides which addresses travel through the tunnel: that is AllowedIPs. Split DNS decides which resolver answers a name. You often need both, and they depend on each other: the remote DNS server itself must be routed through the tunnel. In the example, AllowedIPs has to cover 10.20.0.53 as well as 10.20.0.20. See DNS, routing and split tunnelling for the routing half.

Your options on macOS

ApproachWhat it changesWhat it does not do
Keep the official app’s behaviourEvery lookup goes first to the tunnel’s DNS server while connectedNames that only your own network’s DNS knows may stop resolving
Tick “Exclude private IPs” in the official appRouting: private IPv4 ranges leave a full tunnelIt does not choose a resolver per domain; the DNS settings stay the same
Add a resolver file in /etc/resolverA resolver configuration for one domain, naming the server you chooseIt is not tied to the tunnel, and its interaction with the official app while connected is not established
Use wg-quickMachine-wide DNS while the tunnel is up, restored afterwardsNo per-domain resolver; scripts can add one, and their cleanup is then yours to maintain
Use a client that selects resolvers per domainOnly the declared domains use the remote resolverCheck how it treats search domains, and what happens to names when the tunnel stops

Per-domain resolvers with /etc/resolver

The manual page on your Mac, man 5 resolver, describes resolver configuration files for individual domains, read from /etc/resolver. For a file in that directory, the file name is used as the domain name, and the nameserver keyword gives the address of a name server that the resolver should query. The page describes queries being routed to the configuration whose domain best matches the name. For the example, a file named /etc/resolver/corp.example.com would contain:

nameserver 10.20.0.53

The same page documents port and the other keywords. It also says that resolver configurations can come from other sources, such as the System Configuration database, and that users should make no assumptions about where the configuration comes from.

Know its limits before relying on it:

  • Creating the file needs administrator rights.
  • The file stays in place whether the tunnel is up or not. Nothing removes it when the tunnel stops: it still names 10.20.0.53 for that domain, a server that may only be reachable through the tunnel.
  • It is a macOS mechanism, not a WireGuard setting. How it interacts with the official WireGuard app while that app is connected has not been established here: the app sends every lookup to the tunnel’s DNS first. Do not assume one overrides the other; check the result with scutil --dns and a real lookup, as described below.

What “Exclude private IPs” changes

In the official app for macOS, this checkbox appears in the tunnel editor when the configuration has a single peer whose AllowedIPs covers every IPv4 address (0.0.0.0/0).

Ticking it rewrites AllowedIPs:

  • 0.0.0.0/0 is replaced by a fixed list that the source describes as all non-private IPv4 addresses. It leaves out the private ranges 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.
  • The configuration’s DNS server addresses are added, so they stay in the tunnel.
  • Any other IPv4 entry in that AllowedIPs is replaced as well.

Private addresses then leave through your normal connection. Your local network becomes reachable outside the tunnel. Remote private networks leave the tunnel too: apart from the DNS server addresses that were added, they are no longer reached through it.

The option changes routes only. The DNS settings stay as they were, and lookups still go to the tunnel’s DNS server first. It does not select a resolver per domain.

Check what macOS really uses

Three commands answer three different questions. Replace the fictional names and addresses with yours. They read the configuration or perform lookups; they change no setting.

Read the resolver configuration

scutil --dns

This answers: which resolvers has macOS been given, and for which domains? Look for the tunnel’s DNS server, the domain attached to each resolver, the search domains, and the interface each resolver is scoped to. A resolver with no domain and a resolver for corp.example.com play different roles. The first resolver listed is not necessarily the one used for every query.

scutil --dns shows configuration, not the result of a lookup.

Resolve through the system

dscacheutil -q host -a name server.corp.example.com

This answers: what does macOS return when it is asked for this name through its standard lookup calls? Its manual page, man dscacheutil, says it initiates a query using standard calls, and that the result can come from a cache. It shows the address the system returns, not which DNS server provided it. Use the fully qualified name, and compare the returned address with the one you expect.

Query one server directly

dig @10.20.0.53 server.corp.example.com

This answers: does that server know the name, and can you reach it? dig @server sends the query straight to the server you name and bypasses the system’s resolver selection. A correct answer proves that the server works and is reachable. It does not prove that macOS will choose that server for the name.

Test with the real application

Open the service by its full name, for instance https://server.corp.example.com/. This also checks the HTTPS certificate, which only validates on the real hostname. An application that uses its own DNS mechanism can behave differently from the system resolver. Cached answers can hide a change: after changing a setting, re-test with names whose expected answer you know.

Common traps

SymptomWhat to check
Only the short name failsThe search domain: absent, or not applied by your client. Test the full name
The full name fails, the address answersThe resolvers and their domains in scutil --dns; what the system returns with dscacheutil
Every name goes through the tunnelThe official app’s catch-all DNS, or wg-quick’s machine-wide settings
Local names stop resolving once connectedA remote resolver answering for everything; see the options above
dig @10.20.0.53 answers, the browser does notdig bypassed the system’s resolver selection; read scutil --dns, and compare with what dscacheutil returns
No answer at all from the remote DNS serverIts address in AllowedIPs; see DNS, routing and split tunnelling
Names fail after the tunnel stopsSettings not restored, or a file left in /etc/resolver
A name ending in .local does not resolve through DNSBonjour’s multicast DNS uses that suffix, and Apple has documented resolution failures for unicast DNS names ending in .local

If nothing answers even by address, the problem is the tunnel itself: see When the tunnel will not connect when no handshake completes, and WireGuard connected but no traffic when one does.

Why it matters once several networks are connected

With two remote networks that each have their own DNS server, a single resolver is wrong for one of them: neither server knows the other network’s names. Several VPN clients that each change the machine’s DNS settings can also interfere with one another, particularly when one of them stops. For two WireGuard tunnels at once, routes and DNS together, see Multiple WireGuard tunnels on macOS.

Using Paart for split DNS

Paart Client is one WireGuard client that selects a resolver per domain. Its split DNS works with internal names that you declare for each connection.

What internal names do

Nothing is split until you say which names belong to the remote network. In the connection’s detail, open Names and choose Add an internal name: int.example.com, say. Those names, and only those, are resolved through the tunnel. Every other name keeps this device’s DNS:

  • int.example.com goes through the tunnel to the remote resolver, 10.0.99.10;
  • google.com goes to the DNS of the Wi-Fi you are on.

Unless you pick an override resolver in Settings › Resolvers: that resolver then answers every other name instead.

The Look up with row, at the top of Names, says where the internal names are looked up. Left empty, it is the configuration’s DNS. With no internal name listed, nothing is split: the resolver chosen under DNS answers every name. On macOS, Paart attaches the internal names to the chosen resolver as match domains.

Internal names select a resolver; they are not search domains. Paart does not apply the search domains of a configuration’s DNS = line: they are dropped on import, and the import says so. Use fully qualified names, such as server.int.example.com.

Internal names are available on Mac, iPhone and iPad. They are part of advanced networking: on the free tier they work on your Free connection, and on the others they come with Paart Pro.

Technical sources

Source review: 7 October 2026. The official app and wg-quick are described from their upstream source, not from a test of every macOS version.