Initial commit: Pi-hole baremetal one-liner installer

- Supports Ubuntu, Debian, Fedora, Rocky, CentOS, RHEL, Arch, openSUSE
- Automatic OS detection and dependency installation
- Automatic network interface and IP detection
- Configurable upstream DNS servers
- Firewall configuration (firewalld/ufw/iptables)
- Management helper script (pihole-manage)
- Unattended installation option
- FreeBSD redirects to AdGuard Home alternative
This commit is contained in:
Vish
2026-01-18 08:12:38 +00:00
commit ce5674cb6c
4 changed files with 896 additions and 0 deletions

17
.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
# OS files
.DS_Store
Thumbs.db
# Editor files
*.swp
*.swo
*~
.idea/
.vscode/
# Logs
*.log
# Temp files
*.tmp
*.bak

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Vish
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

212
README.md Normal file
View File

@@ -0,0 +1,212 @@
# pihole-baremetal
One-command Pi-hole installation on bare metal - network-wide ad blocking DNS server.
## Quick Install
```bash
curl -fsSL -H "Authorization: token 77e3ddaf262bb94f6fa878ca449cc1aa1129a00d" \
"https://git.vish.gg/Vish/pihole-baremetal/raw/branch/main/install.sh" | sudo bash
```
### Install Options
```bash
# Fully unattended (no prompts, uses defaults)
curl ... | sudo bash -s -- --unattended
# Without web interface (DNS only)
curl ... | sudo bash -s -- --no-lighttpd
# Custom upstream DNS
curl ... | sudo bash -s -- --dns1 8.8.8.8 --dns2 8.8.4.4
# Specify interface and IP
curl ... | sudo bash -s -- --interface eth0 --ipv4 192.168.1.10/24
# Force install on unsupported OS
curl ... | sudo bash -s -- --skip-os-check --unattended
# Combine options
curl ... | sudo bash -s -- --unattended --dns1 9.9.9.9 --dns2 149.112.112.112
```
## What It Does
**Zero intervention required.** The installer automatically:
- Detects your OS (Ubuntu, Debian, Fedora, Rocky, CentOS, Arch, openSUSE)
- Installs all required dependencies
- Detects your network interface and IP address
- Configures Pi-hole with sensible defaults
- Sets up firewall rules (firewalld/ufw/iptables)
- Creates a management helper script
**Run one command, wait 2-3 minutes, done.**
## Supported Systems
| OS | Version | Status |
|----|---------|--------|
| Ubuntu | 20.04, 22.04, 24.04+ | ✅ Official |
| Debian | 10, 11, 12+ | ✅ Official |
| Raspberry Pi OS | All | ✅ Official |
| Fedora | 38+ | ✅ Official |
| CentOS / RHEL | 8, 9+ | ✅ Official |
| Rocky Linux | 8, 9+ | ✅ Official |
| AlmaLinux | 8, 9+ | ✅ Official |
| Linux Mint | 20, 21, 22+ | ✅ Works |
| Pop!_OS | 22.04+ | ✅ Works |
| Arch Linux | Rolling | ⚠️ Experimental |
| Manjaro | Rolling | ⚠️ Experimental |
| openSUSE | Leap/Tumbleweed | ⚠️ Experimental |
| FreeBSD | - | ❌ Use AdGuard Home |
## Services & Ports
| Service | Port | Description |
|---------|------|-------------|
| DNS | 53/tcp, 53/udp | DNS resolver |
| Web Admin | 80/tcp | Admin interface |
| FTL | 4711/tcp | Pi-hole FTL API |
## Post-Install Configuration
### Set Admin Password
```bash
pihole -a -p
```
### Configure Clients
Set your devices or router's DNS server to your Pi-hole's IP address.
**Router (recommended):** Set Pi-hole IP as the primary DNS in your router's DHCP settings. All devices will automatically use Pi-hole.
**Individual devices:** Manually set DNS to Pi-hole IP in network settings.
### Add Custom Blocklists
1. Open Admin Panel → Group Management → Adlists
2. Add URLs of blocklists
3. Run `pihole -g` to update gravity
Popular blocklist sources:
- https://firebog.net/ (curated lists)
- https://github.com/StevenBlack/hosts
## Management Commands
### Native Pi-hole Commands
```bash
pihole status # Show status
pihole -c # Console dashboard (live)
pihole -up # Update Pi-hole
pihole -g # Update blocklists (gravity)
pihole -q example.com # Query logs for domain
pihole -w example.com # Whitelist domain
pihole -b example.com # Blacklist domain
pihole enable # Enable blocking
pihole disable # Disable blocking
pihole disable 5m # Disable for 5 minutes
pihole restartdns # Restart DNS resolver
pihole -a -p # Change admin password
pihole -t # Tail the log
```
### Helper Script Commands
```bash
pihole-manage status # Show Pi-hole and service status
pihole-manage logs # Tail Pi-hole log
pihole-manage ftl-logs # Tail FTL log
pihole-manage stats # Show statistics
pihole-manage top-ads # Show top blocked domains
pihole-manage gravity # Update blocklists
pihole-manage backup # Create backup
pihole-manage password # Change admin password
```
## File Locations
| Path | Description |
|------|-------------|
| `/etc/pihole/` | Pi-hole configuration |
| `/etc/pihole/setupVars.conf` | Installation settings |
| `/etc/pihole/custom.list` | Local DNS records |
| `/etc/dnsmasq.d/` | Dnsmasq configuration |
| `/var/log/pihole/` | Log files |
| `/var/log/pihole/pihole.log` | Query log |
| `/var/log/pihole/FTL.log` | FTL engine log |
| `/opt/pihole/` | Pi-hole scripts |
## Troubleshooting
### Check if Pi-hole is running
```bash
pihole status
systemctl status pihole-FTL
```
### DNS not resolving
```bash
# Check if FTL is listening
ss -tulpn | grep ':53'
# Test DNS resolution
dig @127.0.0.1 google.com
# Restart services
pihole restartdns
```
### Web interface not loading
```bash
# Check lighttpd status
systemctl status lighttpd
# Restart lighttpd
systemctl restart lighttpd
```
### View logs for errors
```bash
pihole -t # Tail query log
tail -f /var/log/pihole/FTL.log # FTL log
journalctl -u pihole-FTL -f # Systemd journal
```
### Reset admin password
```bash
pihole -a -p
```
## Uninstall
```bash
pihole uninstall
```
This will remove Pi-hole and optionally its dependencies.
## Upstream DNS Options
| Provider | DNS 1 | DNS 2 |
|----------|-------|-------|
| Cloudflare | 1.1.1.1 | 1.0.0.1 |
| Google | 8.8.8.8 | 8.8.4.4 |
| Quad9 | 9.9.9.9 | 149.112.112.112 |
| OpenDNS | 208.67.222.222 | 208.67.220.220 |
| Cloudflare (malware) | 1.1.1.2 | 1.0.0.2 |
| Cloudflare (family) | 1.1.1.3 | 1.0.0.3 |
## License
MIT

