Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/damianiglesias/pihole-ubuntu-deploy/llms.txt

Use this file to discover all available pages before exploring further.

deploy.sh is the main installer script for Pi-hole Ubuntu Deploy (version 4.1, authored by Damian Iglesias). It must be run as root (sudo ./deploy.sh) and performs a fully interactive, sequential installation with [y/n] prompts for each optional component.

Usage

sudo ./deploy.sh
The script checks for root privileges at startup using an EUID check. If it is not run as root, it prints an error and exits immediately: ERROR: Please run as root (sudo ./deploy.sh)

Requirements

  • Must be run as root (EUID check — exits with error if not root)
  • Internet connection required — the script pings 8.8.8.8 before proceeding; if no response, the installer exits with a fatal error
  • OS: Ubuntu Server 20.04, 22.04, or 24.04 (LTS recommended)
  • Minimum resources: 512 MB RAM, 1 CPU core

Installation Steps Reference

Every numbered step in deploy.sh is listed below in execution order.
StepLabelWhat it does
1Network PrepStops and disables systemd-resolved, overwrites /etc/resolv.conf with 8.8.8.8 and 1.1.1.1, then pings 8.8.8.8 to verify internet connectivity
2DependenciesRuns apt-get update then installs: curl, net-tools, ufw, sqlite3, wget, python3, python3-venv, python3-pip, git
3Pi-hole InstallRuns the official Pi-hole installer via curl -sSL https://install.pi-hole.net | bash; verifies success with a command -v pihole check
3.5Blocklists (opt)Injects 3 blocklists directly into gravity.db via sqlite3, then runs pihole -g to rebuild gravity
4PasswordPrompts for a web admin password with confirmation loop; applies it via pihole setpassword, then restarts pihole-FTL
4.5Unbound (opt)Installs unbound, downloads root.hints from internic.net to /var/lib/unbound/, writes /etc/unbound/unbound.conf.d/pi-hole.conf, restarts unbound
4.8PADD (opt)Downloads padd.sh from GitHub to /usr/local/bin/padd, makes it executable; optionally appends an SSH auto-start line to ~/.bashrc
4.9DNS Manager (opt)Clones pihole_dns from Codeberg to /opt/pihole-dns-manager/, creates a Python venv, installs requests, generates run_dns_sync.sh
4.7Log2Ram (opt)Adds the Azlux APT repository, installs log2ram; activates on next reboot
5FirewallRuns ufw allow 22/tcp, ufw allow 53, ufw allow 80/tcp; enables UFW non-interactively
6Static IPLists network interfaces, prompts for selection, detects current IP and gateway, writes /etc/netplan/99-pihole-static.yaml, applies with netplan apply
1

Network Prep (Step 1)

Before any packages are installed, the script frees port 53 by stopping systemd-resolved and forces DNS to Google’s public resolvers so that apt and curl can reach the internet.
systemctl stop systemd-resolved
systemctl disable systemd-resolved
rm -f /etc/resolv.conf
echo "nameserver 8.8.8.8" > /etc/resolv.conf
echo "nameserver 1.1.1.1" >> /etc/resolv.conf
2

Dependencies (Step 2)

Installs all required system packages in a single apt-get call. Exits with error if apt-get update fails.
apt-get install curl net-tools ufw sqlite3 wget python3 python3-venv python3-pip git -y
3

Pi-hole Core Install (Step 3)

Runs the official Pi-hole installer. The script pauses and asks the user to press [ENTER] before launching, instructing them to accept defaults in the blue TUI screens.
curl -sSL https://install.pi-hole.net | bash
After the installer finishes, the script verifies Pi-hole is available with:
if ! command -v pihole &> /dev/null; then exit 1; fi
4

Password Setup (Step 4)

Prompts for a new admin password with a masked input loop that re-prompts on mismatch or empty input. The password is passed directly to pihole setpassword and pihole-FTL is restarted.
5

Firewall (Step 5)

Configures UFW with the minimum required rules for Pi-hole operation, then enables it:
ufw allow 22/tcp
ufw allow 53
ufw allow 80/tcp
echo "y" | ufw enable
6

Static IP (Step 6)

Displays all non-loopback interfaces, reads the current IP and default gateway, and writes a Netplan configuration. Existing Netplan YAML files are backed up to /etc/netplan/backup/ before any changes are made.

Optional Component Prompts

Each optional component is gated behind a [y/n] prompt. The table below lists each prompt in the order it appears, the shell variable that stores the answer, and what is installed.
PromptVariableWhat it installs
Install Advanced Lists? [y/n]list_choice3 blocklists injected into gravity.db via sqlite3
Install Unbound? [y/n]unbound_choiceunbound package, root.hints, /etc/unbound/unbound.conf.d/pi-hole.conf
Install PADD dashboard? [y/n]padd_choice/usr/local/bin/padd
Auto-start PADD on SSH login? [y/n]auto_paddSSH conditional appended to ~/.bashrc
Install DNS Manager tool? [y/n]dns_tool_choice/opt/pihole-dns-manager/ Python environment
Install Log2Ram? [y/n]log2ram_choicelog2ram via Azlux APT repository
Set this IP as STATIC? [y/n]static_choice/etc/netplan/99-pihole-static.yaml

