How-To

DNS Tunneling Detection Not Working in pfSense or Pi-hole? Troubleshooting Guide (2026)

22 min read

You enabled Suricata, subscribed to a blocklist, and pointed your network at Pi-hole. You expected an early-warning system for DNS tunneling. Instead you got one of two things: dead silence, or an alert log so noisy you gave up reading it by day two. That’s normal. It doesn’t mean you broke something. The defaults in pfSense and Pi-hole are tuned for “install and it works,” not for catching a device beaconing out over TXT records every 30 seconds.

Getting from default install to something that actually catches bad traffic takes real tuning. This guide walks through that tuning: alerts that never fire, alerts that fire on everything, blocklists that miss the domains that matter, and DNS-over-HTTPS quietly routing around your entire setup. It assumes pfSense and Pi-hole are already running. If you haven’t done that base install yet, go do it first. This is a tuning guide, not a setup guide, and it won’t walk you through running actual tunneling tools like iodine or dnscat2.

Quick Diagnosis

Run through this checklist before you chase individual symptoms. It catches the root cause of most reported issues in under ten minutes.

  • Confirm Pi-hole is actually the DNS resolver for your clients. Check DHCP settings on pfSense (Services > DHCP Server). The DNS server handed to clients should be Pi-hole’s LAN IP, not pfSense’s own address, not an upstream ISP resolver.
  • Confirm Suricata or Snort is bound to the LAN interface, and not only WAN. Tunneling traffic starts from internal clients. The IDS/IPS needs visibility into LAN-to-WAN DNS queries, and inbound WAN traffic alone is not enough.
  • Check that DNS-tunneling-relevant rule categories are actually enabled. pfSense ships the IDS/IPS engine, but no rules are enabled out of the box. You have to add a rule source and turn on categories yourself.
  • Look at Pi-hole’s Query Log for record types. If every query shows type A or AAAA, and you never see TXT, NULL, or long CNAME chains. Either your network is genuinely clean or something is bypassing Pi-hole entirely (see Issue 4 below).
  • Check system resource usage on pfSense under Status > Monitoring after enabling Suricata/Snort. CPU pegged near 100% on a low-power box explains both dropped alerts and network slowdowns.
  • Verify no client is using DNS-over-HTTPS (DoH) or DNS-over-TLS (DoT) directly to an external resolver. This is the single biggest reason DNS tunneling detection appears to “not work” even when it’s set up correctly.

Signs Your DNS Traffic May Include Tunneling

Tunneling tools encode data inside DNS queries and responses. The traffic patterns look different from normal browsing even before you dig into payloads. Keep this table handy while reviewing logs:

IndicatorNormal DNSPossible Tunneling
Query name lengthUnder ~50 characters60+ characters, often near the 253-character DNS limit
Subdomain randomness (entropy)Readable words (www, mail, cdn)Long strings of random-looking letters/numbers (base32/base64-encoded data)
Record types usedMostly A, AAAA, CNAMEHeavy use of TXT, NULL, or unusually large CNAME chains
Query frequency to one domainA handful of lookups per sessionDozens to hundreds of queries per minute to the same base domain
Domain age/reputationEstablished, widely resolved domainsFreshly registered or rarely-seen domains
Response sizeSmall, consistentTXT responses near the 255-byte string limit, repeated

None of these alone proves tunneling is happening. CDNs and plenty of legitimate SaaS tools use TXT records and odd-looking subdomains too: think SPF/DKIM checks or service discovery. That’s why every fix below focuses on tuning detection instead of blocking every anomaly on sight.

Common Issues

Issue 1: Suricata/Snort Isn’t Generating Any DNS Tunneling Alerts

Symptoms:

  • The Alerts tab under Suricata/Snort is empty or shows only unrelated traffic (port scans, ad-tracker blocks)
  • You’ve had the package installed for days with zero DNS-related hits
  • Manually generating a suspicious-looking query (see the verification test below) produces no alert at all

