Pi-Dash is a simple, lightweight dashboard for monitoring multiple Pi-hole instances. It provides a clean, at-a-glance, responsive view of your Pi-hole statistics.
- Multiple Pi-hole Support: Monitor all your Pi-hole instances from a single dashboard.
- Network Summary: View combined query, blocked, cached, and forwarded totals across reporting Pi-holes.
- Pi-hole Status: See reachability, authentication errors, and blocking ON/OFF state for each instance.
- Responsive Design: Desktop shows the full dashboard and ambient query feed. Mobile shows critical metrics in compact cards, with an accessible control to expand all available metrics.
- Live Query Feed: Optionally show recent allowed and blocked domains. Consecutive duplicate queries are grouped with
(x2),(x3), and similar counts. - Configurable Refresh: Set separate refresh intervals for statistics and queries. If the query interval is omitted, it uses the statistics interval.
- Efficient Polling: Polling stops while the page is hidden or the browser is offline, then resumes safely when it becomes active again. A short shared cache reduces duplicate Pi-hole API requests.
- Lightweight and Fast: Built with Flask and vanilla JavaScript, with no database or frontend framework.
- Dark Mode and PWA Support: Works with your preferred color scheme and can be installed as a Progressive Web App.
Copy config-example.json to config.json and edit it for your network. The example is valid JSON without comments; all options and their defaults are described below.
{
"base_path": "/",
"refresh_interval": 2000,
"queries_refresh_interval": 3000,
"cache_ttl": 1000,
"show_queries": false,
"show_network_summary": true,
"show_trends": true,
"piholes": [
{
"name": "Primary",
"address": "https://pi.hole",
"password": "${PIHOLE_PRIMARY_PASSWORD}",
"enabled": true,
"link": true,
"verify_ssl": false
}
]
}| Option | Default | Description |
|---|---|---|
base_path |
/ |
Subpath where Pi-Dash is hosted, for example /pi-dash/. |
refresh_interval |
5000 |
Statistics refresh interval in milliseconds. |
queries_refresh_interval |
refresh_interval |
Query-feed refresh interval in milliseconds. |
cache_ttl |
Automatic | Shared backend cache lifetime in milliseconds. Set to 0 to disable caching. |
show_queries |
false |
Show the live DNS query feed. Allowed queries are green and blocked queries are red. |
show_network_summary |
true |
Show combined statistics from all reporting Pi-holes. |
show_trends |
true |
Show short, in-memory query-rate sparklines. |
piholes |
[] |
List of Pi-hole instances to monitor. |
When cache_ttl is omitted, Pi-Dash calculates it as half of the shortest refresh interval, with a minimum of 100 ms and a maximum of 1000 ms. The values in config-example.json are recommended example settings; omitted options use the defaults above.
| Option | Default | Description |
|---|---|---|
name |
Required | Display name for the Pi-hole. Names must be unique. |
address |
Required | Full Pi-hole base URL, including the scheme and optional port. Do not include /admin or /api. |
password |
Empty string | Pi-hole API/application password. Literal values and ${ENV_NAME} references are supported. |
enabled |
true |
Set to false to hide and stop monitoring an instance without deleting it from the configuration. |
link |
false |
Make the Pi-hole name a link to its admin interface. |
verify_ssl |
false |
Set to true to verify trusted HTTPS certificates, or provide a CA bundle path. |
Settings omitted from config.json use the defaults above, so existing configurations continue to work. Existing installations may also continue storing the password directly in config.json:
"password": "your_app_password_here"For new installations, the password can instead be kept outside config.json by referencing an environment variable:
"password": "${PIHOLE_PRIMARY_PASSWORD}"With Docker Compose, add the corresponding value to a .env file beside compose.yaml:
PIHOLE_PRIMARY_PASSWORD=your_app_password_hereThe Compose example below passes this variable to Pi-Dash. For Docker Run, use --env-file .env; for a native installation, export the variable in your shell before starting Pi-Dash. The same ${ENV_NAME} syntax can be used for a CA bundle path. The .env file is ignored by this repository and should not be committed to GitHub.
The Network Summary includes only additive DNS counters: total queries, blocked queries, cached queries, and forwarded queries. It does not combine active clients, unique domains, or domains on lists because those values can overlap between Pi-holes. If an instance is unavailable, the summary is marked as partial.
When the query feed is enabled, it displays recent queries while the dashboard is visible and online. Only consecutive entries with the same Pi-hole, domain, and blocked/allowed state are grouped. The feed is intended as a live overview; use Pi-hole's query log for complete history.
This file contains the Progressive Web App name, colors, and icon:
{
"name": "Pi-Dash",
"short_name": "Pi-Dash",
"description": "A simple dashboard to monitor Pi-hole status.",
"start_url": "/",
"display": "standalone",
"background_color": "#111827",
"theme_color": "#06b6d4",
"icons": [
{
"src": "https://pi.hole/admin/img/logo.svg",
"sizes": "512x512",
"type": "image/svg+xml"
}
]
}Replace icons.src with a direct link to your Pi-hole logo or preferred icon.
services:
pi-dash:
image: ghcr.io/surajverma/pi-dash:latest
container_name: pi-dash
ports:
- 5001:5001
environment:
PIHOLE_PRIMARY_PASSWORD: "${PIHOLE_PRIMARY_PASSWORD}"
volumes:
- ./config.json:/app/config.json:ro
- ./manifest.json:/app/manifest.json:ro
restart: unless-stoppeddocker run -d \
--name pi-dash \
-p 5001:5001 \
--env-file .env \
-v /path/to/pi-dash/config.json:/app/config.json:ro \
-v /path/to/pi-dash/manifest.json:/app/manifest.json:ro \
ghcr.io/surajverma/pi-dash:latest-
Clone the repository:
git clone https://github.com/surajverma/pi-dash.git cd pi-dash -
Create your configuration and install the dependencies:
cp config-example.json config.json python -m pip install -r requirements.txt
On Windows, use
copy config-example.json config.jsoninstead. -
Start Pi-Dash:
python proxy.py
Open http://localhost:5001 in your browser.
GET /health reports whether the Pi-Dash application is running. It does not contact the configured Pi-hole instances.
The automated tests use mocked Pi-hole responses and do not require a live Pi-hole:
python -m unittest discover -s tests -v
npm ci
npm run test:js
npm run build:css
npx playwright install chromium
npm run test:browserInitial development of Pi-Dash was done by Codeloaf. It has since been transferred to this repository for ongoing maintenance, as the original author is not active on GitHub.
This project is not associated with the official Pi-hole project. Pi-hole is a registered trademark of Pi-hole LLC.
This project is licensed under the MIT License. See the LICENSE file for details.
Contributions are welcome! If you have any ideas, suggestions, or bug reports, please open an issue or submit a pull request.
If you like my work, you can buy me a coffee ☕