diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..f91e1ba
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,11 @@
+# Intentionally left blank. Do NOT put secrets here.
+# Example placeholders (do not set real values):
+# PIHOLE_API_URL=
+# PIHOLE_PASSWORD=
+# Local configuration for tools (no secrets)
+# Export before running healthcheck:
+# export PIHOLE_API_URL="http://127.0.0.1/api"
+# read -s PIHOLE_PASSWORD
+# export PIHOLE_PASSWORD
+PIHOLE_API_URL=
+# PIHOLE_PASSWORD is read from environment if set
diff --git a/.gitignore b/.gitignore
index 635f780..88af306 100644
--- a/.gitignore
+++ b/.gitignore
@@ -86,3 +86,23 @@ pihole_maintenance_pro_test.sh
vendor/bundle/
.bundle/
.npm-cache/
+
+# Additional ignores
+.DS_Store
+Thumbs.db
+node_modules/
+dist/
+build/
+out/
+__pycache__/
+*.pyc
+.mypy_cache/
+.pytest_cache/
+.ruff_cache/
+*.log
+*.tmp
+
+# Dotenv / local env files
+.env
+.env.*
+!.env.example
diff --git a/LICENSE b/LICENSE
index 1201355..f794082 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2025 ==TIM.©.B ==
+Copyright (c) 2025 Tim
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index adc262e..045b06f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,24 +1,37 @@
+.PHONY: check fmt lint
+
SHELL := /bin/bash
SHFMT ?= shfmt
SHELLCHECK ?= shellcheck
SCRIPTS := pihole_maintenance_pro.sh scripts/*.sh tools/*.sh
-.PHONY: fmt lint check
+check:
+ @echo "bash -n"
+ bash -n $(SCRIPTS)
+ @echo "shellcheck"
+ @if command -v $(SHELLCHECK) >/dev/null 2>&1; then \
+ $(SHELLCHECK) -x $(SCRIPTS) || true; \
+ else \
+ echo "shellcheck not installed; skipping"; \
+ fi
+ @echo "shfmt -d (no changes)"
+ @if command -v $(SHFMT) >/dev/null 2>&1; then \
+ $(SHFMT) -i 2 -ci -sr -d .; \
+ else \
+ echo "shfmt not installed; skipping"; \
+ fi
fmt:
@if command -v $(SHFMT) >/dev/null 2>&1; then \
- $(SHFMT) -i 2 -ci -sr -w $(SCRIPTS); \
+ $(SHFMT) -i 2 -ci -sr -w .; \
else \
- echo "shfmt not installed; skipping fmt"; \
+ echo "shfmt not installed; skipping"; \
fi
lint:
@if command -v $(SHELLCHECK) >/dev/null 2>&1; then \
$(SHELLCHECK) -x $(SCRIPTS); \
else \
- echo "shellcheck not installed; skipping lint"; \
+ echo "shellcheck not installed; skipping"; \
fi
-
-check: fmt lint
-
diff --git a/README.de.md b/README.de.md
index d51361e..b221d99 100644
--- a/README.de.md
+++ b/README.de.md
@@ -1,6 +1,7 @@
# 🛰️ Pi-hole Maintenance PRO MAX
+
**Automatisiertes Pi-hole v6 Wartungsskript**
[](https://github.com/TimInTech/pihole-maintenance-pro/actions)
@@ -16,20 +17,24 @@
---
## Was & Warum
+
Pi-hole v6 Wartung für Raspberry Pi OS (Bookworm/Trixie) mit Logging und Healthchecks.
## Features
-- APT update/upgrade/autoremove/autoclean
-- Pi-hole Update (`-up`), Gravity (`-g`), `reloaddns`
-- Healthchecks: Port 53, `dig`, GitHub-Erreichbarkeit
-- Optional: Tailscale-Info, FTL-Toplisten via `sqlite3`
-- Performance-Dashboard & intelligente Zusammenfassung
-- Lokales Backup vor Pi-hole-Änderungen
-- Installer setzt automatisch einen wöchentlichen Cron (`0 4 * * 0`)
+
+- APT update/upgrade/autoremove/autoclean
+- Pi-hole Update (`-up`), Gravity (`-g`), optionaler FTL-Restart (`--restart-ftl`)
+- Healthchecks: Port 53, `dig`, GitHub-Erreichbarkeit
+- Optional: Tailscale-Info, FTL-Toplisten via `sqlite3`
+- Performance-Dashboard & intelligente Zusammenfassung
+- Lokales Backup vor Pi-hole-Änderungen
+- Installer setzt automatisch einen wöchentlichen Cron (`0 4 * * 0`) (idempotent)
- Logs: `/var/log/pihole_maintenance_pro_.log`
## Schnellstart
+
**Installer:**
+
```bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main/scripts/install.sh)"
```
@@ -38,11 +43,13 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-mainten
## Update / Überschreiben (sichere Re-Installation)
Zieht die aktuelle Version und überschreibt die vorhandene:
+
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main/scripts/install.sh)"
```
## Uninstall (saubere Entfernung)
+
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main/scripts/uninstall.sh)"
```
@@ -55,7 +62,8 @@ Zieht die aktuelle Version und überschreibt die vorhandene:
- `--no-apt` – APT-Schritte (update/upgrade/autoremove/autoclean) überspringen.
- `--no-upgrade` – **kein** `pihole -up`.
- `--no-gravity` – `pihole -g` (Blocklisten/Gravity) überspringen.
-- `--no-dnsreload` – `pihole reloaddns` überspringen.
+- `--no-dnsreload` – veraltet unter v6 (No-Op).
+- `--restart-ftl` – pihole-FTL am Ende neustarten (nur bei Bedarf).
- `--backup` – Backup vor Pi-hole-Operationen unter `/var/backups/pihole/`.
- `--json` – JSON-Ausgabe statt farbiger Zusammenfassung.
@@ -81,6 +89,7 @@ sudo /usr/local/bin/pihole_maintenance_pro.sh --no-apt --no-upgrade --no-gravity
```
## Beispielausgabe (echtes Pi-hole v6)
+
Aufgenommen auf einem Raspberry Pi mit Pi-hole Core 6.1.4, Web 6.2.1, FTL 6.2.3 – so sieht das aktuelle Dashboard + die Zusammenfassung live aus:
```bash
@@ -99,6 +108,7 @@ Aufgenommen auf einem Raspberry Pi mit Pi-hole Core 6.1.4, Web 6.2.1, FTL 6.2.3
```
Der reale Lauf bestätigt außerdem:
+
- Backups werden vor Pi-hole-Wartung erstellt (z. B. `/etc/pihole/backup_20251025_100315`, `/etc/pihole/backup_20251025_100337`)
- Der Installer setzt automatisch den empfohlenen Cron: `0 4 * * 0 /usr/local/bin/pihole_maintenance_pro.sh >>/var/log/pihole_maint_cron.log 2>&1`
- Security-Block (Steps 20–26) und Healthchecks (Steps 07–10) laufen ohne Warnungen durch
@@ -111,30 +121,32 @@ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
30 3 * * * /usr/local/bin/pihole_maintenance_pro.sh >> /var/log/pihole_maintenance_pro.log 2>&1
```
-> Trixie/Cron nutzt einen reduzierten PATH. Mit vollem PATH laufen beide Skripte zuverlässig.
+> Trixie/Cron nutzt einen reduzierten PATH. Mit vollem PATH laufen beide Skripte zuverlässig. Der Installer setzt den wöchentlichen Cron jetzt idempotent.
## Hinweis zu Pi-hole v6 API
-- Keine setupVars.conf mehr
-- Konfiguration jetzt in /etc/pihole/pihole.toml
-- API unter /api, nicht /api.php
-- Authentifizierung via Basic Auth mit User cli und Passwort aus /etc/pihole/cli_pw
-- Das Healthcheck-Skript pihole_api_healthcheck.sh kann lokal Basic-Auth gegen die API fahren, wenn PIHOLE_API_URL gesetzt ist
-- Unbound ist nicht erforderlich
+- `setupVars.conf` entfällt
+- Konfiguration in `/etc/pihole/pihole.toml`
+- API unter `/api` (nicht `/api.php`)
+- Authentifizierung mittels Session: `POST /api/auth` → `sid`, danach Header `X-FTL-SID`
+- Healthcheck (`tools/pihole_api_healthcheck.sh`) nutzt `PIHOLE_API_URL` und optional `PIHOLE_PASSWORD` zum Login
+- Unbound ist optional
## Troubleshooting
-* `sqlite3` für Top-Listen:
+- `sqlite3` für Top-Listen:
```bash
sudo apt update && sudo apt install -y sqlite3
```
+
* Locale-Warnungen:
```bash
echo -e "en_GB.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8" | sudo tee /etc/locale.gen >/dev/null
sudo locale-gen && sudo update-locale LANG=de_DE.UTF-8 LC_ALL=de_DE.UTF-8
```
+
* Hinweis `linux-image-rpi-v8` auf Pi 3B: ignorierbar.
## Lizenz
@@ -144,5 +156,6 @@ MIT. Siehe [LICENSE](LICENSE).
*Zuletzt aktualisiert: 2025-10-10 • Version: 5.3.2*
## Support
+
Wenn dir dieses Projekt hilft, kannst du es hier unterstützen:
[buymeacoffee.com/timintech](https://buymeacoffee.com/timintech)
diff --git a/README.md b/README.md
index d8a78e0..61e0bcc 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# 🛰️ Pi-hole Maintenance PRO MAX
+
**Automated Pi-hole v6 Maintenance Script**
[](https://github.com/TimInTech/pihole-maintenance-pro/actions)
@@ -9,25 +10,27 @@
**Languages:** 🇬🇧 English (this file) • [🇩🇪 Deutsch](README.de.md)
-
-
---
## What & Why
+
Automated Pi-hole v6 maintenance script for Raspberry Pi OS (Bookworm/Trixie) with logging and health checks.
## Features
-- APT update/upgrade/autoremove/autoclean
-- Pi-hole update (`-up`), gravity (`-g`), `reloaddns`
-- Health checks: port 53, `dig`, GitHub reachability
-- Optional Tailscale info, FTL toplists via `sqlite3`
-- Performance dashboard & intelligent end-of-run summary
-- Automatic local backup prior to Pi-hole changes
-- Installer drops a weekly cron (`0 4 * * 0`) out of the box
+
+- APT update/upgrade/autoremove/autoclean
+- Pi-hole update (`-up`), gravity (`-g`), optional FTL restart (`--restart-ftl`)
+- Health checks: port 53, `dig`, GitHub reachability
+- Optional Tailscale info, FTL toplists via `sqlite3`
+- Performance dashboard & intelligent end-of-run summary
+- Automatic local backup prior to Pi-hole changes
+- Installer drops a weekly cron (`0 4 * * 0`) out of the box (idempotent)
- Logs in `/var/log/pihole_maintenance_pro_.log`
## Quickstart
+
**Installer:**
+
```bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main/scripts/install.sh)"
```
@@ -36,11 +39,13 @@ bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-mainten
## Update / Overwrite (safe re-install)
Use this to pull and overwrite with the latest release:
+
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main/scripts/install.sh)"
```
## Uninstall (clean removal)
+
```bash
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main/scripts/uninstall.sh)"
```
@@ -50,11 +55,12 @@ Use this to pull and overwrite with the latest release:
### Flags
-- `--no-apt` – skips APT steps (update/upgrade/autoremove/autoclean)
-- `--no-upgrade` – does **not** run `pihole -up`
-- `--no-gravity` – skips `pihole -g` (blocklists/Gravity update)
-- `--no-dnsreload` – skips `pihole reloaddns`
-- `--backup` – creates a backup before Pi-hole ops under `/var/backups/pihole/`
+- `--no-apt` – skips APT steps (update/upgrade/autoremove/autoclean)
+- `--no-upgrade` – does **not** run `pihole -up`
+- `--no-gravity` – skips `pihole -g` (blocklists/Gravity update)
+- `--no-dnsreload` – deprecated in v6 (no-op)
+- `--restart-ftl` – restart pihole-FTL at the end (v6: only if needed)
+- `--backup` – creates a backup before Pi-hole ops under `/var/backups/pihole/`
- `--json` – outputs machine-readable JSON instead of the colored TUI
**Manual installation:**
@@ -79,6 +85,7 @@ sudo /usr/local/bin/pihole_maintenance_pro.sh --no-apt --no-upgrade --no-gravity
```
## Real Pi-hole v6 sample run
+
Captured on a Raspberry Pi with Pi-hole Core 6.1.4, Web 6.2.1, FTL 6.2.3 — this is the live dashboard + summary rendered by the current release:
```bash
@@ -97,6 +104,7 @@ Captured on a Raspberry Pi with Pi-hole Core 6.1.4, Web 6.2.1, FTL 6.2.3 — thi
```
The same production run confirms:
+
- Backups are created before Pi-hole maintenance kicks in (e.g. `/etc/pihole/backup_20251025_100315`, `/etc/pihole/backup_20251025_100337`)
- The installer provisions the recommended cron automatically: `0 4 * * 0 /usr/local/bin/pihole_maintenance_pro.sh >>/var/log/pihole_maint_cron.log 2>&1`
- Security (Steps 20–26) and health checks (Steps 07–10) run green end-to-end
@@ -109,30 +117,32 @@ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
30 3 * * * /usr/local/bin/pihole_maintenance_pro.sh >> /var/log/pihole_maintenance_pro.log 2>&1
```
-> Trixie/cron runs with a reduced PATH. Using a full PATH ensures both scripts run reliably.
+> Trixie/cron runs with a reduced PATH. Using a full PATH ensures both scripts run reliably. The installer now sets the weekly cron idempotently.
## Pi-hole v6 API notes
-- setupVars.conf is gone
-- Config now lives in /etc/pihole/pihole.toml
-- API is served at /api instead of /api.php
-- Authentication is HTTP Basic Auth using cli plus the password in /etc/pihole/cli_pw
-- The healthcheck script (pihole_api_healthcheck.sh) can hit those endpoints locally when PIHOLE_API_URL is set
-- Unbound is not required
+- `setupVars.conf` is gone
+- Config lives in `/etc/pihole/pihole.toml`
+- API is served at `/api` instead of `/api.php`
+- Authentication uses session tokens: `POST /api/auth` returns `sid`, pass via header `X-FTL-SID`
+- The healthcheck script (`tools/pihole_api_healthcheck.sh`) can hit endpoints when `PIHOLE_API_URL` is set; set `PIHOLE_PASSWORD` to enable session login
+- Unbound is optional
## Troubleshooting
-* `sqlite3` toplists:
+- `sqlite3` toplists:
```bash
sudo apt update && sudo apt install -y sqlite3
```
+
* Locale warnings:
```bash
echo -e "en_GB.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8" | sudo tee /etc/locale.gen >/dev/null
sudo locale-gen && sudo update-locale LANG=de_DE.UTF-8 LC_ALL=de_DE.UTF-8
```
+
* Pi 3B note about `linux-image-rpi-v8`: ignorable on ARMv7.
## License
@@ -142,5 +152,6 @@ MIT. See [LICENSE](LICENSE).
*Last updated: 2025-10-25 • Version: 5.3.2*
## Support
+
If this project helps you, you can support it here:
[buymeacoffee.com/timintech](https://buymeacoffee.com/timintech)
diff --git a/assets/icons/README.md b/assets/icons/README.md
deleted file mode 100644
index 09145a4..0000000
--- a/assets/icons/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Local icon placeholder. No runtime dependency.
diff --git a/docs/Anleitung_DE.md b/docs/Anleitung_DE.md
index 2460a25..791d479 100644
--- a/docs/Anleitung_DE.md
+++ b/docs/Anleitung_DE.md
@@ -1,30 +1,50 @@
# Anleitung DE – Pi-hole Maintenance PRO MAX (v5.3.2)
-Nutzung:
- sudo /usr/local/bin/pihole_maintenance_pro.sh
- sudo /usr/local/bin/pihole_maintenance_pro.sh --no-apt --no-upgrade --no-gravity --no-dnsreload
-
-Installation:
- bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main/scripts/install.sh)"
-
-Cron:
- PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- */30 * * * * /usr/local/bin/pihole_api_healthcheck.sh >> /var/log/pihole_healthcheck.log 2>&1
- 30 3 * * * /usr/local/bin/pihole_maintenance_pro.sh >> /var/log/pihole_maintenance_pro.log 2>&1
-
-Hinweis:
- Trixie/Cron nutzt einen reduzierten PATH. Mit vollem PATH laufen beide Skripte zuverlässig.
-
-Troubleshooting kurz:
-- rfkill → do_wifi_country DE; optional rfkill block wifi
-- sqlite3 → apt install sqlite3
-- FTL-DB Rechte → sudo sqlite3 -readonly /etc/pihole/pihole-FTL.db "SELECT COUNT(*) FROM queries;"
-- Locale → locale-gen; update-locale LANG=de_DE.UTF-8 LC_ALL=de_DE.UTF-8
-
-Pi-hole v6 API:
- - Keine setupVars.conf mehr
- - Konfiguration jetzt in /etc/pihole/pihole.toml
- - API unter /api, nicht /api.php
- - Authentifizierung via Basic Auth mit User cli und Passwort aus /etc/pihole/cli_pw
- - Das Healthcheck-Skript pihole_api_healthcheck.sh kann lokal Basic-Auth gegen die API fahren, wenn PIHOLE_API_URL gesetzt ist
- - Unbound ist nicht erforderlich
+## Nutzung
+
+```bash
+sudo /usr/local/bin/pihole_maintenance_pro.sh
+sudo /usr/local/bin/pihole_maintenance_pro.sh --no-apt --no-upgrade --no-gravity --no-dnsreload
+```
+
+## Installation
+
+```bash
+bash -c "$(curl -fsSL https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main/scripts/install.sh)"
+```
+
+## Cron
+
+```cron
+PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+*/30 * * * * /usr/local/bin/pihole_api_healthcheck.sh >> /var/log/pihole_healthcheck.log 2>&1
+30 3 * * * /usr/local/bin/pihole_maintenance_pro.sh >> /var/log/pihole_maintenance_pro.log 2>&1
+```
+
+> Hinweis: Cron nutzt oft einen reduzierten PATH. Der vollständige PATH stellt sicher, dass beide Skripte korrekt laufen.
+
+## Troubleshooting (kurz)
+
+- rfkill → `do_wifi_country DE`; optional `rfkill block wifi`
+- sqlite3 installieren: `apt install -y sqlite3`
+- FTL-DB Rechte testen:
+
+ ```bash
+ sudo sqlite3 -readonly /etc/pihole/pihole-FTL.db "SELECT COUNT(*) FROM queries;"
+ ```
+
+- Locale setzen:
+
+ ```bash
+ echo -e "en_GB.UTF-8 UTF-8\nde_DE.UTF-8 UTF-8" | sudo tee /etc/locale.gen >/dev/null
+ sudo locale-gen && sudo update-locale LANG=de_DE.UTF-8 LC_ALL=de_DE.UTF-8
+ ```
+
+## Pi-hole v6 API
+
+- Keine `setupVars.conf` mehr
+- Konfiguration in `/etc/pihole/pihole.toml`
+- API unter `/api` (nicht `/api.php`)
+- Authentifizierung via Session: `POST /api/auth` → `sid`, danach Header `X-FTL-SID`
+- Healthcheck nutzt `PIHOLE_API_URL` und optional `PIHOLE_PASSWORD` für Login
+- Unbound ist optional
diff --git a/pihole_maintenance_pro.sh b/pihole_maintenance_pro.sh
index ef3e21d..5034933 100755
--- a/pihole_maintenance_pro.sh
+++ b/pihole_maintenance_pro.sh
@@ -45,18 +45,25 @@ WARN="${YELLOW}⚠${NC}"
FAIL="${RED}✖${NC}"
# --------------------------- Root check ------------------------------------
+# Für sicheren lokalen Selftest (RUN_SELFTEST=1) ohne Root erlauben
if [[ ${EUID} -ne 0 ]]; then
- echo -e "${RED}[ERROR]${NC} Bitte mit sudo oder als root ausführen." >&2
- exit 1
+ if [[ "${RUN_SELFTEST:-0}" == "1" ]]; then
+ echo -e "${YELLOW}Hinweis:${NC} RUN_SELFTEST=1 erkannt – Root-Check übersprungen (APT/Upgrade/Gravity sollten via --no-* Flags deaktiviert sein)."
+ else
+ echo -e "${RED}[ERROR]${NC} Bitte mit sudo oder als root ausführen." >&2
+ exit 1
+ fi
fi
# --------------------------- Args ------------------------------------------
DO_APT=1
DO_UPGRADE=1
DO_GRAVITY=1
-DO_DNSRELOAD=1
+# shellcheck disable=SC2034 # legacy flag (kept for help text compatibility)
+DO_DNSRELOAD=1 # no-op on v6, retained for help text compatibility
JSON_OUTPUT=0
DO_BACKUP=0
+RESTART_FTL=0
while (("$#")); do
case "$1" in
--no-apt)
@@ -72,9 +79,14 @@ while (("$#")); do
shift
;;
--no-dnsreload)
+ # shellcheck disable=SC2034 # legacy flag retained for help text compatibility
DO_DNSRELOAD=0
shift
;;
+ --restart-ftl)
+ RESTART_FTL=1
+ shift
+ ;;
--backup)
DO_BACKUP=1
shift
@@ -90,6 +102,7 @@ Usage: sudo ./pihole_maintenance_pro.sh [options]
--no-upgrade Skip "pihole -up"
--no-gravity Skip "pihole -g"
--no-dnsreload Skip "pihole reloaddns"
+ --restart-ftl Restart pihole-FTL at the end (v6: only if needed)
--json Output results in JSON format
EOF
exit 0
@@ -483,7 +496,8 @@ if ((DO_BACKUP == 1)); then
mkdir -p "$BACKUP_DIR"
cp -a /etc/pihole/gravity.db "$BACKUP_DIR" 2> /dev/null || true
cp -a /etc/pihole/pihole-FTL.db "$BACKUP_DIR" 2> /dev/null || true
- cp -a /etc/pihole/custom.list "$BACKUP_DIR" 2> /dev/null || true
+ cp -a /etc/pihole/pihole.toml "$BACKUP_DIR" 2> /dev/null || true
+ cp -a /etc/pihole/hosts/*.list "$BACKUP_DIR" 2> /dev/null || true
echo "Backup gespeichert: $BACKUP_DIR"
find /var/backups/pihole/ -maxdepth 1 -type d -printf '%T@ %p\n' | sort -n | awk '{print $2}' | head -n -$MAX_BACKUPS | xargs -r rm -rf
fi
@@ -492,7 +506,8 @@ backup_pihole() {
backup_dir="/etc/pihole/backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$backup_dir"
cp -a /etc/pihole/*.db "$backup_dir" 2> /dev/null || true
- cp -a /etc/pihole/*.conf "$backup_dir" 2> /dev/null || true
+ cp -a /etc/pihole/pihole.toml "$backup_dir" 2> /dev/null || true
+ cp -a /etc/pihole/hosts/*.list "$backup_dir" 2> /dev/null || true
echo "Backup erstellt: $backup_dir"
}
@@ -513,11 +528,9 @@ else
echo -e "${YELLOW}Gravity-Update übersprungen (--no-gravity).${NC}"
fi
-# 06 – DNS reload
-if ((DO_DNSRELOAD == 1)); then
- run_step 06 "🔁" "Reload DNS (reloaddns)" "\"$PIHOLE_BIN\" reloaddns"
-else
- echo -e "${YELLOW}DNS-Reload übersprungen (--no-dnsreload).${NC}"
+# 06 – optionaler FTL-Restart (v6: nur bei Bedarf)
+if ((RESTART_FTL == 1)); then
+ run_step 06 "🔁" "Restart FTL (v6: nur bei Bedarf)" "systemctl restart pihole-FTL"
fi
# 07 – Health
diff --git a/scripts/install.sh b/scripts/install.sh
index 8a52882..6983c01 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -1,5 +1,9 @@
#!/usr/bin/env bash
set -euo pipefail
+if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
+ echo "This installer requires root. Re-run with sudo." >&2
+ exit 1
+fi
TMP="$(mktemp -d)"
RAW_BASE="https://raw.githubusercontent.com/TimInTech/pihole-maintenance-pro/main"
SRC="$RAW_BASE/pihole_maintenance_pro.sh"
@@ -8,6 +12,28 @@ if ! curl -fsSL "$SRC" -o "$TMP/pihole_maintenance_pro.sh"; then
echo "✗ Download fehlgeschlagen: $SRC" >&2
exit 1
fi
-sudo install -m 0755 "$TMP/pihole_maintenance_pro.sh" "$OUT"
-echo "Cron (So 04:00): 0 4 * * 0 /usr/local/bin/pihole_maintenance_pro.sh >>/var/log/pihole_maint_cron.log 2>&1"
+install -m 0755 "$TMP/pihole_maintenance_pro.sh" "$OUT"
+
+# Healthcheck-Tool bereitstellen (robust, mit Fallback)
+HC_URL="$RAW_BASE/tools/pihole_api_healthcheck.sh"
+HC_TMP="$TMP/pihole_api_healthcheck.sh"
+HC_OUT="/usr/local/bin/pihole_api_healthcheck.sh"
+if curl -fsSL "$HC_URL" -o "$HC_TMP" || curl -fsSL "$HC_URL" -o "$HC_TMP"; then
+ install -m 0755 "$HC_TMP" "$HC_OUT"
+ echo "Installed: $HC_OUT"
+else
+ # Lokaler Fallback, falls Repo geklont ausgeführt wird
+ if [[ -r "$(dirname "$0")/../tools/pihole_api_healthcheck.sh" ]]; then
+ install -m 0755 "$(dirname "$0")/../tools/pihole_api_healthcheck.sh" "$HC_OUT"
+ echo "Installed from local repo: $HC_OUT"
+ else
+ echo "WARN: Healthcheck konnte nicht installiert werden (curl fehlgeschlagen, kein lokaler Fallback)." >&2
+ fi
+fi
+# Wöchentlicher Cron, idempotent
+(
+ crontab -l 2> /dev/null | grep -v 'pihole_maintenance_pro.sh'
+ echo "0 4 * * 0 /usr/local/bin/pihole_maintenance_pro.sh >>/var/log/pihole_maint_cron.log 2>&1"
+) | crontab -
+echo "Cron installed: Sundays 04:00"
echo "Troubleshooting: rfkill, sqlite3, FTL-DB-Rechte, Locale → README"
diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh
index f82f065..2237029 100755
--- a/scripts/uninstall.sh
+++ b/scripts/uninstall.sh
@@ -5,18 +5,28 @@
# ============================================================================
set -euo pipefail
IFS=$'\n\t'
+if [[ ${EUID:-$(id -u)} -ne 0 ]]; then
+ echo "This uninstaller requires root. Re-run with sudo." >&2
+ exit 1
+fi
+PURGE=0
+[[ "${1:-}" == "--purge" ]] && PURGE=1
echo "🗑️ Removing Pi-hole Maintenance PRO MAX..."
-# 1. Remove main script in /usr/local/bin
+# 1. Remove main script and healthcheck in /usr/local/bin
if [[ -f /usr/local/bin/pihole_maintenance_pro.sh ]]; then
- sudo rm -f /usr/local/bin/pihole_maintenance_pro.sh
+ rm -f /usr/local/bin/pihole_maintenance_pro.sh
echo "✔ Removed: /usr/local/bin/pihole_maintenance_pro.sh"
fi
+if [[ -f /usr/local/bin/pihole_api_healthcheck.sh ]]; then
+ rm -f /usr/local/bin/pihole_api_healthcheck.sh
+ echo "✔ Removed: /usr/local/bin/pihole_api_healthcheck.sh"
+fi
# 2. Remove logs and temporary files
-sudo rm -f /var/log/pihole_maintenance_pro_*.log 2> /dev/null || true
-sudo rm -rf /tmp/pihole_maint_* 2> /dev/null || true
+rm -f /var/log/pihole_maintenance_pro_*.log 2> /dev/null || true
+rm -rf /tmp/pihole_maint_* 2> /dev/null || true
echo "✔ Logs removed"
# 3. Clean up cronjob
@@ -27,10 +37,12 @@ else
echo "ℹ No cronjob found"
fi
-# 4. Remove backups (optional)
-if [[ -d /var/backups/pihole ]]; then
- sudo rm -rf /var/backups/pihole/
- echo "✔ Removed backups: /var/backups/pihole/"
+# 4. Remove backups (only when --purge)
+if ((PURGE)) && [[ -d /var/backups/pihole ]]; then
+ rm -rf /var/backups/pihole/
+ echo "✔ Removed backups: /var/backups/pihole/ (purge)"
+else
+ echo "ℹ Backups preserved (use --purge to remove)"
fi
-echo "✅ Uninstallation complete. System is clean."
+echo "✅ Uninstallation complete."
diff --git a/tools/pihole_api_healthcheck.sh b/tools/pihole_api_healthcheck.sh
index f6ed3b8..4c2ead1 100755
--- a/tools/pihole_api_healthcheck.sh
+++ b/tools/pihole_api_healthcheck.sh
@@ -1,17 +1,17 @@
#!/usr/bin/env bash
# ============================================================================
-# Pi-hole API Healthcheck (v6-ready)
+# Pi-hole API Healthcheck (v6-ready, session auth)
# Collects local diagnostics and (optionally) queries the Pi-hole v6 JSON API.
# Usage examples:
# bash tools/pihole_api_healthcheck.sh
# bash tools/pihole_api_healthcheck.sh --json
-# PIHOLE_API_URL="http://localhost/api" bash tools/pihole_api_healthcheck.sh
-# Note: Works without root, but sqlite3 + cli_pw access may require sudo.
+# PIHOLE_API_URL="http://localhost/api" PIHOLE_PASSWORD="..." bash tools/pihole_api_healthcheck.sh
+# Note: Works without root, but sqlite3 access may require sudo. For API calls
+# use session auth: export PIHOLE_API_URL and PIHOLE_PASSWORD.
# ============================================================================
set -euo pipefail
IFS=$'\n\t'
-CLI_PW_PATH="/etc/pihole/cli_pw"
FTL_DB_PATH="/etc/pihole/pihole-FTL.db"
JSON_OUTPUT=0
@@ -21,9 +21,9 @@ usage() {
Usage: pihole_api_healthcheck.sh [--json]
Collects local Pi-hole health metrics (CLI, FTL, DNS listeners, sqlite3 stats,
-temperature, load, memory, disk). When PIHOLE_API_URL is set and the Pi-hole
-CLI password is readable, performs authenticated Basic Auth requests (user
-"cli") against the Pi-hole v6 API endpoints /stats/summary and /stats/top_clients.
+temperature, load, memory, disk). When PIHOLE_API_URL is set, the script will
+attempt to authenticate using a session token (POST /api/auth) if
+PIHOLE_PASSWORD is provided, then query /stats/summary and /stats/top_clients.
Options:
--json Emit machine-readable JSON instead of human-readable text
@@ -226,7 +226,7 @@ fi
disk_used_pct=""
if command -v df > /dev/null 2>&1; then
- disk_used_pct="$(df -P / | awk 'NR==2 {gsub(\"%\", \"\", $5); print $5}')"
+ disk_used_pct="$(df -P / | awk 'NR==2 {gsub("%", "", $5); print $5}')"
fi
uptime_summary=""
@@ -235,15 +235,11 @@ if command -v uptime > /dev/null 2>&1; then
uptime_summary="${uptime_summary//$'\n'/}"
fi
-cli_password=""
-if [[ -r "$CLI_PW_PATH" ]]; then
- cli_password="$(tr -d '\r\n' < "$CLI_PW_PATH")"
-fi
+# Note: v6 recommends session-based auth; cli_pw is deprecated for API usage.
api_url="${PIHOLE_API_URL:-}"
[[ -n "$api_url" ]] && api_url="${api_url%/}"
api_status="API not queried (PIHOLE_API_URL unset)"
-api_used_basic_auth="false"
api_context=0
api_summary_body=""
api_summary_http=""
@@ -255,7 +251,24 @@ declare -a TOP_CLIENTS_API=()
api_total_override=""
api_blocked_override=""
api_percent_override=""
-auth_token=""
+SID=""
+
+# Perform session login (v6): POST /api/auth {"password":"..."} -> {"sid":"..."}
+api_login() {
+ local password="${PIHOLE_PASSWORD:-}"
+ [[ -z "$api_url" ]] && return 1
+ [[ -z "$password" ]] && return 2
+ local resp code
+ resp="$(curl -sS --connect-timeout 3 --max-time 7 -X POST "$api_url/api/auth" \
+ -H 'Content-Type: application/json' -d "{\"password\":\"${password}\"}" -w ' HTTP/%{http_code}')" || return 3
+ code="${resp##*HTTP/}"
+ resp="${resp% HTTP/*}"
+ if [[ "$code" == "200" ]]; then
+ SID="$(printf '%s' "$resp" | grep -oE '"sid"\s*:\s*"[^"]+"' | sed -E 's/.*"sid"\s*:\s*"([^"]+)".*/\1/')"
+ [[ -n "$SID" ]] && return 0
+ fi
+ return 4
+}
call_api_endpoint() {
local endpoint="$1" body_ref="$2" code_ref="$3" note_ref="$4"
@@ -265,9 +278,10 @@ call_api_endpoint() {
tmp_err="$(mktemp -t pihole_api_err_XXXX)"
TMP_FILES+=("$tmp_body" "$tmp_code" "$tmp_err")
- if ! curl -sS -m 7 \
- -H "Authorization: Basic $auth_token" \
- -H "Accept: application/json" \
+ local extra_headers=()
+ [[ -n "$SID" ]] && extra_headers+=(-H "X-FTL-SID: $SID")
+ if ! curl -sS --connect-timeout 3 --max-time 7 \
+ "${extra_headers[@]}" -H "Accept: application/json" \
-o "$tmp_body" \
-w '%{http_code}' \
"$api_url/$endpoint" > "$tmp_code" 2> "$tmp_err"; then
@@ -287,23 +301,17 @@ call_api_endpoint() {
}
if [[ -n "$api_url" ]]; then
- if [[ -z "$cli_password" ]]; then
- api_status="PIHOLE_API_URL set but $CLI_PW_PATH not readable"
- elif ! command -v curl > /dev/null 2>&1; then
+ if ! command -v curl > /dev/null 2>&1; then
api_status="curl not installed; skipping API calls"
- elif ! command -v base64 > /dev/null 2>&1; then
- api_status="base64 not installed; skipping API calls"
else
- auth_token="$(printf 'cli:%s' "$cli_password" | base64 | tr -d $'\n')"
- api_used_basic_auth="true"
api_context=1
- call_api_endpoint "stats/summary" api_summary_body api_summary_http api_summary_note
- call_api_endpoint "stats/top_clients" api_top_clients_body api_top_clients_http api_top_clients_note
- if [[ "$api_summary_http" == "200" || "$api_top_clients_http" == "200" ]]; then
- api_status="API queried with Basic Auth"
+ if api_login; then
+ api_status="API queried with Session Auth"
else
- api_status="API query attempted with Basic Auth (check endpoint details)"
+ api_status="API unauthenticated (no PIHOLE_PASSWORD or login failed)"
fi
+ call_api_endpoint "stats/summary" api_summary_body api_summary_http api_summary_note
+ call_api_endpoint "stats/top_clients" api_top_clients_body api_top_clients_http api_top_clients_note
fi
fi
@@ -613,7 +621,7 @@ print_json() {
printf '"api":{'
printf '"url":"%s",' "$(json_escape "$api_url")"
printf '"status":"%s",' "$(json_escape "$api_status")"
- printf '"used_basic_auth":%s,' "$([[ "$api_used_basic_auth" == "true" ]] && echo "true" || echo "false")"
+ printf '"auth":"%s",' "$([[ -n "$SID" ]] && echo "session" || echo "none")"
printf '"summary_http_code":%s,' "$(json_http_code_or_null "$api_summary_http")"
printf '"summary_error":%s,' "$(json_string_or_null "$api_summary_note")"
printf '"top_clients_http_code":%s,' "$(json_http_code_or_null "$api_top_clients_http")"