Cause: pfSense’s Suricata and Snort packages install the detection engine, but ship with zero signatures enabled. Nothing happens until you add a rule source, most people use the free Emerging Threats Open ruleset, and turn on the categories that cover DNS anomalies and known tunneling tool signatures. Depending on the ruleset provider, those usually live under policy, malware, and DNS-specific categories.

Fix:

  • Go to Services > Suricata > Global Settings. Under Rule Update Settings, make sure at least one rule source is enabled. For the free tier, ET Open is the standard choice. Click Update Rules and confirm the last update timestamp changes.
  • Go to Services > Suricata > Interfaces, edit your LAN interface, and confirm it’s enabled. Set Block Offenders to match your mode: leave it off for now and start in alert-only/legacy mode.
pfSense Suricata Interfaces tab showing LAN interface enabled and assigned
  • Click the Categories icon (wrench) next to the LAN interface. Enable at least these categories, which cover the bulk of DNS-tunneling-relevant signatures:
    • dns-events.rules (or equivalent DNS-specific category depending on ruleset)
    • policy-events.rules / policy category
    • malware-events.rules / malware-C2 category
  • Save, then click Force Update on the interface to apply the new category selection.
pfSense Suricata rule categories page with DNS and policy categories checked

Verify: Under Services > Suricata > Interfaces, the LAN row should show a green “running” status with a non-zero rule count. Generate a controlled test query (Issue 8 below) and confirm an entry appears in the Alerts tab within a minute or two.

Issue 2: Suricata/Snort Alerts Are Flooding In, Mostly False Positives

Symptoms:

  • Dozens or hundreds of DNS-related alerts per hour
  • Alert descriptions reference legitimate services: CDN telemetry, antivirus cloud lookups, Windows Update, cloud sync clients (OneDrive, Dropbox)
  • You’ve started ignoring the alert log entirely because it’s too noisy to be useful

Cause: Broad rule categories catch a lot more than tunneling tools. Any service that makes frequent DNS queries, uses TXT records for service discovery, or resolves odd-looking subdomains can trip a generic “DNS anomaly” signature without doing anything wrong. Plenty of CDNs randomize edge-node hostnames for entirely legitimate reasons.

Fix:

  • Sort the Alerts tab by Description to group repeated hits together.
  • For alerts you’ve confirmed are legitimate, check the destination IP/domain against known services. Right-click the entry and choose Suppress this SID/Source combination rather than disabling the whole category. This keeps the signature active for other sources.
  • If an entire category is too noisy for your environment, disable just that category rather than turning off Suricata altogether. It’s better to lose one signature type than to stop watching DNS traffic completely.
  • Consider running in alert-only (IDS) mode for the first 1–2 weeks before flipping any category to Block Offenders (IPS mode). This gives you a baseline of what’s normal on your network before you start dropping traffic automatically.
pfSense Suricata alerts log showing timestamp, source IP, and signature description columns

Verify: After a few days of tuning, alert volume should drop to a level you can actually review, ideally single digits per day outside of active incidents. If you’re still seeing 50+ alerts/hour after suppressing known-good sources, the category is probably too broad for your traffic. Keep it in alert-only mode rather than IPS mode.

Tip: Keep a running list of suppressed SIDs with a one-line note on why. Six months from now you won’t remember that SID 2024897 was just your Synology’s cloud sync client talking to itself.

Issue 3: pfSense Slows Down or Drops Packets After Enabling Suricata/Snort

Symptoms:

  • Web browsing feels sluggish network-wide right after enabling the IDS/IPS package
  • Status > Monitoring shows CPU pegged near 100% on the pfSense box
  • Ping times to the LAN gateway spike or become inconsistent

Cause: Deep packet inspection eats CPU and RAM. It’s especially rough on lower-power appliances, such as small-form-factor boxes with 2–4 cores or entry-level Netgate hardware, once you’re inspecting real LAN traffic volume instead of just WAN.

