You open a laptop in a hotel room, bring up the client, type the internal file server name, and get nothing back. The tunnel reports connected, and a ping to an address inside the same subnet still answers, so the transport itself is fine. Only the name fails, and that gap narrows the problem to two places: which resolver the client asked, and whether the answer it got can travel back through the tunnel. Get one right and skip the other and the failure simply moves.

Before editing any profile, confirm what the client does with the name. On Linux, resolvectl query files.corp.example prints which link and which resolver produced the answer. On Windows, Resolve-DnsName files.corp.example shows the server that replied and the address it returned.

Read the answer before you change anything

If the name comes back NXDOMAIN in a few milliseconds, the query never reached your zone and some public or hotel resolver answered instead. If it comes back after a long pause, something is dropping UDP port 53 on the way and the client eventually fell back. If it answers with the right address but the connection still stalls, the lookup is fine and your problem is routing or the service itself.

That three-way split saves an hour of guessing. It also tells you whether to touch the VPN at all: a name that resolves to the correct private address has already proved the resolver path, so the work left is on the data path.

Hand the resolver out from inside the tunnel

Clients fall into two groups. One group can be told a resolver by the server during connection setup; the other keeps the setting in a local file that no gateway can change remotely.

OpenVPN is in the first group. On the server, push "dhcp-option DNS 10.8.0.53" and push "dhcp-option DOMAIN corp.example" travel down the control channel, but only if the client config still has pull enabled. A hand-edited client carrying pull-filter ignore "dhcp-option" will never see them, and that single line explains a surprising number of "the server pushes it but my laptop disagrees" cases.

WireGuard is in the second group, because the protocol has no option negotiation at all. The resolver and search domain go into the client's own [Interface] block as DNS = 10.8.0.53, corp.example. wg-quick applies that through resolvconf or systemd-resolved, and on Windows the official client installs NRPT rules that exist only while the tunnel is up — Get-DnsClientNrptPolicy lists them, which makes it a quick way to see whether the client ever applied your file.

IPsec/IKEv2 sits in between. strongSwan's attr plugin can return a DNS server drawn from a pool, and a Windows client normally accepts it, but a profile that pins its own name server wins over whatever the gateway offers. On a Linux client the equivalent manual step is resolvectl dns wg0 10.8.0.53 followed by resolvectl domain wg0 '~corp.example'; both vanish when the interface does, which is exactly what you want for a tunnel-scoped setting.

Scope the suffix instead of swallowing every query

Pointing the client's whole resolver list at your internal server is easy and usually wrong. Every public name then resolves from your datacenter egress, so CDNs hand back distant addresses, and one resolver outage takes the user's browsing down with it.

Send only the private suffix inward. On systemd-resolved, a domain beginning with ~ is routing-only, so ~corp.example means queries under that suffix go to that link's servers while everything else keeps using the physical network. Windows does the same job with NRPT rules scoped to a namespace, and macOS with a supplemental resolver file under /etc/resolver/.

Multicast names deserve their own answer. .local names are link-local by design (RFC 6762) and a point-to-point tun interface does not carry that multicast group, so adding a public resolver will not publish them and asking a unicast internal resolver for them returns NXDOMAIN. A reflector such as avahi in reflector mode can bridge two segments, but that is a server-side decision no client can request. If a printer or NAS has to be reachable by name, give it an A record in your zone instead.

Prove the answer can travel back

A correct answer pointing at an unreachable address looks exactly like a resolver problem until you check the route. Ask the kernel where the answer would go: ip route get 10.20.5.20 names the interface and, more usefully, the source address it would use.

Watch the resolver address itself. A client with DNS = 10.8.0.53 next to AllowedIPs = 10.20.0.0/16 sends its queries out the physical NIC, where they die quietly, because the resolver is not inside any prefix the tunnel claims. That mismatch is the most common single-cause failure in this whole area, and it is invisible unless you compare the DNS setting with the allowed prefixes line by line.

Overlapping ranges cause the opposite failure. The answer is right, the route exists, and it points at the wrong host, because 192.168.0.0/24 at home is more specific than the tunnel's route to the same range. Renumber one side or push a narrower route, then confirm the service host's firewall and reply path; strongSwan's notes on forwarding cover the sysctl side of that path.

Certificates are a separate identity check that people blame on DNS. If the browser reports a name mismatch instead of a resolution error, the lookup already worked and the SAN on the certificate is what needs fixing. Test HTTPS against the name, never against the bare IP.

Retest from the client, not the gateway

Test inside the application the user complains about, because a command-line lookup is not proof that the browser takes the same path. Chrome's secure DNS and Firefox's network.trr.mode can bypass the system resolver entirely, and when they do, a private name either fails or leaks to a public resolver. Comparing resolvectl query with a hand-run dig @10.8.0.53 files.corp.example tells you which of the two happened.

Then disconnect and reconnect before calling it fixed. Settings applied by hand to an interface disappear with the interface, and a profile that only looked correct because of a leftover local edit will fail on the next boot.

A short checklist for the next machine: the name resolves through the tunnel resolver, the suffix is scoped rather than global, the resolver address sits inside the allowed prefixes, the answer's host answers on the service port, and the certificate covers the name the user typed.

Artihkkalat mat laktásit