646
install.sh Normal file
View File

@@ -0,0 +1,646 @@
#!/bin/bash
# =============================================================================
# Pi-hole Baremetal Installer
# =============================================================================
# Network-wide ad blocking DNS server - installs directly on the system
#
# Supported: Ubuntu, Debian, Fedora, Rocky/Alma/RHEL 8+, Arch, openSUSE, FreeBSD
# Works on minimal/headless installs
#
# Usage:
# curl -fsSL <url>/install.sh | sudo bash
#
# Options:
# --unattended Skip all prompts, use defaults
# --no-lighttpd Skip web server (API/admin only via CLI)
# --set-password Set admin password non-interactively (reads from stdin)
# --ipv4 <ip> Set static IPv4 address
# --interface <if> Set network interface (e.g., eth0)
# --dns1 <ip> Set upstream DNS 1 (default: 1.1.1.1)
# --dns2 <ip> Set upstream DNS 2 (default: 1.0.0.1)
# =============================================================================
set -o pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
log() { echo -e "${BLUE}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[OK]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; exit 1; }
# Configuration defaults
UNATTENDED=false
INSTALL_LIGHTTPD=true
PIHOLE_DNS_1="1.1.1.1"
PIHOLE_DNS_2="1.0.0.1"
INTERFACE=""
IPV4_ADDRESS=""
ADMIN_PASSWORD=""
INSTALL_DIR="/etc/pihole"
PIHOLE_SKIP_OS_CHECK=false
# Parse arguments
while [ $# -gt 0 ]; do
case $1 in
--unattended) UNATTENDED=true; shift ;;
--no-lighttpd) INSTALL_LIGHTTPD=false; shift ;;
--set-password) ADMIN_PASSWORD="$2"; shift 2 ;;
--ipv4) IPV4_ADDRESS="$2"; shift 2 ;;
--interface) INTERFACE="$2"; shift 2 ;;
--dns1) PIHOLE_DNS_1="$2"; shift 2 ;;
--dns2) PIHOLE_DNS_2="$2"; shift 2 ;;
--skip-os-check) PIHOLE_SKIP_OS_CHECK=true; shift ;;
--help|-h)
echo "Pi-hole Baremetal Installer"
echo ""
echo "Usage: install.sh [options]"
echo ""
echo "Options:"
echo " --unattended Skip prompts, use defaults"
echo " --no-lighttpd Skip web server installation"
echo " --set-password X Set admin password"
echo " --ipv4 <ip> Set static IPv4 (e.g., 192.168.1.10/24)"
echo " --interface <if> Set interface (e.g., eth0)"
echo " --dns1 <ip> Upstream DNS 1 (default: 1.1.1.1)"
echo " --dns2 <ip> Upstream DNS 2 (default: 1.0.0.1)"
echo " --skip-os-check Skip OS compatibility check"
exit 0
;;
*) shift ;;
esac
done
# Check root
[ "$(id -u)" -ne 0 ] && error "Run as root: sudo bash install.sh"
# Detect OS
detect_os() {
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
OS_VERSION=${VERSION_ID:-}
OS_NAME="${NAME:-$OS}"
elif [ "$(uname)" = "FreeBSD" ]; then
OS="freebsd"
OS_VERSION=$(freebsd-version -u 2>/dev/null | cut -d'-' -f1)
OS_NAME="FreeBSD"
else
error "Cannot detect OS"
fi
log "Detected: $OS_NAME $OS_VERSION"
}
# Check if OS is supported by official Pi-hole installer
check_pihole_support() {
case $OS in
ubuntu|debian|raspbian)
# Supported versions
return 0
;;
fedora)
return 0
;;
centos|rhel|rocky|almalinux)
return 0
;;
*)
if [ "$PIHOLE_SKIP_OS_CHECK" = true ]; then
warn "OS '$OS' may not be officially supported by Pi-hole"
warn "Attempting installation anyway (--skip-os-check enabled)"
return 0
else
return 1
fi
;;
esac
}
# Wait for apt/dpkg locks
wait_for_apt_lock() {
local max_wait=120
local waited=0
while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1 || \
fuser /var/lib/apt/lists/lock >/dev/null 2>&1 || \
fuser /var/lib/dpkg/lock >/dev/null 2>&1; do
if [ $waited -eq 0 ]; then
log "Waiting for apt/dpkg lock to be released..."
fi
sleep 5
waited=$((waited + 5))
if [ $waited -ge $max_wait ]; then
warn "Timeout waiting for apt lock, attempting to continue..."
break
fi
done
}
# Wait for zypper lock
wait_for_zypper_lock() {
local max_wait=120
local waited=0
while pgrep -x zypper >/dev/null 2>&1; do
if [ $waited -eq 0 ]; then
log "Waiting for zypper lock to be released..."
fi
sleep 5
waited=$((waited + 5))
if [ $waited -ge $max_wait ]; then
warn "Timeout waiting for zypper lock..."
break
fi
done
}
# Install prerequisites
install_prerequisites() {
log "Installing prerequisites..."
case $OS in
ubuntu|debian|raspbian|linuxmint|pop)
export DEBIAN_FRONTEND=noninteractive
wait_for_apt_lock
apt-get update -qq
apt-get install -y -qq curl ca-certificates git iproute2 procps >/dev/null 2>&1
;;
fedora)
dnf install -y -q curl ca-certificates git iproute procps-ng >/dev/null 2>&1
;;
rocky|almalinux|rhel|centos)
if command -v dnf >/dev/null 2>&1; then
dnf install -y -q curl ca-certificates git iproute procps-ng >/dev/null 2>&1
else
yum install -y curl ca-certificates git iproute procps >/dev/null 2>&1
fi
;;
arch|manjaro|endeavouros)
pacman -Sy --noconfirm --quiet curl ca-certificates git iproute2 procps-ng >/dev/null 2>&1
;;
opensuse*|sles)
wait_for_zypper_lock
zypper install -y curl ca-certificates git iproute2 procps >/dev/null 2>&1
;;
freebsd)
env ASSUME_ALWAYS_YES=YES pkg bootstrap >/dev/null 2>&1 || true
pkg install -y bash curl git ca_root_nss >/dev/null 2>&1
;;
*)
warn "Unknown OS, attempting to continue..."
;;
esac
success "Prerequisites installed"
}
# Detect network interface
detect_interface() {
if [ -n "$INTERFACE" ]; then
return
fi
# Try to find the default interface
INTERFACE=$(ip route get 8.8.8.8 2>/dev/null | grep -oP 'dev \K\S+' | head -1)
if [ -z "$INTERFACE" ]; then
# Fallback: get first non-loopback interface
INTERFACE=$(ip -o link show | awk -F': ' '$2 != "lo" {print $2; exit}')
fi
if [ -z "$INTERFACE" ]; then
INTERFACE="eth0"
fi
log "Using interface: $INTERFACE"
}
# Detect IP address
detect_ip() {
if [ -n "$IPV4_ADDRESS" ]; then
return
fi
# Get current IP on the detected interface
IPV4_ADDRESS=$(ip -4 addr show "$INTERFACE" 2>/dev/null | grep -oP 'inet \K[\d.]+/\d+' | head -1)
if [ -z "$IPV4_ADDRESS" ]; then
# Fallback: get any non-loopback IP
IPV4_ADDRESS=$(hostname -I 2>/dev/null | awk '{print $1}')
if [ -n "$IPV4_ADDRESS" ]; then
IPV4_ADDRESS="${IPV4_ADDRESS}/24"
fi
fi
if [ -z "$IPV4_ADDRESS" ]; then
error "Could not detect IP address. Use --ipv4 to specify."
fi
log "Using IP: $IPV4_ADDRESS"
}
# Get gateway
detect_gateway() {
GATEWAY=$(ip route | grep default | awk '{print $3}' | head -1)
if [ -z "$GATEWAY" ]; then
GATEWAY="192.168.1.1"
fi
log "Gateway: $GATEWAY"
}
# Create Pi-hole setup vars for unattended install
create_setupvars() {
log "Creating Pi-hole configuration..."
mkdir -p "$INSTALL_DIR"
# Extract IP without CIDR for some settings
IP_ONLY=$(echo "$IPV4_ADDRESS" | cut -d'/' -f1)
cat > "$INSTALL_DIR/setupVars.conf" << EOF
PIHOLE_INTERFACE=$INTERFACE
IPV4_ADDRESS=$IPV4_ADDRESS
IPV6_ADDRESS=
PIHOLE_DNS_1=$PIHOLE_DNS_1
PIHOLE_DNS_2=$PIHOLE_DNS_2
QUERY_LOGGING=true
INSTALL_WEB_SERVER=$( [ "$INSTALL_LIGHTTPD" = true ] && echo "true" || echo "false" )
INSTALL_WEB_INTERFACE=$( [ "$INSTALL_LIGHTTPD" = true ] && echo "true" || echo "false" )
LIGHTTPD_ENABLED=$( [ "$INSTALL_LIGHTTPD" = true ] && echo "true" || echo "false" )
CACHE_SIZE=10000
DNS_FQDN_REQUIRED=true
DNS_BOGUS_PRIV=true
DNSMASQ_LISTENING=local
WEBPASSWORD=
BLOCKING_ENABLED=true
EOF
success "Configuration created at $INSTALL_DIR/setupVars.conf"
}
# Install Pi-hole using official installer
install_pihole_official() {
log "Installing Pi-hole (official installer)..."
# Download and run official installer
if [ "$UNATTENDED" = true ]; then
curl -sSL https://install.pi-hole.net | bash /dev/stdin --unattended
else
curl -sSL https://install.pi-hole.net | bash
fi
if [ $? -ne 0 ]; then
error "Pi-hole installation failed"
fi
success "Pi-hole installed successfully"
}
# Install Pi-hole on Arch Linux (manual process)
install_pihole_arch() {
log "Installing Pi-hole on Arch Linux..."
# Install dependencies
pacman -Sy --noconfirm --needed \
php php-cgi php-sqlite php-intl \
lighttpd \
base-devel git \
dnsmasq \
sudo \
inetutils >/dev/null 2>&1
# Clone Pi-hole from AUR or use manual install
if command -v yay >/dev/null 2>&1; then
log "Using yay to install Pi-hole from AUR..."
sudo -u nobody yay -S --noconfirm pi-hole-server pi-hole-ftl 2>/dev/null || true
elif command -v paru >/dev/null 2>&1; then
log "Using paru to install Pi-hole from AUR..."
sudo -u nobody paru -S --noconfirm pi-hole-server pi-hole-ftl 2>/dev/null || true
fi
# If AUR helpers failed or not available, try official installer with skip
if ! command -v pihole >/dev/null 2>&1; then
warn "AUR installation failed, trying official installer..."
export PIHOLE_SKIP_OS_CHECK=true
curl -sSL https://install.pi-hole.net | PIHOLE_SKIP_OS_CHECK=true bash /dev/stdin --unattended
fi
success "Pi-hole installed on Arch Linux"
}
# Install Pi-hole on openSUSE
install_pihole_opensuse() {
log "Installing Pi-hole on openSUSE..."
wait_for_zypper_lock
# Install dependencies
zypper install -y \
php8 php8-cgi php8-sqlite php8-intl \
lighttpd \
git curl \
dnsmasq \
iproute2 >/dev/null 2>&1
# Try official installer with skip
export PIHOLE_SKIP_OS_CHECK=true
curl -sSL https://install.pi-hole.net | PIHOLE_SKIP_OS_CHECK=true bash /dev/stdin --unattended
success "Pi-hole installed on openSUSE"
}
# Install Pi-hole on FreeBSD
install_pihole_freebsd() {
log "Installing Pi-hole on FreeBSD..."
echo ""
echo "========================================"
echo " FreeBSD Pi-hole Installation"
echo "========================================"
echo ""
echo "FreeBSD is not officially supported by Pi-hole."
echo ""
echo "Alternatives for FreeBSD:"
echo ""
echo "1. Use AdGuard Home (better FreeBSD support):"
echo " pkg install adguardhome"
echo " sysrc adguardhome_enable=YES"
echo " service adguardhome start"
echo " # Access at http://localhost:3000"
echo ""
echo "2. Use Unbound + blocklists manually"
echo ""
echo "3. Run Pi-hole in a Linux jail (bhyve/vm)"
echo ""
# Offer to install AdGuard Home instead
if [ "$UNATTENDED" != true ]; then
read -p "Install AdGuard Home instead? [Y/n] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
pkg install -y adguardhome
sysrc adguardhome_enable=YES
service adguardhome start
success "AdGuard Home installed! Access at http://localhost:3000"
exit 0
fi
fi
error "FreeBSD is not supported for Pi-hole baremetal installation"
}
# Configure firewall
configure_firewall() {
log "Configuring firewall..."
if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld 2>/dev/null; then
firewall-cmd --permanent --add-service=dns 2>/dev/null || true
firewall-cmd --permanent --add-service=http 2>/dev/null || true
firewall-cmd --permanent --add-service=https 2>/dev/null || true
firewall-cmd --permanent --add-port=53/tcp 2>/dev/null || true
firewall-cmd --permanent --add-port=53/udp 2>/dev/null || true
firewall-cmd --permanent --add-port=80/tcp 2>/dev/null || true
firewall-cmd --permanent --add-port=4711/tcp 2>/dev/null || true # FTL
firewall-cmd --reload 2>/dev/null || true
success "Firewall configured (firewalld)"
elif command -v ufw >/dev/null 2>&1 && ufw status | grep -q "active"; then
ufw allow 53/tcp 2>/dev/null || true
ufw allow 53/udp 2>/dev/null || true
ufw allow 80/tcp 2>/dev/null || true
ufw allow 4711/tcp 2>/dev/null || true
success "Firewall configured (ufw)"
elif command -v iptables >/dev/null 2>&1; then
# Basic iptables rules
iptables -A INPUT -p tcp --dport 53 -j ACCEPT 2>/dev/null || true
iptables -A INPUT -p udp --dport 53 -j ACCEPT 2>/dev/null || true
iptables -A INPUT -p tcp --dport 80 -j ACCEPT 2>/dev/null || true
iptables -A INPUT -p tcp --dport 4711 -j ACCEPT 2>/dev/null || true
success "Firewall rules added (iptables)"
else
warn "No firewall detected, skipping configuration"
fi
}
# Set admin password
set_admin_password() {
if [ -n "$ADMIN_PASSWORD" ]; then
log "Setting admin password..."
pihole -a -p "$ADMIN_PASSWORD"
success "Admin password set"
elif [ "$UNATTENDED" != true ]; then
echo ""
echo "Set your Pi-hole admin password:"
pihole -a -p
fi
}
# Create management script
create_management_script() {
log "Creating management script..."
cat > /usr/local/bin/pihole-manage << 'EOFSCRIPT'
#!/bin/bash
# Pi-hole management helper
case "${1:-help}" in
status)
echo "=== Pi-hole Status ==="
pihole status
echo ""
echo "=== Service Status ==="
systemctl status pihole-FTL --no-pager 2>/dev/null || service pihole-FTL status
;;
logs)
tail -f /var/log/pihole/pihole.log
;;
ftl-logs)
tail -f /var/log/pihole/FTL.log
;;
query)
shift
pihole -q "$@"
;;
update)
pihole -up
;;
restart)
pihole restartdns
;;
disable)
duration="${2:-}"
if [ -n "$duration" ]; then
pihole disable "$duration"
else
pihole disable
fi
;;
enable)
pihole enable
;;
stats)
pihole -c -e
;;
top-ads)
echo "=== Top Blocked Domains ==="
pihole -t
;;
top-clients)
sqlite3 /etc/pihole/pihole-FTL.db \
"SELECT client, COUNT(*) as count FROM queries GROUP BY client ORDER BY count DESC LIMIT 10;" 2>/dev/null || \
echo "Database query not available"
;;
whitelist)
shift
pihole -w "$@"
;;
blacklist)
shift
pihole -b "$@"
;;
gravity)
pihole -g
;;
backup)
timestamp=$(date +"%Y%m%d_%H%M%S")
backup_dir="/var/backups/pihole"
mkdir -p "$backup_dir"
pihole -a -t "$backup_dir/pihole_backup_$timestamp.tar.gz"
echo "Backup created: $backup_dir/pihole_backup_$timestamp.tar.gz"
;;
password)
pihole -a -p
;;
*)
echo "Pi-hole Management Helper"
echo ""
echo "Usage: pihole-manage <command>"
echo ""
echo "Commands:"
echo " status Show Pi-hole and service status"
echo " logs Tail the Pi-hole log"
echo " ftl-logs Tail the FTL log"
echo " query <d> Query the log for domain <d>"
echo " update Update Pi-hole"
echo " restart Restart DNS resolver"
echo " disable [t] Disable blocking (optionally for t seconds)"
echo " enable Enable blocking"
echo " stats Show statistics"
echo " top-ads Show top blocked domains"
echo " whitelist Add domain to whitelist"
echo " blacklist Add domain to blacklist"
echo " gravity Update blocklists"
echo " backup Create configuration backup"
echo " password Change admin password"
echo ""
echo "Pi-hole native commands: pihole -h"
;;
esac
EOFSCRIPT
chmod +x /usr/local/bin/pihole-manage
success "Management script created: pihole-manage"
}
# Show completion message
show_complete() {
local IP=$(echo "$IPV4_ADDRESS" | cut -d'/' -f1)
if [ -z "$IP" ]; then
IP=$(hostname -I 2>/dev/null | awk '{print $1}')
fi
echo ""
echo "========================================"
echo " Pi-hole Installation Complete!"
echo "========================================"
echo ""
echo "Access:"
echo " Admin Panel: http://$IP/admin"
echo " DNS Server: $IP"
echo ""
echo "Configuration:"
echo " Interface: $INTERFACE"
echo " IPv4: $IPV4_ADDRESS"
echo " Upstream DNS: $PIHOLE_DNS_1, $PIHOLE_DNS_2"
echo ""
echo "Commands:"
echo " pihole status - Check status"
echo " pihole -c - Console dashboard"
echo " pihole -up - Update Pi-hole"
echo " pihole -g - Update gravity (blocklists)"
echo " pihole-manage help - Management helper"
echo ""
echo "Client Configuration:"
echo " Set your devices/router DNS to: $IP"
echo ""
if [ -z "$ADMIN_PASSWORD" ] && [ "$UNATTENDED" = true ]; then
echo "⚠️ Set admin password:"
echo " pihole -a -p"
echo ""
fi
echo "Logs: /var/log/pihole/"
echo "Config: /etc/pihole/"
echo ""
}
# Main installation
main() {
echo ""
echo "========================================"
echo " Pi-hole Baremetal Installer"
echo "========================================"
echo ""
detect_os
install_prerequisites
detect_interface
detect_ip
detect_gateway
# Create config for unattended install
if [ "$UNATTENDED" = true ]; then
create_setupvars
fi
# Route to appropriate installer
case $OS in
ubuntu|debian|raspbian|fedora|centos|rhel|rocky|almalinux)
install_pihole_official
;;
arch|manjaro|endeavouros)
install_pihole_arch
;;
opensuse*|sles)
install_pihole_opensuse
;;
freebsd)
install_pihole_freebsd
;;
linuxmint|pop)
# Mint and Pop are Ubuntu-based, should work
install_pihole_official
;;
*)
if [ "$PIHOLE_SKIP_OS_CHECK" = true ]; then
warn "Attempting installation on unsupported OS: $OS"
install_pihole_official
else
error "Unsupported OS: $OS. Use --skip-os-check to force installation."
fi
;;
esac
configure_firewall
set_admin_password
create_management_script
show_complete
}
main "$@"