Fix:

  • Only run Suricata/Snort on interfaces that need it; for DNS tunneling detection, that’s LAN. Don’t enable it on every interface by default.
  • Start in legacy/alert-only mode, not inline IPS mode. Inline blocking adds latency because every packet has to be inspected before it’s forwarded. Alert-only mode inspects a copy of the traffic instead.
  • Disable rule categories you don’t need. A general home network doesn’t need every IoT-exploit or industrial-protocol category running. Every enabled category adds inspection overhead.
  • Check Interfaces > Assigned Interface Hardware Offloading settings. Suricata/Snort need checksum offloading and other NIC offloads disabled on the monitored interface. pfSense handles this automatically when you enable the package, but it’s worth confirming under System > Advanced > Networking if performance doesn’t improve.
  • If you’re on hardware with fewer than 4 CPU cores and less than 4 GB RAM, treat that as a hard ceiling. Suricata with a full ET Open ruleset on a busy LAN can outstrip that hardware no matter how you tune it.

Verify: Watch Status > Monitoring > CPU Usage for 24 hours under normal load. Sustained usage should stay well under 80%. If it’s pegged constantly, trim rule categories further or plan a hardware upgrade before relying on IPS (blocking) mode.

Issue 4: Pi-hole’s Query Log Shows Nothing Unusual, But You Suspect Tunneling Anyway

Symptoms:

  • A device is behaving oddly (high outbound bandwidth, unexpected battery drain, unfamiliar background processes) but Pi-hole’s log looks completely normal
  • Total query counts for that device seem low compared to its actual network activity
  • Suricata also shows nothing on the same device

Cause: This is almost always DNS-over-HTTPS (DoH) or DNS-over-TLS (DoT) bypass. If a device or app resolves DNS directly to an external encrypted resolver, such as Cloudflare’s 1.1.1.1, Google’s 8.8.8.8, or a resolver baked into browsers like Firefox’s built-in DoH, it never touches Pi-hole or Suricata’s plain port-53 inspection at all. Browsers increasingly ship DoH enabled by default. Malware authors know it’s an easy way around DNS-based monitoring too.

Fix:

  • Force all DNS through Pi-hole at the firewall level. On pfSense, go to Firewall > NAT > Port Forward and add a rule redirecting all outbound port 53 (TCP/UDP) traffic from the LAN, except from Pi-hole itself, to Pi-hole’s IP. This catches devices with hardcoded DNS servers.
  • Block known DoH endpoints outright. Create a pfSense Alias (Firewall > Aliases) with IPs for major public DoH resolvers. Add a Firewall > Rules entry on LAN blocking outbound TCP 443 to that alias. You may need exceptions for legitimate services you intentionally use DoH for.
  • Alternatively, install pfBlockerNG-devel and subscribe to a DoH/DoT provider IP feed. These are maintained lists built for this exact purpose, and easier to keep current than a manual alias.
  • On managed devices, disable browser-level DoH via policy: Group Policy on Windows, about:config network.trr.mode on Firefox, or MDM profiles on macOS/iOS. This makes browsers respect your network’s resolver instead of overriding it.

Verify: After applying the redirect rule, check Pi-hole’s Query Log again. You should see a jump in total queries as previously-bypassing devices start showing up. Confirm with dig:

dig example.com @1.1.1.1

If the pfSense port-forward rule is working, this query still resolves, but it’s transparently redirected through Pi-hole instead of reaching Cloudflare directly. Check Pi-hole’s Query Log for a matching entry at the same timestamp.

Issue 5: Unbound Rate Limiting Isn’t Throttling High-Frequency Queries

Symptoms:

  • A device sending hundreds of queries per minute to one domain isn’t being slowed down or flagged
  • You’ve added rate-limiting text under DNS Resolver custom options but nothing changed
  • No errors appear, but query volume graphs in Pi-hole still show the spike unaffected

