| |

LFCE 40 ๐Ÿง DNS Server โ€” unbound Basics

โฑ๏ธ Estimated read: 10 min | |

Unbound is a validating, recursive, and caching DNS resolver. It is not an authoritative server like BIND9, and it is not a combined forwarder/DHCP daemon like dnsmasq. It performs one function and performs it thoroughly: it takes a query from a client, walks the DNS hierarchy from the root down using its built-in root hints, validates the answer with DNSSEC, caches the result according to its TTL, and returns the answer . The previous chapters covered BIND9’s authoritative and resolver roles and dnsmasq’s small-network forwarding. Unbound occupies a different position: it is the dedicated, security-focused resolver that is often deployed on a local network or a single host to replace the ISP’s resolver.

For the LFCE candidate, Unbound represents the modern resolver implementation. It is designed to be fast and lean, it supports DNS-over-TLS and DNS-over-HTTPS, and its configuration is intentionally minimal. A working resolver can be configured in a few lines, and the default behavior is to listen only on localhost, which is the safe default that prevents it from becoming an open resolver .

Key point: Unbound is a recursive resolver, not a forwarder by default. It queries the root servers directly using its built-in root hints. To use upstream forwarders instead, a forward-zone must be configured explicitly. The default access control refuses queries from everything except localhost, and this must be changed deliberately if the resolver is to serve a local network .


Why Unbound exists

The dedicated-resolver problem.

BIND9 can act as a resolver, but it also carries the full weight of authoritative zone hosting. dnsmasq can forward and cache, but it is designed as a small-network DHCP companion. Unbound is built for the resolver role alone. It does not host zones, it does not assign addresses, and it does not attempt to be a general-purpose DNS toolkit. This focus allows it to implement the resolver function with a smaller attack surface and a simpler configuration .

The DNSSEC-validation problem.

DNSSEC validation requires the resolver to fetch and verify cryptographic signatures for every answer. Unbound implements this as a core feature, not an add-on. It maintains a chain of trust from the root’s trust anchor down to the queried name, and it returns a SERVFAIL if the validation fails . A resolver that does not validate DNSSEC is vulnerable to cache poisoning; Unbound’s validation is the defense against that class of attack.

The privacy problem.

Using an ISP’s resolver exposes every domain the local network queries to the ISP. Unbound, running locally or on a local network server, performs the recursive lookups itself. The root servers and authoritative servers see queries from the Unbound host, not from every individual client. Combined with DNS-over-TLS for the outbound queries, this reduces the exposure of the local network’s browsing patterns .


a. Installation and the default configuration

Unbound is packaged for every major distribution. On Debian and Ubuntu, the package is unbound. The service is controlled through systemctl as unbound. The configuration file is /etc/unbound/unbound.conf, and it uses a YAML-like syntax with server: blocks and indented directives .

# Debian / Ubuntu
sudo apt update
sudo apt install unbound

# RHEL / Fedora
sudo dnf install unbound

# Validate the configuration syntax
unbound-checkconf
# Output: unbound-checkconf: no errors in /etc/unbound/unbound.conf

The unbound-checkconf command is the equivalent of named-checkconf. It parses the configuration and reports any syntax errors before the service is started. It is mandatory after every change .

The default configuration listens only on 127.0.0.1 and ::1, and the default access control refuses queries from any other address. This is the safe default: a freshly installed Unbound serves the local host and nothing else. To serve a local network, the interface and access-control directives must be added explicitly .

# /etc/unbound/unbound.conf
server:
    interface: 127.0.0.1
    interface: 192.168.1.10
    access-control: 127.0.0.0/8 allow
    access-control: 192.168.1.0/24 allow

The interface directive tells Unbound which addresses to listen on. The access-control directive tells it which clients are allowed to query. Without the access-control entry for the local subnet, clients on 192.168.1.0/24 receive a REFUSED response .


b. Recursion versus forwarding

