DNS & TLS·5 min read·

Designing Split-Horizon Authoritative DNS Zones for Private Cloud VPS

Architect split-horizon DNS zones that serve internal private IP addresses to authenticated VPS peers while publishing public records to the internet.

NB

Netbay Engineering

Netbay Engineering

On this page

Organizations deploying infrastructure across both public internet facing services and private internal networks encounter a classic DNS dilemma: using public DNS records for internal services leaks private network topology to external attackers, while hardcoding IP addresses in /etc/hosts files creates an unmanageable configuration nightmare.

Split-horizon DNS (also called split-view DNS) solves this dilemma. An authoritative nameserver evaluates the source IP address of the incoming query and delivers different answers depending on the client identity. Internal VPS nodes resolve database and API endpoints directly to high-speed private network addresses (such as 10.10.1.5), while external queries either receive public edge proxy IPs or non-existent domain (NXDOMAIN) responses.

Without split-horizon DNS, internal servers communicating with peer microservices must route traffic out through public IP addresses and back through external firewalls (hairpin NAT). This unnecessarily consumes public bandwidth, adds firewall connection tracking overhead, and introduces latency. By serving private RFC 1918 addresses directly to internal hosts, traffic stays on high-speed private virtual switches.

Expand
Split Horizon DNS Architecture
Split horizon DNS resolution and view routing

Defining Access Control Lists and Views in BIND9

In BIND9 (/etc/bind/named.conf.local), organize your DNS namespaces using the view statement and access control lists (ACLs):

Split-Horizon DNS: Access-Controlled View Resolution Internal VPS Client Source: 10.10.0.0/16 Query: db.internal.net BIND9 DNS Engine view "internal" { match-clients { vps; }; returns 10.10.1.5 } view "external" { match-clients { any; }; returns 203.0.113.25 } Public WAN Client Source: Any Public IP Query: db.internal.net Resolution Security Private subnets hidden No hairpin NAT overhead Sub-millisecond resolution Zero external leakage Complete Zone Isolation
bind
acl "trusted_internal" {
    127.0.0.1;
    10.10.0.0/16;
    172.16.0.0/12;
};

view "internal" {
    match-clients { trusted_internal; };
    recursion yes;

    zone "corp.example.com" {
        type master;
        file "/etc/bind/zones/db.corp.example.com.internal";
    };
};

view "external" {
    match-clients { any; };
    recursion no;

    zone "corp.example.com" {
        type master;
        file "/etc/bind/zones/db.corp.example.com.external";
    };
};

Notice that in the internal view, recursion is enabled for trusted internal VPS nodes so the nameserver can act as a recursive resolver for outbound internet lookups. In contrast, recursion is strictly disabled (recursion no;) in the external view. Disabling external recursion is an essential security measure that prevents your server from being exploited as an open recursive resolver in distributed DNS amplification attacks.

Creating Zone Records for Internal and External Clients

Define the internal zone file (/etc/bind/zones/db.corp.example.com.internal) with private subnets:

bind
$TTL 300
@   IN  SOA ns1.example.com. admin.example.com. (
            2026102001 ; Serial
            3600       ; Refresh
            1800       ; Retry
            604800     ; Expire
            300 )      ; Minimum TTL

@       IN  NS  ns1.example.com.
api     IN  A   10.10.1.10
db      IN  A   10.10.1.20
redis   IN  A   10.10.1.30

And the external zone file (/etc/bind/zones/db.corp.example.com.external) with public edge IPs:

bind
$TTL 3600
@   IN  SOA ns1.example.com. admin.example.com. (
            2026102001 ; Serial
            7200       ; Refresh
            3600       ; Retry
            1209600    ; Expire
            3600 )     ; Minimum TTL

@       IN  NS  ns1.example.com.
api     IN  A   203.0.113.15
; Notice db and redis are omitted entirely to prevent public discovery

Testing Resolution from Distinct Client Perspectives

Verify that BIND9 delivers the correct view based on the client IP address:

bash
# Query from internal trusted IP address
dig @localhost api.corp.example.com +short
# Returns: 10.10.1.10

# Query simulating an external untrusted IP
dig @localhost -b 203.0.113.99 api.corp.example.com +short
# Returns: 203.0.113.15

If an external client attempts to resolve db.corp.example.com, the nameserver returns NXDOMAIN. The existence of your database and Redis cache tiers remains completely invisible to port scanners and reconnaissance tools.

Split-horizon DNS provides transparent, high-performance routing for internal services while maintaining an airtight external security posture.

DNS Explained: Records, Zones, and Architecture
YouTube

You can spin up an Ubuntu 24.04 instance on Netbay in under 60 seconds with Intel Xeon Platinum compute and high-speed SSD storage in Lucknow — netbayhosts.in.

Keep reading

Follow along on a real VPS

Deploy Linux in under 60 seconds

These guides are written against Ubuntu, Debian, and RHEL-family images — the same ones on NetBay.

Deploy an instance