Cause: Unbound’s rate-limiting directives have to sit inside the correct server: block. pfSense’s Custom options box under DNS Resolver expects exact YAML-style indentation. Paste the directives without the server: header, or mix tabs and spaces, and Unbound silently ignores the whole block on reload: no error, no warning, just nothing happening.

Fix:

  • Go to Services > DNS Resolver, scroll to Custom options, and enter:
server:
    ip-ratelimit: 1000
    ip-ratelimit-slabs: 4
    ratelimit: 1000
    ratelimit-slabs: 4

ip-ratelimit caps queries per second per client IP. This is the setting that catches a single compromised host hammering DNS. ratelimit caps queries per second per domain, which catches tunneling traffic that fans out across many client-facing requests toward one C2 domain. Both use slabs for internal locking performance and should generally match. 4 is a safe default for most home/small-office hardware.

pfSense DNS Resolver settings page with the Custom options text box showing rate-limiting directives
  • Save and apply. pfSense reloads Unbound automatically. You can confirm the reload happened under Status > System Logs > DNS Resolver, which logs a restart event with no syntax errors.
  • If you still see no effect, check for a duplicate server: block elsewhere in the custom options. Unbound only honors the first one it parses correctly. A second block later in the same text box causes a silent conflict.

Verify: Check the DNS Resolver log for rate-limit drop messages after the change:

grep -i ratelimit /var/log/resolver.log

Expected output once a client exceeds the threshold:

info: ip ratelimit exceeded 192.168.1.55

If you never see this line, even under a deliberately high query load during your verification test (Issue 8), the values may be set too high for your test. Temporarily lower ratelimit to something small, like 20, to confirm the mechanism works. Then raise it back to a realistic production value.

Issue 6: Pi-hole Blocklists Aren’t Catching Known Tunneling or C2 Domains

Symptoms:

  • A domain you know is associated with a tunneling tool or malware C2 infrastructure still resolves through Pi-hole
  • Pi-hole’s Query Log shows the domain as allowed, not blocked
  • Adding the domain manually works, but you’re worried about the domains you don’t know about yet

Cause: Pi-hole ships with a minimal default blocklist aimed at ads, not threat intelligence. A lot of DNS tunneling tools and malware families use freshly-registered or algorithmically-generated domains (DGA) that simply haven’t been added to any public blocklist yet. Blocklists can only block what they already know about.

Fix:

  • Go to Group Management > Adlists and add threat-intelligence-focused lists alongside your ad-blocking lists. Good categories include malware-domain lists and C2 IOC feeds maintained by security research groups. Check current recommendations on the Pi-hole documentation, since list URLs change over time.
Pi-hole Group Management Adlists page with the add-new-adlist input field and a list of active subscriptions
  • After adding lists, go to Tools > Update Gravity to pull the new domains into Pi-hole’s blocking database.
  • Accept that blocklists are reactive by nature. Pair them with the behavioral detection covered in Issues 1–2 and 5. Suricata signatures and rate limiting catch new tunneling activity based on behavior, not domain reputation; that’s exactly the gap blocklists can’t close.
  • For domains you strongly suspect but that aren’t confirmed malicious, use Pi-hole’s regex filtering under Group Management > Domains. This catches pattern families rather than one-off exact matches: for example, blocking excessively long random-looking subdomains under a specific parent domain you’re monitoring.
Pi-hole Domains management page showing the regex toggle when adding a new domain rule

Verify: After updating gravity, re-check the Query Log for the previously-allowed domain. It should now show as Blocked (blocklist) or Blocked (regex). You can also check from the command line on the Pi-hole host:

pihole -q suspicious-domain.example

Expected output when the domain is now covered by an adlist:

[i] suspicious-domain.example is in the “malware-domains” adlist

Issue 7: Manually Reviewing Pi-hole’s Query Log Is Too Slow to Catch Anything

