Many organizations face the need to maintain both public and private subdomains under the same top-level domain (TLD). The traditional approach of creating separate zone files for private subdomains becomes cumbersome when dealing with multiple internal services.
Your existing solution with a dedicated zone for svn.example.com
works but has scalability limitations:
zone "svn.example.com" IN {
type master;
file "/etc/named/svn.example.com.zone";
};
Each new private subdomain requires:
- New zone declaration
- Additional zone file
- DNS server reload
The optimal solution combines zone delegation with conditional forwarding:
options {
forwarders { 8.8.8.8; 8.8.4.4; }; // Public DNS resolvers
forward first;
};
zone "example.com" {
type master;
file "/etc/named/example.com.zone";
allow-query { any; };
};
zone "internal.example.com" {
type forward;
forwarders { 10.200.1.1; }; // Your internal DNS
};
Create a comprehensive zone file that handles both cases:
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2023081501 ; Serial
3600 ; Refresh
1800 ; Retry
604800 ; Expire
86400 ) ; Minimum TTL
; Public records
@ IN NS ns1.example.com.
@ IN A 203.0.113.1
www IN A 203.0.113.1
mail IN A 203.0.113.2
; Private records
svn IN A 10.200.1.1
git IN A 10.200.1.2
jenkins IN A 10.200.1.3
; Wildcard catch-all for public resolution
* IN CNAME example.com.
- Client queries
svn.example.com
- DNS server checks local zone file first
- If no match found, forwards to public resolvers
- Returns either private IP or public resolution
For more complex scenarios, consider:
view "internal" {
match-clients { 10.200.0.0/16; };
recursion yes;
zone "example.com" {
type master;
file "/etc/named/internal.example.com.zone";
};
};
view "external" {
match-clients { any; };
recursion no;
zone "example.com" {
type master;
file "/etc/named/external.example.com.zone";
};
};
This BIND views configuration provides complete separation between internal and external DNS resolution while maintaining the same domain structure.
- Implement zone file version control
- Automate serial number increments
- Set up monitoring for resolution failures
- Document all private subdomains
When managing internal networks with existing public DNS infrastructure, administrators often need to make specific subdomains resolve differently internally while maintaining normal resolution for public records. The classic example is having svn.example.com
point to an internal IP (10.200.1.1) while letting other *.example.com
records resolve normally.
Traditional methods like creating separate zone files for each private subdomain become cumbersome at scale. Here's a better approach using BIND's forwarders
and zone
directives:
// named.conf fragment
options {
forwarders { 8.8.8.8; 8.8.4.4; }; // Your public DNS servers
};
zone "example.com" {
type master;
file "/etc/named/zones/internal.example.com.zone";
allow-query { internal-network; };
};
zone "." {
type hint;
file "/etc/named/named.ca";
};
The key is creating a zone file that contains your private records while letting other queries fall through:
; internal.example.com.zone
$TTL 86400
@ IN SOA ns1.example.com. admin.example.com. (
2023081501 ; serial
3600 ; refresh
1800 ; retry
604800 ; expire
86400 ) ; minimum
; Private records
svn IN A 10.200.1.1
gitlab IN A 10.200.1.2
jenkins IN A 10.200.1.3
; Public records delegation
www IN CNAME public-lb.example.com.
mail IN CNAME mailhandler.example.com.
* IN CNAME public-lb.example.com.
For more complex setups, consider using views and conditional forwarding:
view "internal" {
match-clients { 10.200.0.0/16; };
recursion yes;
zone "example.com" {
type master;
file "/etc/named/zones/internal.example.com.zone";
};
zone "." {
type hint;
file "/etc/named/named.ca";
};
};
view "external" {
match-clients { any; };
recursion no;
zone "example.com" {
type master;
file "/etc/named/zones/public.example.com.zone";
};
};
When implementing this hybrid approach, pay attention to TTL values. Private records should typically have shorter TTLs (3600 seconds) for flexibility, while public records can use longer values.
Remember to test your configuration with named-checkconf
and named-checkzone
before reloading BIND.