Skip to content

Latest commit

 

History

History
381 lines (275 loc) · 13.2 KB

README.md

File metadata and controls

381 lines (275 loc) · 13.2 KB

🛡️ Pi-hole + Unbound

One-Click DNS Security Stack

License Pi-hole Unbound Debian Python Buy Me A Coffee

Tech Stack

🌐 Languages: 🇬🇧 English (this file) • 🇩🇪 Deutsch


✨ What This Is

A production-ready installer and management suite for running Pi-hole + Unbound on a Raspberry Pi.

DNS chain:

Client → Pi-hole (port 53) → Unbound (port 5335) → Internet

Pi-hole handles ad/tracker blocking; Unbound handles recursive DNS resolution with full DNSSEC validation — no third-party DNS resolver required.

Project Status and Latest Update

Documentation last checked: 2026-10-28

Latest project update: 2026-10-28 — PR #37 fixes upstream detection under systemd hardening. The README refresh and stale-artifact cleanup are in PR #35; the dashboard and maintenance updates are in PR #32, PR #33, and PR #34.

  • Integrated the read-only DNS dashboard with the authenticated maintenance panel.
  • Hardened upgrades, bounded DNS-log parsing, kept the API key out of persistent browser storage, and enabled least-privilege log access.
  • Restricted the test workflow token to read-only repository contents.
  • Rechecked production DNS and DNSSEC behavior, both web interfaces, and authenticated API routes.

NetAlertX is optional. It was not configured on the production system last checked, so /devices reports HTTP 503 rather than inventing an empty device list. Pi-hole and Unbound monitoring and DNS are independent of this optional feature. See CHANGELOG.md for the change history.


⚡ Quickstart

git clone https://github.com/TimInTech/Pi-hole-Unbound-PiAlert-Setup.git
cd Pi-hole-Unbound-PiAlert-Setup
chmod +x install.sh
sudo ./install.sh

Clone as a normal user (pi), not root. The installer requires sudo ./install.sh.

For an existing suite with the maintenance interface, sudo ./install.sh --upgrade-only updates the suite and web files without changing DNS configuration or the Python environment. See docs/MAINTENANCE_WEB.md for prerequisites and rollback.


✅ Requirements

Requirement Details
Platform Raspberry Pi 3/4/5, Debian Bookworm/Trixie (64-bit)
Pi-hole v6.x (installed by this script)
Unbound Installed and configured to port 5335
Python 3.10+ (for the optional Suite API and maintenance panel)
User Normal user with sudo

Install prerequisites manually (optional):

sudo apt-get update
sudo apt-get install -y unbound unbound-host unbound-anchor dns-root-data \
  ca-certificates curl dnsutils iproute2 python3 python3-venv python3-pip \
  git openssl sqlite3 jq

Install docker.io as well when you want the optional NetAlertX or containerized Pi-hole mode.


🔴 Critical: Pi-hole Must Use Unbound as Upstream

Without this, the stack is broken — DNSSEC is bypassed and you are using an external resolver.

Pi-hole must forward DNS queries to Unbound on 127.0.0.1#5335.

Verify via Pi-hole admin → Settings → DNS:

Pi-hole upstream DNS setting

Or via the installer / Rescue Menu:

sudo pihole-rescue   # Option 9: Pi-hole → Unbound standard fix

🖥️ Management Tools

This repo ships three complementary management interfaces:

1. Console Menu (scripts/console_menu.sh)

General-purpose interactive menu for everyday management.

bash ~/Pi-hole-Unbound-PiAlert-Setup/scripts/console_menu.sh
# or with forced text mode:
bash ~/Pi-hole-Unbound-PiAlert-Setup/scripts/console_menu.sh --text

Console Menu

Option Action
1 Post-Install Check (Quick)
2 Post-Install Check (Full) — requires sudo
3 Show Service URLs
4 Manual Steps Guide
5 Maintenance Pro — requires sudo
6 View Logs
7 Rescue & Backup Menu
8 Exit

2. Rescue & Backup Menu (scripts/rescue_menu.sh)

Standalone recovery and diagnostic tool. Accessible globally:

sudo pihole-rescue
Option Action
1 System status check (services, DNS, ports, temperature)
2 DNS loop / upstream check
3 Nightly / diagnostic test
4 Create backup (pihole.toml + Unbound config + systemd drop-ins)
5 Restore from backup
6 Delete old backups
7 Last-Known-Good restore
8 Emergency DNS bypass (Pi → 8.8.8.8/1.1.1.1, reversible)
9 Pi-hole → Unbound standard fix
10 Router / client DNS hint (FritzBox guide)
11 Show last report / log
0 Exit

3. Maintenance Pro (tools/pihole_maintenance_pro.sh)

Batch maintenance script (apt updates, Pi-hole update, gravity update, security scan).

sudo bash tools/pihole_maintenance_pro.sh
# or with flags:
sudo bash tools/pihole_maintenance_pro.sh --no-apt --no-upgrade

Available flags: --no-apt, --no-upgrade, --no-gravity, --restart-ftl, --backup, --json


📁 Repository Structure