Symptoms:

  • You’ve tried scrolling through the Query Log looking for anomalies and gave up after a few hundred entries
  • A slow, “low-and-slow” tunneling pattern (a handful of queries every few minutes over days) never stands out in a daily log review
  • You suspect something is wrong but can’t pinpoint which domain or client

Cause: Raw query log review doesn’t scale. Slow exfiltration is deliberately designed to blend into normal traffic volume on a per-minute basis. A handful of queries every few minutes over several days looks like nothing while you’re scrolling. The signal only becomes obvious once you zoom out over a longer window.

Fix:

  • Use Long Term Data graphs (under the main dashboard’s query-over-time chart) rather than the raw log to spot volume anomalies across days or weeks. A domain with a steadily climbing query count, even at low absolute numbers, stands out far more clearly here than in a scrolling log.
Pi-hole Long Term Data query-over-time graph showing volume trends across a multi-day window
  • On the dashboard, check the Query Types pie chart periodically. A sudden appearance of TXT or NULL queries where you previously saw almost none is one of the clearest tunneling indicators available without deep packet inspection.
Pi-hole admin dashboard showing Total Queries and Query Types breakdown widgets
  • Use the Query Log’s filter/search bar to isolate one suspicious domain at a time rather than reading chronologically. Filter by domain and by query type (TXT, NULL) to see the full pattern for that domain specifically.
Pi-hole Query Log page with the search/filter bar and query type column visible
  • For ongoing monitoring rather than one-time review, query Pi-hole’s FTL database directly and sort by query count to find outlier domains:
sqlite3 /etc/pihole/pihole-FTL.db "SELECT domain, COUNT(*) as cnt FROM queries WHERE type=16 GROUP BY domain ORDER BY cnt DESC LIMIT 20;"

(type=16 filters for TXT records specifically. This pulls the top 20 domains by TXT query volume, exactly the pattern tunneling tools produce.)

Verify: Run the query above weekly and watch for new entries appearing near the top of the list. A domain you don’t recognize jumping into the top 20 for TXT queries warrants a manual look at the Query Log filtered to that domain.

Issue 8: Your Test to Verify Detection Doesn’t Trigger Any Alerts

Symptoms:

  • You’ve enabled everything above but have no confidence it actually works because nothing has triggered it yet
  • You want to confirm the pipeline before relying on it during a real incident

Cause: Without a controlled, safe way to generate DNS traffic that resembles tunneling patterns (long, high-entropy, unusual record types), you have no way to confirm your rules and rate limits actually catch anything. You’d find that out during a real incident instead. That’s the worst possible time to learn it.

Fix: Use the standard dig utility (a completely legitimate DNS lookup tool, not a tunneling tool) against a domain you control. This generates a query that matches the shape of tunneling traffic, without any actual data exfiltration or C2 behavior involved.

  • Query a TXT record with a long, random-looking subdomain under a domain you own:
dig txt aXb9k2mZq7wPn4rT8vLc1sYd6fGh3jKm.example.com
  • Repeat the same query 30–40 times in a short burst to simulate volume:
for i in $(seq 1 40); do dig txt aXb9k2mZq7wPn4rT8vLc1sYd6fGh3jKm.example.com > /dev/null; done
  • Check pfSense’s Suricata/Snort Alerts tab. You should see one or more alerts referencing DNS query length, TXT record volume, or policy category signatures within a minute.
  • Check Pi-hole’s Query Log filtered to example.com. You should see the burst of TXT queries logged with timestamps matching your test.
  • Check the Unbound resolver log for rate-limit messages if you lowered the threshold for testing, as described in Issue 5.

Verify: All three signals (Suricata alert, Pi-hole log entry, and, if configured, an Unbound rate-limit line) should appear for the same test window. If one is missing, that’s the component still needing attention. Go back to the matching issue above.

Important: Only run this test against a domain you own and control. Never run it against third-party domains, and don’t use this pattern to move real data. The goal is a shape that resembles tunneling for detection testing, nothing more.