By default, Unbound is a recursive resolver. It uses its built-in root hints to query the root servers and walk the hierarchy. This requires outbound access to the root servers and to authoritative servers on port 53. If the network restricts outbound DNS traffic, or if a local upstream resolver is preferred for speed, a forward-zone can be configured.

# /etc/unbound/unbound.conf
forward-zone:
    name: "."
    forward-addr: 8.8.8.8
    forward-addr: 1.1.1.1

The name: "." means the forward zone applies to all queries. The forward-addr entries specify the upstream resolvers. When a forward zone is configured, Unbound sends the query to the forwarder instead of performing the recursive lookup itself. The answer is still cached and returned to the client .

The choice between recursion and forwarding is a network policy decision. Recursion gives Unbound full control over the resolution path and avoids trusting an upstream resolver. Forwarding is faster on a local network if the upstream is close, and it is required when outbound port 53 is blocked. Unbound supports both simultaneously: a forward-zone for a specific domain can coexist with default recursion for everything else.


c. DNSSEC validation and the root trust anchor

Unbound validates DNSSEC by default. It uses a built-in root trust anchor, which is the public key for the root zone. The validation process checks the chain of signatures from the root down to the queried name. If any signature is invalid or missing, Unbound returns SERVFAIL instead of the answer .

# Check the DNSSEC validation status
dig @localhost dnssec-failed.org
# Output: status: SERVFAIL
# The domain is intentionally broken for DNSSEC testing

The dnssec-failed.org domain is maintained specifically for testing DNSSEC validation. A resolver that validates DNSSEC returns SERVFAIL for it. A resolver that does not validate returns the A record. This is the standard test for confirming that validation is active .

The root trust anchor is maintained by the unbound-anchor utility, which is run automatically by the package’s systemd service or by a cron job. It fetches the current root trust anchor from IANA and installs it in /var/lib/unbound/root.key. If the anchor is missing or stale, validation fails for every domain, and the resolver appears to be broken. The unbound-anchor command can be run manually to repair it .


Complete Example Session

# ============================================
# PART 1: INSTALL UNBOUND
# ============================================
sudo apt install unbound

# ============================================
# PART 2: VALIDATE THE DEFAULT CONFIGURATION
# ============================================
sudo unbound-checkconf
# Output: no errors in /etc/unbound/unbound.conf

# ============================================
# PART 3: CONFIGURE FOR A LOCAL NETWORK
# ============================================
sudo tee -a /etc/unbound/unbound.conf > /dev/null <<'EOF'
server:
    interface: 127.0.0.1
    interface: 192.168.1.10
    access-control: 127.0.0.0/8 allow
    access-control: 192.168.1.0/24 allow
EOF

# ============================================
# PART 4: VALIDATE AND RESTART
# ============================================
sudo unbound-checkconf
sudo systemctl restart unbound
sudo systemctl status unbound

# ============================================
# PART 5: TEST LOCAL RESOLUTION
# ============================================
dig @192.168.1.10 example.com
# Output: an answer with the "ra" flag (recursion available)

# ============================================
# PART 6: TEST DNSSEC VALIDATION
# ============================================
dig @192.168.1.10 dnssec-failed.org
# Output: status: SERVFAIL
# This confirms validation is active

# ============================================
# PART 7: CONFIGURE FORWARDING (OPTIONAL)
# ============================================
sudo tee -a /etc/unbound/unbound.conf > /dev/null <<'EOF'
forward-zone:
    name: "."
    forward-addr: 8.8.8.8
    forward-addr: 1.1.1.1
EOF
sudo unbound-checkconf
sudo systemctl restart unbound

# ============================================
# PART 8: TEST FORWARDING
# ============================================
dig @192.168.1.10 example.com
# The answer now comes from the forwarder instead of recursion

# ============================================
# PART 9: CHECK THE ROOT TRUST ANCHOR
# ============================================
sudo unbound-anchor -v
# Confirms the root trust anchor is present and valid

# ============================================
# PART 10: CONFIGURE THE LOCAL HOST TO USE UNBOUND
# ============================================
# /etc/resolv.conf:
# nameserver 127.0.0.1

