How to Configure Unbound as a Local DNS Resolver with Dnssec Validation and Dns-over-tls Forwarding on Ubuntu Server
Learning how to configure Unbound as a local DNS resolver with DNSSEC validation and DNS-over-TLS forwarding on Ubuntu Server gives you full control over your DNS traffic. Instead of relying on your ISP’s resolvers, you run your own. This means faster lookups, better privacy, and cryptographic validation of DNS responses. In this tutorial, you’ll install and configure Unbound on Ubuntu Server, enable DNSSEC to catch spoofed records, and set up DNS-over-TLS forwarding to an upstream resolver like Cloudflare or Quad9. By the end, your server will resolve DNS queries locally, validate them with DNSSEC, and encrypt outbound queries so your ISP can’t snoop on them. This setup works great for home labs, VPS environments, and self-hosted infrastructure where DNS privacy matters.
Prerequisites for Configuring Unbound as a Local DNS Resolver
Before you start, make sure you have the following in place.
System requirements:
- Ubuntu Server 20.04 or 22.04 (fresh install recommended)
- Root or sudo access
- A static IP address on your server
- Basic familiarity with the Linux command line
- Port 53 available (not blocked by another DNS service)
Estimated time: 30–45 minutes.
You should also check whether systemd-resolved is running on port 53. Ubuntu enables it by default. It will conflict with Unbound. You’ll handle that in the steps below.
You don’t need prior DNS administration experience. However, understanding what DNS does will help. If you want background reading, the official Unbound documentation from ISC is a solid reference.
Make sure your system is fully updated before you begin. Run:
sudo apt update && sudo apt upgrade -y
Once your system is ready, move on to the installation steps.
How to Configure Unbound as a Local DNS Resolver on Ubuntu Server
Related tutorial: How to Configure Postfix with Dovecot Lmtp and Virtual Mailbox Domains for Multi-domain Email Hosting on Ubuntu Server
Follow these steps carefully. Each one builds on the last.
Step 1: Disable systemd-resolved
Ubuntu’s built-in stub resolver listens on 127.0.0.53:53. You need to free up port 53 for Unbound.
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
Now remove the symlink for /etc/resolv.conf and create a static one:
sudo rm /etc/resolv.conf
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf
This tells your system to use your local Unbound instance for DNS.
Step 2: Install Unbound
Install Unbound from Ubuntu’s official repositories:
sudo apt install unbound -y
After installation, check the service status:
sudo systemctl status unbound
It may show errors at this point. That’s fine. You haven’t configured it yet.
Step 3: Download the Root Hints File
Unbound needs a list of root DNS servers. Download the current root hints file:
sudo curl -o /var/lib/unbound/root.hints https://www.internic.net/domain/named.root
This file tells Unbound where to start when resolving queries from scratch.
Step 4: Create the Unbound Configuration File
Back up the default config, then create a clean one:
sudo mv /etc/unbound/unbound.conf /etc/unbound/unbound.conf.bak
sudo nano /etc/unbound/unbound.conf
Paste in the following configuration:
server:
verbosity: 1
interface: 127.0.0.1
port: 53
do-ip4: yes
do-ip6: no
do-udp: yes
do-tcp: yes
root-hints: "/var/lib/unbound/root.hints"
# DNSSEC validation
auto-trust-anchor-file: "/var/lib/unbound/root.key"
val-log-level: 2
# Privacy and security hardening
hide-identity: yes
hide-version: yes
harden-glue: yes
harden-dnssec-stripped: yes
use-caps-for-id: yes
qname-minimisation: yes
# Cache settings
cache-min-ttl: 3600
cache-max-ttl: 86400
prefetch: yes
num-threads: 2
# Access control
access-control: 127.0.0.0/8 allow
# DNS-over-TLS forwarding to Cloudflare
forward-zone:
name: "."
forward-tls-upstream: yes
forward-addr: 1.1.1.1@853#cloudflare-dns.com
forward-addr: 1.0.0.1@853#cloudflare-dns.com
Save and exit with Ctrl+O, then Ctrl+X.
This config does several things at once. It binds Unbound to localhost only. It enables DNSSEC validation using a trust anchor file. It hardens the resolver against common attacks. It also forwards all queries upstream over TLS on port 853 to Cloudflare.
If you prefer Quad9 instead of Cloudflare, replace the forward addresses with:
forward-addr: 9.9.9.9@853#dns.quad9.net
forward-addr: 149.112.112.112@853#dns.quad9.net
Step 5: Initialize the DNSSEC Trust Anchor
Unbound uses a root key file for DNSSEC. Generate it with:
sudo unbound-anchor -a /var/lib/unbound/root.key
Set the correct ownership:
sudo chown unbound:unbound /var/lib/unbound/root.key
Step 6: Validate the Configuration
Before restarting Unbound, check your config file for syntax errors:
sudo unbound-checkconf
You should see: unbound-checkconf: no errors in /etc/unbound/unbound.conf. If you see errors, double-check your indentation and syntax in the config file.
Step 7: Start and Enable Unbound
sudo systemctl restart unbound
sudo systemctl enable unbound
Check that it’s running cleanly:
sudo systemctl status unbound
Step 8: Test Your DNS Resolver
Run a quick query to confirm Unbound is working:
dig google.com @127.0.0.1
You should get a valid response with a status of NOERROR. To confirm DNSSEC is working, test a signed domain:
dig sigok.verteiltesysteme.net @127.0.0.1
Look for the ad flag in the response flags. That flag means the answer is DNSSEC-authenticated. To confirm DNSSEC is rejecting bad records, run:
dig sigfail.verteiltesysteme.net @127.0.0.1
This should return SERVFAIL. That’s the correct result. Unbound caught the invalid signature.
To verify DNS-over-TLS is actually being used, check the Unbound logs:
sudo journalctl -u unbound --since "5 minutes ago"
You should see outbound TLS connections to your upstream resolver. For more on DNSSEC standards, see the DNSSEC introduction RFC 4033 from the IETF.
Troubleshooting Common Issues with Unbound DNS Setup
Unbound won’t start after installation
Check for port conflicts first. Run sudo ss -tulnp | grep :53. If another process holds port 53, stop it before starting Unbound.
DNSSEC validation fails for all domains
Your root.key file may be outdated or missing. Re-run sudo unbound-anchor -a /var/lib/unbound/root.key and restart Unbound.
DNS queries time out
Check that your firewall allows outbound traffic on port 853. Run:
sudo ufw allow out 853/tcp
Also confirm your server can reach the upstream resolver:
curl -v https://cloudflare-dns.com
dig returns SERVFAIL for legitimate domains
Some domains don’t have DNSSEC properly configured. This isn’t a bug. If you suspect a false positive, temporarily disable DNSSEC validation by commenting out the auto-trust-anchor-file line and restarting Unbound. If the query succeeds, the domain has a broken
