The Problem: When Pi-hole Becomes a “Black Box” on Your Local Network
For homelab enthusiasts and small office network admins, Pi-hole is a familiar line of defense for blocking DNS trackers and advertisements. Pi-hole’s default web interface is clean and straightforward. However, it is only handy when you want a quick glance at a few basic metrics. Things change drastically once your ecosystem grows to 40–50 devices, ranging from IP cameras and smart TVs to test lab virtual machines.
Its biggest drawback: Pi-hole limits how long logs are retained in RAM and local SQLite files to prevent I/O bottlenecks. When your network stutters because a malware-infected camera is flooding DNS requests, correlating query spikes with CPU usage or router bandwidth becomes notoriously difficult. To retain logs for months or years and analyze multidimensional graphs, pairing Pi-hole with the powerhouse duo of Prometheus and Grafana is the best way to go.
Core Concepts: How Prometheus Ingests Metrics from Pi-hole
Pi-hole does not natively expose a Prometheus-standard /metrics endpoint. Instead, it only provides a REST API via the FTL engine that outputs raw JSON data.
We need an intermediary bridge: pihole-exporter. The data flow works as follows:
- pihole-exporter: Every 15 seconds, this container queries the Pi-hole API using an authentication token. It ingests the JSON payload and translates it into standard OpenMetrics text metrics.
- Prometheus: Periodically scrapes data from port
9617of the exporter. All metrics are compressed and written directly to the Time-Series Database (TSDB). - Grafana: Pulls figures from Prometheus using PromQL. From there, you can build dashboards tracking block ratios, query rates per second, and the top DNS-hungry clients.
Step-by-Step Guide: From Zero to a Complete Dashboard
Step 1: Retrieve the API Token from Pi-hole
The exporter needs this token string to read FTL metrics. Follow these steps to obtain it:
- Open the Pi-hole Admin interface > go to Settings > select the API / Web interface tab.
- Click Show API token, confirm the warning popup, and copy the
WEBPASSWORDhash.
Bước 2: Run pihole-exporter with Docker Compose
Spinning up the exporter with Docker keeps your environment clean and easy to maintain. You can place the docker-compose.yml file directly on the Raspberry Pi hosting Pi-hole or on a separate monitoring host:
version: '3.8'
services:
pihole-exporter:
image: eko/pihole-exporter:v0.12.0
container_name: pihole-exporter
restart: unless-stopped
ports:
- "9617:9617"
environment:
- PIHOLE_HOSTNAME=192.168.1.53
- PIHOLE_PASSWORD=b49c0d9a691234567890abcdef1234567890abcdef1234567890abcdef123456
- PORT=9617
- INTERVAL=15s
Pull the image and start the service:
docker compose up -d
Verify whether the exporter is successfully scraping live data:
curl -s http://localhost:9617/metrics | grep pihole_
If the terminal returns metrics such as pihole_dns_queries_today 18450, your connection is working properly.
Step 3: Define the Scrape Job in Prometheus
Open the prometheus.yml file on your monitoring server and add the scrape configuration:
scrape_configs:
- job_name: 'pihole'
scrape_interval: 15s
scrape_timeout: 10s
static_configs:
- targets: ['192.168.1.53:9617']
labels:
instance: 'homelab-pihole'
environment: 'production'
Reload the configuration without restarting the Prometheus process:
curl -X POST http://localhost:9090/-/reload
Step 4: Import the Grafana Dashboard and Write Practical PromQL Queries
For an out-of-the-box polished look, import Dashboard ID 10176 (or revision 13565). Go to Grafana > Dashboards > New > Import, enter the ID, and select your Prometheus data source.
However, crafting panels by hand is still the best way to keep control of your metrics. Here are 3 essential PromQL queries you should master:
1. Percentage of requests blocked today:
(pihole_ads_blocked_today / pihole_dns_queries_today) * 100
2. Average query rate (queries/second):
rate(pihole_dns_queries_total[2m])
3. Top 10 clients sending the most requests over the last 5 minutes:
topk(10, sum by (client) (rate(pihole_queries_by_client_total[5m])))
Battle-Tested Tips: Avoid Alert Fatigue When Setting Thresholds
When I first set up this stack, I suffered from severe alert fatigue. Whenever query volume spiked or the block percentage surpassed 35%, my Telegram bot would blow up with alerts. It turned out the culprits were just a Sony TV updating its firmware in the background or a laptop running iCloud sync.
After many sleepless nights triggered by false positives, I arrived at two critical rules:
- Never alert on instantaneous spikes: Wrap your metrics inside
rate()orincrease()over a 10–15 minute evaluation window. A user launching a browser with 20 tabs simultaneously firing hundreds of requests in 5 seconds is completely normal. - Catch anomalies from individual IPs instead of total volume: Trigger an alert when a single IP accounts for more than 50% of total network queries over a 15-minute period. This is often the clearest fingerprint of an IoT device hijacked by a Mirai botnet variant or an application stuck in an aggressive DNS retry storm.
Conclusion
The trio of Pi-hole, Prometheus, and Grafana transforms a simple DNS sinkhole into a full-fledged network monitoring radar. You will gain clear visibility into every traffic shift—from a network printer beaming diagnostics outside to anomalous network scanning. Spin up the exporter container today, and be sure to tune your alerting thresholds carefully to spare your peace of mind.