The ten parts demonstrate the complete Unbound setup: installation, validation, local network configuration, DNSSEC testing, optional forwarding, and trust anchor verification. The critical distinctions are Part 3 (the default refuses local network clients) and Part 6 (the SERVFAIL for dnssec-failed.org confirms validation).


Quick Reference

Unbound vs BIND9 vs dnsmasq

PropertyUnboundBIND9dnsmasq
RoleValidating resolverAuthoritative + resolverForwarder + DHCP
DNSSEC validationDefaultOptionalNo
Root recursionDefaultOptionalNo (forwards)
Authoritative zonesNoYesNo
DHCPNoNoYes
Configuration/etc/unbound/unbound.confMultiple files/etc/dnsmasq.conf

Key Configuration Directives

DirectivePurpose
interface:Listen address
access-control:Client subnet and action (allow, refuse, deny)
forward-zone:Upstream resolvers for a domain
forward-addr:Upstream resolver address
root-hints:Path to root hints file
do-ip4: / do-ip6:Enable IPv4 / IPv6

Validation and Control Commands

CommandPurpose
unbound-checkconfValidate configuration syntax
unbound-anchorUpdate the root trust anchor
unbound-controlRemote control (status, reload)
dig @server dnssec-failed.orgTest DNSSEC validation

Best Practices

โœ… Do This:

# Validate before restarting
unbound-checkconf                                             # โœ…

# Restrict access to the local network
access-control: 192.168.1.0/24 allow                          # โœ…

# Test DNSSEC validation
dig @localhost dnssec-failed.org                              # โœ…

# Keep the root trust anchor updated
unbound-anchor                                                # โœ…

# Use forward-zone only when outbound DNS is restricted
forward-zone: name: "."; forward-addr: 8.8.8.8                # โœ…

# Set the local host to use Unbound
nameserver 127.0.0.1                                          # โœ…

โŒ Don’t Do This:

# Leave access-control as default when serving a network
# The default refuses everything except localhost               # โŒ

# Listen on 0.0.0.0 without access-control
interface: 0.0.0.0    # Open resolver if access-control is allow all # โŒ

# Assume forwarding is the default
# Unbound recurses from the root by default                     # โŒ

# Ignore the root trust anchor
# Stale anchor causes SERVFAIL for every domain                 # โŒ

# Use Unbound for authoritative zone hosting
# Unbound is a resolver, not an authoritative server            # โŒ

Common Pitfalls

PitfallWhy It HappensFix
Local network clients get REFUSEDaccess-control not configured for the subnetAdd access-control: 192.168.1.0/24 allow
Every domain returns SERVFAILRoot trust anchor missing or staleRun unbound-anchor
Queries fail after configuring forward-zoneForwarder unreachableVerify forwarder IP and port 53 access
Unbound does not startPort 53 occupied by systemd-resolvedDisable or reconfigure systemd-resolved
DNSSEC test returns answer instead of SERVFAILValidation disabledCheck auto-trust-anchor-file and module-config

Real-World Examples

1. Install Unbound

sudo apt install unbound

2. Validate configuration

unbound-checkconf

3. Listen on local network

interface: 192.168.1.10

4. Allow local subnet

access-control: 192.168.1.0/24 allow

5. Test recursion

dig @192.168.1.10 example.com

6. Test DNSSEC validation

dig @192.168.1.10 dnssec-failed.org

7. Configure forwarder

forward-zone: name: "."; forward-addr: 8.8.8.8

8. Update root trust anchor

unbound-anchor

9. Set local resolver

echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf

10. Check service status

systemctl status unbound

Visual

