How to Configure DNS Forwarders and Conditional Forwarding on Windows Server 2025
DNS forwarding is a foundational component of enterprise name resolution strategy. Rather than allowing every DNS server in your organization to perform its own recursive lookups against the root hints on the internet, you configure forwarders to direct unresolved queries to designated upstream resolvers. Windows Server 2025 provides rich PowerShell-based tooling for managing standard forwarders, conditional forwarders, stub zones, root hints, and advanced DNS policies—including split-brain DNS using client subnet-based responses. This tutorial walks through each configuration in detail, giving you the knowledge to build a resilient, policy-aware DNS infrastructure.
Prerequisites
- Windows Server 2025 with the DNS Server role installed
- Administrative privileges on the DNS server
- PowerShell 5.1 or later (DnsServer module available via RSAT or built-in)
- Network connectivity to upstream forwarder IP addresses
- Basic understanding of DNS zone types and resolution hierarchy
Step 1: Understanding DNS Resolution Order
Before configuring forwarders, it is important to understand the query resolution order Windows DNS follows. When a client query arrives, the server checks its local zones first. If no authoritative match exists, the server either uses configured forwarders or, if no forwarders are defined (or all fail), falls back to root hints. Conditional forwarders take precedence over standard forwarders for their specific domain namespaces. This hierarchy is: Local Zones → Conditional Forwarders → Standard Forwarders → Root Hints.
Step 2: Configuring Standard DNS Forwarders
Standard forwarders handle all queries that your DNS server cannot answer locally. You should specify multiple forwarder IPs for redundancy. The UseRootHint parameter controls whether the server falls back to root hints if all forwarders fail to respond.
# View current forwarder configuration
Get-DnsServerForwarder
# Add forwarders — here using Cloudflare and Google Public DNS
# UseRootHint $false means do NOT fall back to root hints if forwarders fail
Add-DnsServerForwarder -IPAddress 1.1.1.1, 8.8.8.8 -UseRootHint $false
# Verify the configuration
Get-DnsServerForwarder | Format-List *
# Remove a specific forwarder IP
Remove-DnsServerForwarder -IPAddress 8.8.8.8
# Set a timeout (seconds) for forwarder queries
Set-DnsServerForwarder -IPAddress 1.1.1.1, 1.0.0.1 -UseRootHint $false -Timeout 5
Setting UseRootHint $false is recommended in environments where all internet-bound DNS should go through corporate proxies or where DNS-over-HTTPS is enforced at the upstream forwarder. If the forwarder is unavailable and root hints are disabled, resolution fails—plan accordingly with multiple redundant forwarder IPs.
Step 3: Configuring Conditional Forwarders
Conditional forwarders direct queries for specific domain namespaces to designated DNS servers. This is the standard mechanism for resolving names in partner organizations, Azure private DNS zones, or internal namespaces hosted on separate DNS infrastructure.
# Add a conditional forwarder for a partner domain
# MasterServers are the DNS servers authoritative for that namespace
Add-DnsServerConditionalForwarderZone `
-Name "partner.contoso.com" `
-MasterServers 10.50.0.10, 10.50.0.11 `
-ReplicationScope "Forest"
# Add a conditional forwarder for Azure private DNS
Add-DnsServerConditionalForwarderZone `
-Name "privatelink.blob.core.windows.net" `
-MasterServers 168.63.129.16 `
-ReplicationScope "Domain"
# List all conditional forwarder zones
Get-DnsServerZone | Where-Object { $_.ZoneType -eq "Forwarder" } |
Select-Object ZoneName, MasterServers, ZoneType
# Remove a conditional forwarder
Remove-DnsServerZone -Name "partner.contoso.com" -Force
# Modify master servers on existing conditional forwarder
Set-DnsServerConditionalForwarderZone `
-Name "partner.contoso.com" `
-MasterServers 10.50.0.10, 10.50.0.12
The ReplicationScope parameter controls whether the conditional forwarder is replicated across all DNS servers in the domain (Domain), the entire forest (Forest), or kept local (None). Use Forest for namespaces all domain controllers need to resolve.
Step 4: Stub Zones vs Conditional Forwarders
Stub zones are an alternative to conditional forwarders. Unlike a conditional forwarder that statically lists target DNS server IPs, a stub zone stores the NS records and glue A records for the target zone and dynamically queries the authoritative servers. Stub zones are more resilient to infrastructure changes because they auto-update NS records.
# Create a stub zone — the DNS server queries the master for NS and A (glue) records
Add-DnsServerStubZone `
-Name "subsidiary.local" `
-MasterServers 192.168.100.10 `
-ReplicationScope "Forest" `
-ZoneFile "subsidiary.local.dns"
# List stub zones
Get-DnsServerZone | Where-Object { $_.ZoneType -eq "Stub" } |
Select-Object ZoneName, MasterServers
# Force refresh of stub zone data
Start-DnsServerZoneTransfer -Name "subsidiary.local" -FullTransfer
# View stub zone NS records after transfer
Get-DnsServerResourceRecord -ZoneName "subsidiary.local" -RRType "NS"
Use stub zones when the authoritative servers for the remote namespace may change IP addresses over time. Use conditional forwarders when you control both environments and IPs are stable—conditional forwarders are simpler and lower overhead.
Step 5: Managing Root Hints
Root hints are the list of internet root name servers used when no forwarder is configured or when forwarder fallback is enabled. In an internal-only environment, you may want to replace the default internet root hints with internal root servers for a disconnected forest.
# View current root hints
Get-DnsServerRootHint | Format-Table IPAddress, NameServer -AutoSize
# Remove all existing root hints (exercise caution in production)
Get-DnsServerRootHint | ForEach-Object {
Remove-DnsServerRootHint -NameServer $_.NameServer -Force
}
# Add a custom internal root hint (for isolated/disconnected AD forests)
Add-DnsServerRootHint -NameServer "internal-root.corp.local" -IPAddress 10.0.0.1
# Restore default internet root hints from the built-in list
Import-DnsServerRootHint
Step 6: Configuring DNS Policy for Split-Brain DNS
DNS Policy enables conditional responses based on client subnet, time of day, or query type. Split-brain DNS (also called split-horizon) serves different answers to internal vs external clients for the same DNS name—without maintaining two separate zones.
# Step 6a: Define client subnets
Add-DnsServerClientSubnet -Name "InternalSubnet" -IPv4Subnet "10.0.0.0/8"
Add-DnsServerClientSubnet -Name "ExternalSubnet" -IPv4Subnet "0.0.0.0/0"
# Step 6b: Create zone scopes (partitions within the zone)
# The default scope already exists; add an internal scope
Add-DnsServerZoneScope -ZoneName "contoso.com" -Name "InternalScope"
# Step 6c: Add resource records to each scope
# Internal clients get the internal IP
Add-DnsServerResourceRecord `
-ZoneName "contoso.com" `
-ZoneScope "InternalScope" `
-A `
-Name "www" `
-IPv4Address "10.10.1.100"
# External clients get the public IP (added to default scope)
Add-DnsServerResourceRecord `
-ZoneName "contoso.com" `
-A `
-Name "www" `
-IPv4Address "203.0.113.50"
# Step 6d: Create query resolution policies
# Internal subnet → serve from InternalScope
Add-DnsServerQueryResolutionPolicy `
-Name "InternalPolicy" `
-Action ALLOW `
-ClientSubnet "EQ,InternalSubnet" `
-ZoneScope "InternalScope,1" `
-ZoneName "contoso.com" `
-ProcessingOrder 1
# External (all other) clients → serve from default scope
Add-DnsServerQueryResolutionPolicy `
-Name "ExternalPolicy" `
-Action ALLOW `
-ClientSubnet "EQ,ExternalSubnet" `
-ZoneScope "contoso.com,1" `
-ZoneName "contoso.com" `
-ProcessingOrder 2
# View all policies on the zone
Get-DnsServerQueryResolutionPolicy -ZoneName "contoso.com"
Step 7: Testing DNS Resolution with Resolve-DnsName
After configuring forwarders and policies, validate resolution behavior from multiple perspectives using Resolve-DnsName and classic tools.
# Test basic forward resolution via a specific DNS server
Resolve-DnsName -Name "www.contoso.com" -Server "10.0.0.53" -Type A
# Test conditional forwarder resolution
Resolve-DnsName -Name "app.partner.contoso.com" -Server "10.0.0.53" -Type A
# Test that forwarder is reachable and functioning
Resolve-DnsName -Name "microsoft.com" -Server "1.1.1.1" -Type A
# Use nslookup for SRV record verification
nslookup -type=SRV _ldap._tcp.dc._msdcs.contoso.com 10.0.0.53
# Check DNS server statistics for forwarder query counts
Get-DnsServerStatistics | Select-Object -ExpandProperty RecursionStatistics
# Test from a client machine targeting your DNS server
Test-NetConnection -ComputerName 10.0.0.53 -Port 53
Step 8: Monitoring and Best Practices
Enable DNS debug logging selectively to capture query/response data for troubleshooting. Use DNS audit events in the event log (Microsoft-Windows-DNS-Server/Audit) for change tracking without the overhead of full debug logging.
# Enable DNS audit logging (lightweight, tracks configuration changes)
Set-DnsServerDiagnostics -EnableLoggingToFile $false -EnableLoggingForPluginDllEvent $true
# Check DNS Server operational log for errors
Get-WinEvent -LogName "Microsoft-Windows-DNS-Server/Audit" -MaxEvents 50 |
Where-Object { $_.LevelDisplayName -eq "Error" } |
Format-Table TimeCreated, Message -AutoSize
# Export full DNS server configuration for documentation
Get-DnsServer | Export-Clixml -Path "C:DNS-Backupdns-config-$(Get-Date -Format yyyyMMdd).xml"
Conclusion
Windows Server 2025 provides a comprehensive PowerShell-driven toolkit for managing every layer of DNS forwarding—from simple upstream forwarders to conditional zone-based forwarding, stub zones, and sophisticated split-brain policies driven by client subnet matching. By combining Add-DnsServerForwarder, Add-DnsServerConditionalForwarderZone, and Add-DnsServerQueryResolutionPolicy, you can build a DNS architecture that serves internal users with private addresses, external users with public addresses, and partner namespaces with dedicated resolvers—all from a single, replication-aware DNS infrastructure. Always test changes with Resolve-DnsName from representative clients on each subnet to confirm policy enforcement before rolling out to production workloads.