Blocklist URLs

These three blocklists are injected into Pi-hole’s gravity.db when the Advanced Lists option is selected (Step 3.5).
URLLabel
https://raw.githubusercontent.com/StevenBlack/hosts/master/hostsStevenBlack Unified
https://v.firebog.net/hosts/AdguardDNS.txtAdguard Mobile
https://v.firebog.net/hosts/Easyprivacy.txtEasyPrivacy Tracking
The lists are inserted with INSERT OR IGNORE to avoid duplicates, then pihole -g is run to rebuild the gravity database.

Generated Files

deploy.sh creates or modifies the following files on the system. Files marked (opt) are only created when the corresponding component is selected.
FileCreated byNotes
/etc/resolv.confStep 1Overwritten with nameserver 8.8.8.8 and nameserver 1.1.1.1
/etc/pihole/gravity.dbStep 3.5 (opt)Blocklist rows injected via sqlite3
/etc/unbound/unbound.conf.d/pi-hole.confStep 4.5 (opt)Unbound configuration listening on 127.0.0.1:5335
/var/lib/unbound/root.hintsStep 4.5 (opt)Root nameserver hints downloaded from internic.net
/usr/local/bin/paddStep 4.8 (opt)PADD terminal dashboard executable
~/.bashrcStep 4.8 (opt)SSH auto-start line appended (only if PADD + auto-start both selected)
/opt/pihole-dns-manager/Step 4.9 (opt)DNS Manager project directory with Python venv
/opt/pihole-dns-manager/run_dns_sync.shStep 4.9 (opt)Launcher script with PIHOLE_URL and PIHOLE_PASSWORD pre-filled
/opt/pihole-dns-manager/entries.txtStep 4.9 (opt)Sample DNS entries file (# Format: IP Domain)
/etc/apt/sources.list.d/azlux.listStep 4.7 (opt)Azlux APT repository for Log2Ram
/etc/netplan/99-pihole-static.yamlStep 6 (opt)Static IP Netplan configuration (mode 0600)
/etc/netplan/backup/Step 6 (opt)Backup of pre-existing Netplan YAML files

Unbound Configuration (pi-hole.conf)

When Unbound is installed, the following configuration is written to /etc/unbound/unbound.conf.d/pi-hole.conf:
server:
    verbosity: 0
    interface: 127.0.0.1
    port: 5335
    do-ip4: yes
    do-udp: yes
    do-tcp: yes
    do-ip6: no
    prefer-ip6: no
    root-hints: "/var/lib/unbound/root.hints"
    harden-glue: yes
    harden-dnssec-stripped: yes
    use-caps-for-id: no
    edns-buffer-size: 1232
    prefetch: yes
    num-threads: 1
    so-rcvbuf: 1m
    private-address: 192.168.0.0/16
    private-address: 169.254.0.0/16
    private-address: 172.16.0.0/12
    private-address: 10.0.0.0/8
    private-address: fd00::/8
    private-address: fe80::/10
Unbound is included in deploy.sh but is not fully working in v4.1. The author is tracking this as a known issue. If you enable Unbound and experience DNS failures, see the Troubleshooting guide and revert to a standard upstream (e.g., 8.8.8.8) in Pi-hole Settings → DNS.

Netplan Static IP Configuration

The generated Netplan file uses the detected interface name, current IP, and gateway. Nameservers are set to 8.8.8.8 (fallback) and 127.0.0.1 (Pi-hole itself).
network:
  version: 2
  renderer: networkd
  ethernets:
    <interface>:
      dhcp4: false
      addresses: [<detected-ip>/24]
      routes: [{to: default, via: <detected-gateway>}]
      nameservers: {addresses: [8.8.8.8, 127.0.0.1]}

Legacy Scripts

The legacy_scripts/ directory contains two standalone scripts that pre-date deploy.sh. They are not called by deploy.sh and are kept for reference.

install_prep.sh

A minimal preparation script. It runs apt update, installs curl and net-tools, then immediately launches the official Pi-hole installer:
sudo apt update
sudo apt install curl net-tools -y
curl -sSL https://install.pi-hole.net | bash
This is the simplest possible Pi-hole install with no automation beyond the Pi-hole TUI wizard.

firewall_rules.sh

A standalone UFW configuration script. It opens the three ports required for Pi-hole operation and enables the firewall:
sudo ufw allow 22/tcp   # SSH
sudo ufw allow 53/tcp   # DNS (TCP)
sudo ufw allow 53/udp   # DNS (UDP)
sudo ufw allow 80/tcp   # Web admin
sudo ufw enable
sudo ufw reload
sudo ufw status verbose
Use this script if you installed Pi-hole manually and need to configure UFW independently.
Use firewall_rules.sh as a quick repair tool if UFW rules are lost or incorrect after a system update.

Build docs developers (and LLMs) love