Error Messages Table

Error / Log MessageWhere You’ll See ItWhat It MeansFix
No rules loaded / rule count 0Suricata Interfaces tabNo rule source enabled or categories not selectedAdd ET Open rule source, enable categories, force update (Issue 1)
info: ip ratelimit exceeded X.X.X.X/var/log/resolver.logUnbound rate limiting is working and dropped queries from that clientExpected behavior; confirms Issue 5 fix is active
Alert flood with generic descriptions like “Possible DNS anomaly”Suricata Alerts tabBroad category matching legitimate trafficSuppress known-good SIDs, tune categories (Issue 2)
[i] domain is not in any adlistpihole -q outputDomain isn’t covered by any subscribed blocklistAdd threat-intel adlists, use regex rules (Issue 6)
High CPU / interface flapping under Status > MonitoringpfSense dashboardIDS/IPS overwhelming available CPUReduce categories, restrict to LAN only, alert-only mode (Issue 3)
Query Log shows only A/AAAA, no TXT/NULL everPi-hole Query LogPossible DoH/DoT bypass or genuinely clean networkForce DNS redirect, block DoH endpoints (Issue 4)
server: block ignored, no rate-limit effectDNS Resolver custom optionsYAML indentation error or duplicate server: blockRewrite block with consistent spacing, remove duplicates (Issue 5)

Platform-Specific Issues

Pi-hole on Docker vs. Bare Metal / Raspberry Pi

If you’re running Pi-hole in a Docker container, the FTL database path referenced in Issue 7 (/etc/pihole/pihole-FTL.db) lives inside the container filesystem, not the host. Run sqlite3 commands through docker exec:

docker exec -it pihole sqlite3 /etc/pihole/pihole-FTL.db "SELECT domain, COUNT(*) as cnt FROM queries WHERE type=16 GROUP BY domain ORDER BY cnt DESC LIMIT 20;"

Also confirm your container’s port mapping exposes UDP/TCP 53 correctly (-p 53:53/tcp -p 53:53/udp). A common Docker mistake is mapping only TCP. That doesn’t break normal browsing, but it can hide UDP-based query volume from your monitoring, since most DNS traffic runs over UDP by default.

On Raspberry Pi hardware (Pi 4 or 5, 2–4 GB RAM), Pi-hole itself is lightweight and rarely the bottleneck. If performance issues show up, they’re almost always on the pfSense side (Issue 3), not Pi-hole.

pfSense on Low-Power Appliances vs. VMs

On entry-level Netgate appliances (SG-1100, older SG-3100) or repurposed low-power mini PCs, running Suricata with a full rule set alongside DNS resolution and NAT can genuinely max out the hardware. If you’re on a VM (Proxmox, ESXi), you have more room to work with. Allocate at least 4 vCPUs and 4 GB RAM to the pfSense VM if you plan to run Suricata/Snort with DNS-focused categories continuously. Confirm the virtual NIC uses a paravirtualized driver (VirtIO) rather than emulated hardware; it measurably reduces packet-processing overhead.

Configuration Issues

Mistake: Enabling Suricata/Snort on WAN only. This misses all internal client-to-internet DNS traffic: the exact traffic you need to inspect for tunneling. Assign the package to LAN (or both, if you also want inbound visibility).

Mistake: Setting IPS (blocking) mode immediately on a new install. Correct approach: start with Block Offenders: (Do not block) so you’re in alert-only mode for at least one to two weeks. Review what fires before switching any category to active blocking. Jumping straight to inline blocking on an untuned ruleset risks dropping legitimate traffic. It can lock users out of services with no warning.

Mistake: Pointing DHCP clients at pfSense’s own DNS forwarder instead of Pi-hole. If Services > DHCP Server still lists the pfSense LAN IP as the DNS server, Pi-hole never sees the traffic at all. Its logs will look suspiciously clean. Update the DHCP DNS server field to Pi-hole’s LAN IP directly.

