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.
- Network Insights (Optional): View query history, top clients, and top blocked domains.
- Device Health: See CPU, RAM, temperature, and uptime for each Pi-hole.
- Pi-hole Status: See reachability, authentication errors, and blocking ON/OFF state.
- Responsive Design: Works on desktop and mobile, with expandable details on smaller screens.
- Live Query Feed: Optionally show recent allowed and blocked domains.
- Configurable Refresh: Set separate refresh intervals for statistics and queries.
- Lightweight and Fast: Built with Flask and vanilla JavaScript, with minimal dependencies.
- Dark Mode and PWA Support: Follows your system theme and can be installed as an app.
| Compact default | First instance expanded |
|---|---|
![]() |
![]() |
Copy config-example.json to config.json and edit it for your network. Omitted options use the defaults 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 |
/ |
Hosting subpath, 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 cache lifetime in milliseconds; 0 disables caching. |
show_queries |
false |
Show recent allowed and blocked DNS queries. |
show_network_summary |
true |
Show combined statistics from reporting Pi-holes. |
show_trends |
true |
Show query-rate sparklines. |
show_network_insights |
false |
Show history and top-five rankings; requires Network Summary. |
show_device_metrics |
true |
Show CPU, RAM, temperature, and uptime in instance details. |
piholes |
[] |
Pi-hole instances to monitor. |
| Option | Default | Description |
|---|---|---|
name |
Required | Unique display name for the Pi-hole. |
address |
Required | Full base URL with scheme and optional port; omit /admin and /api. |
password |
Empty string | API/application password or ${ENV_NAME} reference. |
enabled |
true |
Set to false to hide and stop monitoring the instance. |
link |
false |
Link the instance name to its admin interface. |
verify_ssl |
false |
Verify HTTPS certificates with true, or provide a CA bundle path. |
Use a literal password or a ${ENV_NAME} reference. For the example above, create a .env file beside compose.yaml:
PIHOLE_PRIMARY_PASSWORD=your_app_password_hereCompose passes this variable below; Docker Run uses --env-file .env. For native installs, export it before starting Pi-Dash. Keep .env out of version control.
- Installing Pi-Dash as an app (PWA) requires HTTPS or localhost.
- Pi-Dash has no login of its own, so keep it on your LAN or behind a reverse proxy with authentication.
- Restart the container or process after changing
config.json.
If /app/manifest.json is mounted, Pi-Dash uses it; otherwise it uses the built-in manifest. To customize it, copy web/manifest.json, edit it, and mount it.
Icons in a custom manifest must load in the browser: prefer relative paths or a publicly trusted HTTPS URL. An icon on a host with an untrusted self-signed certificate, such as https://pi.hole, can block the install prompt.
Create the host file before enabling a manifest mount; if it does not exist, Docker creates an empty folder in its place.
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
# Optional: create manifest.json first, then uncomment.
# - ./manifest.json:/app/manifest.json:ro
restart: unless-stopped# Optional: create manifest.json first, then add this mount before the image.
# -v /path/to/pi-dash/manifest.json:/app/manifest.json:ro \
docker run -d \
--name pi-dash \
-p 5001:5001 \
--env-file .env \
-v /path/to/pi-dash/config.json:/app/config.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 -m pi_dash
Open http://localhost:5001 in your browser.
GET /health reports whether Pi-Dash is running without contacting your Pi-holes.
python -m unittest discover -s tests
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 ☕



