BIND’s DNS forwarders aren’t just a simple “send queries elsewhere” button; they’re a critical component for managing how your DNS server resolves names it doesn’t know about, and how it keeps its own cache fresh.

Let’s see BIND in action, resolving a name using forwarders. Imagine your BIND server, ns1.example.com, is asked to resolve www.google.com.

dig @ns1.example.com www.google.com

If ns1.example.com doesn’t have www.google.com in its cache and is configured to use forwarders (say, 8.8.8.8 and 8.8.4.4), it won’t go out and ask the root servers itself. Instead, it immediately sends the query for www.google.com to 8.8.8.8 and 8.8.4.4. Whichever of those forwarders responds first with the IP address for www.google.com will have its answer relayed back to the original client that queried ns1.example.com. ns1.example.com then caches this answer for future requests.

The core problem forwarders solve is offloading the iterative resolution process. Instead of your BIND server performing the full dance of querying root servers, then TLD servers, then authoritative servers for a given domain, it delegates that entire process to another DNS server. This is particularly useful in enterprise networks where you might want to:

  • Centralize external DNS resolution: All internal DNS servers forward to a single, managed set of external resolvers.
  • Improve performance: Forwarders might be closer to the internet or have better network connectivity, leading to faster external lookups.
  • Enhance security: By not directly querying external servers, you reduce the attack surface of your internal DNS infrastructure.
  • Leverage existing infrastructure: Use your ISP’s DNS servers or public resolvers like Google DNS or Cloudflare DNS.

To configure forwarders, you modify your BIND configuration file, typically named.conf or a file included from it. The forwarders statement goes within the options block.

options {
    directory "/var/cache/bind";

    // ... other options ...

    recursion yes;
    forwarders {
        8.8.8.8;
        8.8.4.4;
    };

    // ... other options ...
};

In this snippet, recursion yes; is crucial because it tells BIND that it should attempt to resolve queries it doesn’t have authority for. The forwarders { ... }; block then dictates how it resolves them: by sending the query to 8.8.8.8 and 8.8.4.4. If you wanted to forward to your ISP’s DNS servers, you would replace 8.8.8.8 and 8.8.4.4 with their IP addresses.

There’s also a subtle but important distinction between forwarders and forward only. By default, if you specify forwarders, BIND will first try to forward the query. If the forwarders don’t respond (or respond with an error), BIND will fall back to performing iterative lookups itself. If you want to force BIND to only use the forwarders and never attempt iterative resolution, you add forward only; to the options block.

options {
    directory "/var/cache/bind";

    // ... other options ...

    recursion yes;
    forwarders {
        192.168.1.1; // Internal DNS server
        208.67.222.222; // OpenDNS
    };
    forward only; // BIND will NOT attempt iterative lookups if forwarders fail

    // ... other options ...
};

This forward only; directive is powerful. It ensures that your internal DNS server never directly queries the public internet’s root DNS infrastructure. If your configured forwarders are unreachable, your internal clients will not be able to resolve external hostnames. This is often desirable in locked-down environments.

When forward only; is not present, BIND’s behavior is called "forward first." It tries the forwarders, and if that fails, it resorts to iterative resolution. This gives you a fallback mechanism.

The forwarders directive can also be applied to specific views, allowing for more granular control over DNS resolution based on the client’s IP address or other criteria. This is useful in scenarios where different internal networks might have different external DNS resolution requirements.

view "internal" {
    match-clients { 192.168.0.0/16; };
    // ... view specific options ...
    forwarders {
        192.168.1.1;
    };
    recursion yes;
};

view "external" {
    match-clients { any; };
    // ... view specific options ...
    // No forwarders here, will resolve iteratively
    recursion yes;
};

In this example, clients from the 192.168.0.0/16 subnet will use 192.168.1.1 as their forwarder, while all other clients will perform iterative lookups.

The most surprising aspect of BIND’s forwarders is how they interact with dnssec-validation. If you have dnssec-validation auto; or yes; enabled and are using forward only;, your BIND server will not be able to perform DNSSEC validation for records resolved by your forwarders, unless those forwarders are themselves capable of performing and returning DNSSEC validation information (which most public resolvers do). BIND’s role becomes that of a client to the forwarder, and it trusts the answer it receives. If you need your BIND server to be the ultimate arbiter of DNSSEC integrity, you typically cannot use forward only; and must perform iterative lookups.

After configuring forwarders, remember to check your BIND configuration for syntax errors using named-checkconf and then reload or restart the BIND service for the changes to take effect.

The next thing you’ll likely encounter is configuring DNS views to further partition your DNS resolution logic.

Want structured learning?

Take the full Bind course →