Mistake: Adding rate-limit directives to Unbound without the server: header. Correct syntax always needs the top-level server: key:

server:
    ip-ratelimit: 1000

Pasting just ip-ratelimit: 1000 on its own, without the server: context, gets silently ignored by Unbound on reload.

Mistake: Relying on Pi-hole blocklists alone for tunneling defense. Blocklists catch known-bad domains. Tunneling detection needs behavioral signals too: query length, entropy, record type, and volume. That’s why Suricata/Snort and Unbound rate limiting matter just as much as adlists.

Getting Help

If you’ve worked through the issues above and something still isn’t behaving, gather this information before asking for help. It saves everyone a round trip of “can you post your config”:

  • pfSense Suricata/Snort logs: Status > System Logs > System > General and the package’s own Alerts tab, plus raw logs under /var/log/suricata/ on the filesystem (accessible via Diagnostics > Command Prompt if needed)
  • Unbound/DNS Resolver log: Status > System Logs > DNS Resolver, or /var/log/resolver.log
  • Pi-hole FTL log: /var/log/pihole/FTL.log on the Pi-hole host, or docker logs pihole if containerized
  • Pi-hole diagnostics bundle: run pihole -d on the host, which generates a shareable debug token for community forum posts without exposing your full config

Where to get more help:

Prevention Tips

  • Baseline before you tune. Run Suricata/Snort and Pi-hole in observation mode for a couple of weeks after any major change. That way you know what “normal” looks like before flipping anything to active blocking.
  • Review alerts on a schedule, not just when something feels wrong. A quick weekly pass through Suricata’s Alerts tab and Pi-hole’s top-domains view catches slow, low-volume tunneling long before it becomes an incident.
  • Keep rule sources and blocklists updated automatically. Set Suricata’s rule update schedule and Pi-hole’s gravity update to run daily; stale signatures and blocklists miss new C2 infrastructure.
  • Don’t let DoH/DoT quietly bypass your monitoring. Revisit browser and OS-level DoH settings whenever you roll out new devices or update software. Defaults change, and vendors increasingly ship DoH enabled by default.
  • Document your suppressions and custom rules. A one-line note on why a SID is suppressed or why a regex rule exists saves hours of confusion during your next review.
  • Remember the limits. pfSense’s IDS/IPS and Pi-hole’s DNS-layer filtering give you strong visibility into plaintext port-53 traffic. Neither can inspect encrypted DoH/DoT payloads that bypass your local resolver. Neither replaces dedicated network security monitoring (Zeek, Security Onion) for a fully instrumented environment. Treat this setup as a strong, free first layer, not a complete DNS security program.

Wrapping Up

Work through these fixes and you get a setup that pulls its weight. Suricata flags the traffic shape of DNS tunneling. Unbound rate limiting throttles runaway query volume. Pi-hole adds blocklist coverage plus the query-log visibility to catch what slips past the signatures.

None of it is bulletproof. DoH bypass and brand-new DGA domains are real blind spots, and there’s no way around that. But for a free, self-hosted setup running on hardware you already own, it’s a solid first line of defense, more than most homelabs and small offices ever get around to building.

StepActionApplies To
1Enable rule source + DNS/policy categories on LANpfSense Suricata/Snort
2Start in alert-only mode, tune false positivespfSense Suricata/Snort
3Add ip-ratelimit/ratelimit to Unbound custom optionspfSense DNS Resolver
4Force DHCP clients to Pi-hole, block DoH bypasspfSense Firewall/NAT
5Add threat-intel adlists and regex domain rulesPi-hole
6Use Long Term Data + FTL queries to spot outliersPi-hole
7Run a controlled dig-based verification testBoth

Last updated: 2026-07-31 | Applies to pfSense CE (Suricata/Snort packages) and Pi-hole, accessed via the web-based admin consoles on Linux/FreeBSD-based hosts.