Unbound as a Validating Resolver

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  UNBOUND WALKS THE HIERARCHY AND VALIDATES EVERY ANSWER      โ”‚
โ”‚                                                              โ”‚
โ”‚  Client โ”€โ”€โ–ถ Unbound โ”€โ”€โ–ถ Root โ”€โ”€โ–ถ TLD โ”€โ”€โ–ถ Authoritative       โ”‚
โ”‚                โ”‚                                             โ”‚
โ”‚                โ”œโ”€โ”€ DNSSEC validation at each step            โ”‚
โ”‚                โ”œโ”€โ”€ Cache (TTL-based)                         โ”‚
โ”‚                โ””โ”€โ”€ Returns answer or SERVFAIL                โ”‚
โ”‚                                                              โ”‚
โ”‚  Default: recursion from root hints.                         โ”‚
โ”‚  Optional: forward-zone for upstream resolvers.              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Access Control Default

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  DEFAULT ACCESS IS LOCALHOST ONLY                            โ”‚
โ”‚                                                              โ”‚
โ”‚  Fresh install:                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ interface: 127.0.0.1, ::1                              โ”‚  โ”‚
โ”‚  โ”‚ access-control: 127.0.0.0/8 allow                      โ”‚  โ”‚
โ”‚  โ”‚ access-control: ::1 allow                              โ”‚  โ”‚
โ”‚  โ”‚                                                        โ”‚  โ”‚
โ”‚  โ”‚ Everything else: refused                               โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                                              โ”‚
โ”‚  To serve a network:                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚ interface: 192.168.1.10                                โ”‚  โ”‚
โ”‚  โ”‚ access-control: 192.168.1.0/24 allow                   โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

DNSSEC Validation Test

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  dnssec-failed.org CONFIRMS VALIDATION IS ACTIVE             โ”‚
โ”‚                                                              โ”‚
โ”‚  dig @resolver dnssec-failed.org                              โ”‚
โ”‚                                                              โ”‚
โ”‚  Validating resolver:                                        โ”‚
โ”‚  โ””โ”€โ”€ status: SERVFAIL                                        โ”‚
โ”‚      (signature is intentionally broken)                     โ”‚
โ”‚                                                              โ”‚
โ”‚  Non-validating resolver:                                    โ”‚
โ”‚  โ””โ”€โ”€ status: NOERROR                                         โ”‚
โ”‚      (returns the A record)                                  โ”‚
โ”‚                                                              โ”‚
โ”‚  If SERVFAIL is returned, validation is working.             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
SoftwareUnbound (NLnet Labs)
RoleValidating, recursive, caching resolver
Default behaviorRecursion from root hints
Configuration file/etc/unbound/unbound.conf
Default listening127.0.0.1 and ::1 only
Default access controlLocalhost only
DNSSEC validationEnabled by default
Trust anchor/var/lib/unbound/root.key
Forwardingforward-zone with name: "."
Validation commandunbound-checkconf
DNSSEC testdig @server dnssec-failed.org (SERVFAIL = working)

Key takeaways:

  • Unbound is a resolver, not an authoritative server. It recurses from the root, validates DNSSEC, and caches answers. It does not host zones or serve authoritative data .
  • The default is localhost only. A fresh installation serves 127.0.0.1 and refuses everything else. Serving a local network requires adding interface and access-control directives .
  • DNSSEC validation is on by default. The dnssec-failed.org test returns SERVFAIL on a validating resolver, confirming that the chain of trust is being checked .
  • The root trust anchor must be current. If the anchor is missing or stale, every query returns SERVFAIL. unbound-anchor updates it, and the package’s systemd service usually runs it automatically .
  • Forwarding is optional and explicit. Unbound recurses from the root by default. A forward-zone with name: "." redirects queries to upstream resolvers, which is useful when outbound port 53 is restricted .
  • unbound-checkconf validates the configuration. It catches syntax errors before the service is restarted, preventing outages caused by a missing colon or an invalid directive .

Remember: Unbound is the dedicated resolver. It starts with safe defaultsโ€”localhost only, DNSSEC validation on, recursion from the root. Serving a network requires explicit interface and access-control entries. The dnssec-failed.org test confirms that validation is working. The root trust anchor must be current. Forwarding is an option, not the default. For a resolver that prioritizes security and correctness over authoritative hosting, Unbound is the tool.


Was this helpful?


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!