Split-horizon DNS, also called split-brain DNS, is a design where the same hostname returns different answers depending on who is asking. An internal client gets a private IP that routes over the LAN or VPN, while an external client on the public internet gets a public IP that lands on a firewall or load balancer. One name, two views. This lets internal traffic stay off the public internet, keeps internal-only hostnames out of public zones, and avoids the awkward hairpin where a laptop in the office has to exit to the internet and come back just to reach a server sitting in the next rack.
Why serve different answers for one name?
The classic driver is a service that is reachable both inside and outside, such as a corporate mail server, an intranet portal, or an application behind a load balancer. If the public DNS answer is the only answer, internal users are forced out to the WAN edge and back (hairpinning), which wastes bandwidth and can break when the firewall does not allow reflection. Split-horizon fixes this by handing internal clients the direct private address.
Common reasons teams reach for split-horizon:
- Dual-interface services. A server with both a private and a public address answers each audience on the right interface.
- Load balancers. Internal clients hit an internal VIP; external clients hit a public VIP with WAF and rate limiting in front.
- Keeping internal hostnames private. Names like
git.corp.example.comorvault.example.comresolve only inside, so they never appear in public DNS for attackers to enumerate. - Legacy and migration. During a cutover you can point internal users at the new system while the public still sees the old one, or vice versa.
The two ways to build it
There are two mainstream approaches. The right one depends on how much you trust a single server to classify clients correctly.
1. Views with ACLs on one authoritative server
A single DNS server holds two copies of the zone and decides which to serve based on the client source address. BIND calls this feature view; other servers use similar concepts. You define an access control list (ACL) for your internal ranges, then order the views so the internal view matches first and everything else falls through to the external view.
acl "internal-nets" {
10.0.0.0/8;
192.168.0.0/16;
172.16.0.0/12;
};
view "internal" {
match-clients { internal-nets; };
zone "example.com" {
type master;
file "db.example.com.internal";
};
};
view "external" {
match-clients { any; };
zone "example.com" {
type master;
file "db.example.com.external";
};
};
The internal zone file returns the private address; the external file returns the public one:
; db.example.com.internal
app IN A 10.20.0.15
; db.example.com.external
app IN A 203.0.113.40
2. Separate internal and external servers
Instead of views, run two independent sets of nameservers. Your internal resolvers are authoritative (or forward) for the private copy of the zone, while public authoritative nameservers at your registrar or DNS host serve only the public copy. Internal clients are configured to use the internal resolvers; the outside world reaches only the public servers. This is cleaner from a blast-radius standpoint because the public servers never even hold the private records, and it is often how a cloud private zone (for example an internal-only resolver zone) plus a public zone are combined.
Views versus separate servers at a glance
| Factor | Views on one server | Separate internal/external servers |
|---|---|---|
| Infrastructure | One server (or HA pair) | Two distinct server sets |
| Private records exposed if misconfigured | Possible (both copies live together) | No (public servers never hold them) |
| Client classification | By source IP ACL | By which resolver the client is pointed at |
| Sync burden | Two zone files, one host | Two zone files, two platforms |
| Typical fit | Self-hosted BIND or similar | Cloud private zone plus public DNS host |
How to verify each view is correct
Always test from both sides. From an internal host, query your internal resolver and confirm the private answer. From anywhere on the public internet (or a public resolver like 1.1.1.1 or 8.8.8.8), confirm the public answer.
$ dig app.example.com +short @10.0.0.53
10.20.0.15
$ dig app.example.com +short @1.1.1.1
203.0.113.40
A quick way to compare both at once is to run the query against your internal resolver and a public resolver side by side. If the internal query returns the public IP, your ACL did not match the client, which usually means the request arrived from an unexpected source address (for example traffic coming through a NAT that rewrites the source).
Common pitfalls
Split-horizon is powerful, but it introduces a second source of truth. The failure modes are almost always about drift and classification.
- The two zones fall out of sync. You add a record to the public view and forget the internal one, so internal users get NXDOMAIN or a stale target. Automate publishing both copies from one source where you can.
- VPN and remote clients land in the wrong view. A user on the VPN may egress through a gateway whose source IP is not in your internal ACL, so they get the public answer and hairpin anyway. Make sure VPN pools are included in the internal ACL and that split-tunnel DNS points VPN clients at the internal resolver.
- Caching crosses the boundary. A laptop that resolved the name on the corporate LAN can carry the private IP in its cache onto a home network, where that address is unreachable until the TTL expires. Keep TTLs modest on split records.
- TLS certificate mismatches. The internal target must present a certificate valid for the public hostname, or internal browsers throw warnings. Use the same publicly trusted certificate on both faces of the service.
- DNSSEC and views do not mix cleanly. Serving different signed answers per view is complicated; many teams sign only the public view and leave the internal view unsigned on trusted networks.
When split-horizon is worth it, and when to avoid it
Reach for split-horizon when you genuinely need different routing for internal and external clients, when hairpinning is a real performance or firewall problem, or when you must keep internal hostnames out of public DNS. It pays off most in corporate intranets and in environments with strict internal/external separation.
Skip it when a single public answer works fine, when your firewall already supports NAT reflection cleanly, or when the operational cost of keeping two zones in sync outweighs the benefit. A small site with one web server and no internal-only services does not need two views; the complexity will cost you more in drift bugs than it saves.
| Situation | Recommendation |
|---|---|
| Public web server only, no internal services | Single public zone, no split |
| Internal users hairpinning to reach an app | Split-horizon for that name |
| Internal-only tools you do not want enumerated | Separate internal servers or private zone |
| Dual-interface mail or app behind LB | Split-horizon, same certificate both sides |
If you are planning a cutover or just want to confirm that internal and external views agree with what you intended, run your name through the Valla DNS propagation checker from multiple vantage points to see exactly which answer each resolver returns. For the building blocks behind this design, see our related guides in the Valla DNS learning hub on DNS record types, TTL strategy, and resolver behavior.