BIND9 was unintentionally acting as a public recursive DNS resolver, creating a security risk. This guide shows how to safely disable recursion without breaking hosted domains.
Table of Contents
One of my production hosting servers (running Virtualmin) looked perfectly fine on the surface — domains were resolving, clients weren’t complaining, and everything seemed stable.
But during a routine check, something didn’t feel right.
The server had BIND9 installed (as expected with Virtualmin), but deeper inspection showed it was behaving as a public recursive DNS resolver. That’s not just inefficient — it’s a serious security issue.
This kind of problem is common on VPS setups where:
- BIND is installed automatically
- Default configs are left unchanged
- DNS roles (authoritative vs recursive) are not separated
If left unfixed, your server can be abused for DNS amplification attacks or even get blacklisted.
This is a classic case under SSL & DNS Problems.
Problem Summary
Here’s what I observed:
- BIND9 was listening on public IP:
192.0.x.x:53
- No recursion restrictions in config
- Server responded to external recursive queries
- System DNS already moved to Unbound (so BIND recursion was unnecessary)
Key symptom
From an external server:
dig @192.0.x.x google.com
Initial behavior (before fix):
- Would resolve external domains
- Indicates open resolver
At this point, it was clear:
BIND was doing both authoritative DNS + recursion, which is dangerous in production.
Since Unbound was already handling system DNS, the logical next step was to remove recursion from BIND completely.
Confirm BIND is using default recursion behavior
First, check if recursion is explicitly configured:
grep -E "recursion|allow-recursion|allow-query-cache" /etc/bind/named.conf.options
In this case, there was no output.
That means BIND is using defaults:
recursion yes;
allow-recursion { any; };
Which effectively makes your server a public DNS resolver.
Understand the risk (before changing anything)
Important: This was a production server with active DNS zones.
So we could NOT:
- Disable public access to port 53
- Restrict queries to localhost
- Break authoritative DNS
We only needed to:
Disable recursion while keeping DNS zones working
Disable recursion safely
Unbound Should Be Enabled First
If you disable BIND recursion without another resolver, your system DNS will break.
Edit:
nano /etc/bind/named.conf.options
Update the options block:
options {
directory "/var/cache/bind";
recursion no;
dnssec-validation auto;
listen-on-v6 { any; };
};
That single line:
recursion no;
completely removes resolver capability without touching authoritative DNS.
Restart BIND
systemctl restart bind9
Why this works
After this change:
- Your domains → still resolve (authoritative)
- External recursion → blocked
- Server is no longer an open resolver
Since Unbound handles recursion internally, nothing else is affected.
Verification
This is the most important part.
Test 1 — Recursion should fail
From another server:
dig @192.0.x.x google.com
Expected output:
status: REFUSED
WARNING: recursion requested but not available

This confirms:
- Server received request
- Refused recursion properly
Test 2 — Your domains should still resolve
dig @192.0.x.x yourdomain.com
Expected:
status: NOERROR
flags: qr aa rd
- aa = authoritative answer
- Domain resolves correctly
Common Mistakes / Edge Cases
- Blocking port 53 entirely
- Binding only to localhost
- Mixing recursion restrictions incorrectly
- Forgetting existing resolver (Unbound)
Need Help Fixing Your VPS?
If you’re stuck with server issues and need a reliable fix, I troubleshoot real VPS problems daily — from Nginx errors and SMTP failures to DNS and performance issues.
Instead of guessing, get a proven fix based on real experience.
- Fix Nginx, Apache, and 502/504 errors
- Resolve SMTP, email, and SES issues
- Debug DNS, SSL, and domain problems
- Optimize performance (CPU, RAM, slow sites)
Conclusion
This issue wasn’t obvious — everything “worked” at first glance.
But under the hood:
- BIND was acting as an open resolver
- The server was exposed to abuse risks
The fix was simple but critical: Disable recursion in BIND and let a dedicated resolver (Unbound) handle DNS lookups.
Now the setup is clean:
- BIND → authoritative DNS only
- Unbound → recursive DNS
This is how production-grade DNS should be structured.



