Tech Expert & Vibe Coder

With 14+ years of experience, I specialize in self-hosting, AI automation, and Vibe Coding – building applications using AI-powered tools like Google Antigravity, Dyad, and Cline. From homelabs to enterprise solutions.

Building a Pi-hole DNS Sinkhole for Detecting Unauthorized Container-to-Internet Traffic in Raspberry Pi Homelabs

Why I Built a DNS Sinkhole on Raspberry Pi

I run several Docker containers in my homelab—some for automation, some for testing, and a few that handle background tasks I don't always keep track of. Over time, I started wondering: what if one of these containers is quietly phoning home without me knowing?

Most container images come from public registries. Even trusted ones can include dependencies that make unexpected network calls—telemetry, update checks, analytics. I wanted visibility into what was leaving my network at the DNS level, and I wanted the ability to block it selectively.

That's when I set up Pi-hole on a Raspberry Pi 4. Not as an ad blocker (though it does that), but as a DNS sinkhole that logs every query and gives me control over what gets resolved.

My Setup

I used a Raspberry Pi 4 with 4GB of RAM running Raspberry Pi OS Lite. I chose the Pi 4 over a Pi Zero because I needed enough headroom to handle DNS queries from multiple devices and containers without lag. The Pi Zero might work for a small network, but I didn't want to risk bottlenecks.

I run Pi-hole inside a Docker container, not directly on the OS. This keeps the base system clean and makes it easier to back up or migrate later. I use Docker Compose to manage the container, which also simplifies updates and configuration changes.

For upstream DNS, I point Pi-hole to Cloudflare's 1.1.1.1. I considered Google's 8.8.8.8, but I prefer Cloudflare's privacy stance—they don't log queries long-term, and they support DNS-over-HTTPS if I decide to enable it later.

Why Docker Instead of Bare Metal

Installing Pi-hole directly on the OS would work, but I wanted isolation. Running it in a container means:

  • I can blow away the container and rebuild it without touching the base system
  • Updates are just pulling a new image and restarting
  • If I mess up a configuration, I can roll back easily
  • I can move the entire setup to another Pi or server with minimal effort

I configured the container to use host networking mode instead of Docker's default bridge mode. This was necessary so Pi-hole could see the real IP addresses of devices making DNS queries. In bridge mode, everything looked like it was coming from the Docker bridge IP, which defeated the purpose of monitoring individual containers.

Giving the Pi a Static IP

I logged into my router and reserved a static IP for the Pi based on its MAC address. Without this, the Pi's IP could change after a reboot, and any device pointing to it for DNS would lose connectivity. I've had that happen before with other services, and it's annoying to troubleshoot.

Once the IP was locked down, I configured my router's DHCP settings to hand out the Pi's IP as the primary DNS server for all devices on the network. This meant every DNS query—from laptops, phones, and Docker containers—would flow through Pi-hole.

What Worked

Within hours of turning it on, I could see every DNS query in the Pi-hole dashboard. I immediately noticed patterns I hadn't expected:

  • A container running a media automation tool was making repeated queries to a telemetry domain I'd never heard of
  • My phone was constantly hitting tracker domains even when I wasn't actively using it
  • A smart TV I barely use was pinging ad servers every few minutes

I added the telemetry domain to Pi-hole's blocklist. The queries stopped. The container still worked fine—it just couldn't send data I didn't authorize.

For detecting unauthorized container traffic specifically, the query log became my main tool. I can filter by client IP (each container gets its own IP in my Docker network), sort by time, and see exactly what domains are being requested. If a container I expect to be local-only starts querying external domains, I know immediately.

Performance

DNS resolution is fast. I don't notice any delay compared to using my ISP's DNS or Cloudflare directly. Pi-hole caches responses, so repeat queries are even faster. The Pi 4's CPU barely breaks a sweat—most of the time it sits below 10% usage.

Persistence After Reboots

I configured Docker to restart the Pi-hole container automatically on boot. I also mounted Pi-hole's configuration and database directories as Docker volumes, so settings and query history survive reboots. I've tested this by pulling the power plug—everything comes back up without manual intervention.

What Didn't Work

Initial Networking Confusion

The first time I deployed Pi-hole in Docker, I used bridge mode because that's the default. It took me longer than it should have to realize why all queries were showing up as coming from the same IP. I had to stop the container, edit the Docker Compose file to switch to host mode, and redeploy. Lesson learned: always check networking mode when DNS or DHCP is involved.

Overly Aggressive Blocklists

I started with a few popular blocklists from the Pi-hole community. Some of them were too aggressive and broke legitimate services. For example, one list blocked a domain used by a package manager in one of my containers, which caused builds to fail silently. I had to whitelist it manually.

Now I'm more selective about which lists I enable, and I test new ones on a small subset of devices before applying them network-wide.

No Built-in Alerts

Pi-hole logs everything, but it doesn't alert me when something unusual happens. If a container suddenly starts hitting a new external domain, I have to notice it myself by checking the logs. I'm considering writing a script that parses the query log and sends me a notification if a container makes a DNS request it's never made before, but I haven't built that yet.

How I Use It Now

Every few days, I check the Pi-hole query log. I filter by container IP and look for unfamiliar domains. If I see something I don't recognize, I:

  1. Look up the domain to understand what it's for
  2. Decide if it's necessary for the container to function
  3. Block it if it's telemetry, analytics, or tracking
  4. Whitelist it if it's required for updates or core functionality

This process has helped me catch a few things I wouldn't have noticed otherwise. For example, I found out that a container I use for RSS feed aggregation was sending usage stats to the developer's server. I blocked the domain, and the container still works fine.

Blocking Ads as a Side Effect

I didn't set this up primarily for ad blocking, but it does block ads network-wide. Websites load faster, and I don't see banner ads on devices that don't have browser extensions. It's a nice bonus, but the real value for me is the visibility into what my containers are doing.

Limitations I've Accepted

Pi-hole only sees DNS queries. If a container is hardcoded to use a specific DNS server (like 8.8.8.8) instead of the one assigned by DHCP, Pi-hole won't catch it. I've had to manually override DNS settings in a few container configurations to force them through Pi-hole.

It also can't block anything that uses IP addresses directly instead of domain names. If a container is connecting to a hardcoded IP, I won't see it in the DNS logs. For that, I'd need to monitor network traffic at a lower level, which I haven't set up yet.

Finally, Pi-hole doesn't inspect the content of requests—it only blocks or allows based on domain names. If a container is sending data to a domain I've whitelisted, I have no visibility into what that data is.

Key Takeaways

Setting up Pi-hole taught me that DNS is a surprisingly powerful control point. Most devices and containers rely on it, and blocking at the DNS level is simpler than trying to firewall individual connections.

Running it in Docker was the right call. I've rebuilt the container a few times while testing different configurations, and it's always been faster than reinstalling on bare metal would have been.

The biggest value isn't blocking ads—it's knowing what's happening on my network. Before Pi-hole, I had no idea how chatty some of my containers were. Now I can see it, log it, and decide what to allow.

If you run containers in a homelab and you're not monitoring DNS, you're missing a lot of outbound traffic. Pi-hole is a low-effort way to fix that.