Pi-hole-Unbound-PiAlert-Setup/
├── install.sh                     # Main host/container installer
├── start_suite.py                 # Optional authenticated API and DNS dashboard
├── maintenance_web.py             # Browser maintenance panel and session security
├── maintenance_runner.py          # Privileged maintenance job runner
├── maintenance_backups.py         # Verified backup operations
├── maintenance_config.py          # Caddy and LAN configuration validation
├── maintenance_install.py         # Maintenance panel provisioning
├── requirements.txt               # Python API and test dependencies
├── .env.example                   # Environment variable template
├── dashboard/                     # Read-only DNS monitoring dashboard
├── web/                           # Maintenance panel assets
├── deploy/                        # systemd, Caddy, and sudo policy files
├── scripts/
│   ├── install_maintenance_web.sh # Staged/live maintenance installer
│   ├── rollback_maintenance_web.sh # Validated deployment rollback
│   ├── console_menu.sh            # Interactive management menu
│   ├── rescue_menu.sh             # Rescue and backup menu
│   └── lib/ui.sh                  # Shared shell UI helpers
├── tools/pihole_maintenance_pro.sh # Batch maintenance script
├── tests/                         # Python, shell, browser, and upgrade tests
├── docs/                          # Operations, design notes, reports, screenshots
├── CHANGELOG.md
└── README.de.md

⚙️ Post-Install Verification

# Quick check (no sudo)
bash scripts/post_install_check.sh --quick

# Full check (requires sudo)
sudo bash scripts/post_install_check.sh --full

Post-Install Check


🆘 Rescue Operations

Emergency DNS Bypass

When Pi-hole or Unbound is broken and you have no DNS:

sudo pihole-rescue  # Option 8: Emergency DNS bypass

This sets the Pi itself to use 8.8.8.8/1.1.1.1 directly. Fully reversible — the menu stores your previous config and lets you restore it.

Last-Known-Good Restore

Restores your last known-working backup and verifies DNS is working:

sudo pihole-rescue  # Option 7: Last-Known-Good restore

Backup / Restore

sudo pihole-rescue  # Option 4: Create backup
sudo pihole-rescue  # Option 5: Restore from backup

Backups are stored in /home/pi/pihole-rescue-backups/ and include:

  • /etc/pihole/pihole.toml
  • /etc/unbound/unbound.conf.d/
  • Systemd drop-in files

🐍 Optional: Suite REST API & Dashboard

start_suite.py is an optional FastAPI server providing a JSON API for monitoring. It also hosts a modern, responsive, read-only web Dashboard for monitoring your DNS stack.

  • Dashboard Access: On a configured host, open https://<pihole-host>:8443/dashboard/ through Caddy. For local development, use http://127.0.0.1:8090/dashboard/.
  • Maintenance Panel: The root path https://<pihole-host>:8443/ serves the separate maintenance panel when enabled.
  • Remote Access: The API binds to 127.0.0.1:8090. Do not expose that port directly; use the configured Caddy LAN endpoint or an SSH tunnel.
  • Authentication: Dashboard login and API endpoints require the SUITE_API_KEY.
  • The dashboard holds the key in page memory only. Reloading the page requires signing in again.
# Setup
cp .env.example .env
nano .env   # set SUITE_API_KEY

# Install deps
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# Start
set -a
. ./.env
set +a
python3 start_suite.py
# The API stays on 127.0.0.1:8090; production API documentation is disabled.

The DNS dashboard reports overall health, Pi-hole FTL status and version, configured upstreams and the count of parsed queries from the latest 100 log entries; Unbound status, port and DNS probe; optional NetAlertX reachability; and Suite API uptime, version and detected host IP. Missing source data is shown as unavailable, not as zero. The API provides /health, /version, /urls, /pihole, /unbound, /netalertx, /stats, /dns, /leases, and /devices. Maintenance endpoints are under /api/session and /api/maintenance/. Device discovery returns HTTP 503 until NetAlertX integration is configured.

The maintenance panel shows the latest job result, its checks and system snapshot. It can run a system check, create and verify backups (up to 10, with download and deletion), and run a controlled update. Restore is performed locally through the documented recovery procedure, not from the browser.

Not required for the core Pi-hole + Unbound stack.

Secure maintenance web panel

The optional maintenance panel provides a system check, verified backups, controlled updates, the latest job result, system snapshot, and check steps. It remains disabled by default. On a fresh host installation, enable it with:

sudo ./install.sh --with-maintenance-web

For an existing installation that already has the maintenance panel, update it with sudo ./install.sh --upgrade-only. Browser sign-in uses the existing SUITE_API_KEY.

See docs/MAINTENANCE_WEB.md for prerequisites, certificate trust, security boundaries and rollback.


🌐 Optional: NetAlertX

Network device monitoring (separate install):

sudo ./install.sh --with-netalertx

Without NetAlertX, device discovery remains unavailable; DNS monitoring and Pi-hole/Unbound operation continue normally.


🔎 Manual Update Check

The host Pi-hole installer uses the official https://install.pi-hole.net installer and does not pin a patch release. Container mode uses pihole/pihole:latest; NetAlertX uses jokobsk/netalertx:latest.

Run these checks manually during maintenance windows only:

pihole -v
sudo pihole -up
apt list --upgradable
docker pull jokobsk/netalertx:latest

Use the Rescue Menu or create a backup before applying updates on a production Raspberry Pi.


🔧 Troubleshooting

DNS not resolving

sudo pihole-rescue   # Option 2: DNS check, or Option 8: Emergency bypass

Pi-hole not using Unbound

sudo pihole-rescue   # Option 9: Pi-hole → Unbound fix

Check system status

systemctl status pihole-FTL unbound
dig +short @127.0.0.1 google.com
dig +short @127.0.0.1 -p 5335 google.com

Run full diagnostic

sudo bash scripts/post_install_check.sh --full
sudo bash scripts/nightly_test.sh

🛡️ Security Notes

  • The Suite API (start_suite.py) binds to 127.0.0.1 only by default
  • Always set a strong SUITE_API_KEY
  • The Pi-hole admin interface is protected by Pi-hole's own authentication
  • Unbound runs on port 5335 (not exposed externally unless you configure it)
  • See SECURITY.md for vulnerability reporting

📜 License

MIT License — © TimInTech