# The PHP version available via default repositories is older than version 7
# The PHP version available via default repositories is older than version 7
if ! whiptail --defaultno --title "PHP 7 Update (recommended)" --yesno "PHP 7.x is recommended for both security and language features.\\nWould you like to install PHP7 via Remi's RPM repository?\\n\\nSee: https://rpms.remirepo.net for more information""${r}""${c}";then
dialog --no-shadow --keep-tite \
# User decided to NOT update PHP from REMI, attempt to install the default available PHP version
--title "PHP 7 Update (recommended)"\
printf" %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n""${INFO}"
--defaultno \
: # continue with unsupported php version
--yesno "PHP 7.x is recommended for both security and language features.\
else
\\n\\nWould you like to install PHP7 via Remi's RPM repository?\
printf" %b Installed %s from %s\\n""${TICK}""${REMI_PKG}""${REMI_REPO_URL}"
printf" %b Remi's RPM repository has been enabled for PHP7\\n""${TICK}"
fi
yum-config-manager --disable 'remi-php*'
yum-config-manager --enable "${REMI_REPO}"
# trigger an install/update of PHP to ensure previous version of PHP is updated from REMI
# trigger an install/update of PHP to ensure previous version of PHP is updated from REMI
if"${PKG_INSTALL[@]}""php-cli"&> /dev/null;then
if"${PKG_INSTALL[@]}""php-cli"&> /dev/null;then
printf" %b PHP7 installed/updated via Remi's RPM repository\\n""${TICK}"
printf" %b PHP7 installed/updated via Remi's RPM repository\\n""${TICK}"
@ -437,15 +467,49 @@ select_rpm_php(){
printf" %b There was a problem updating to PHP7 via Remi's RPM repository\\n""${CROSS}"
printf" %b There was a problem updating to PHP7 via Remi's RPM repository\\n""${CROSS}"
exit1
exit1
fi
fi
fi
;;
fi# Warn user of unsupported version of Fedora or CentOS
if ! whiptail --defaultno --title "Unsupported RPM based distribution" --yesno "Would you like to continue installation on an unsupported RPM based distribution?\\n\\nPlease ensure the following packages have been installed manually:\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+""${r}""${c}";then
# User chose not to install PHP 7 via Remi's RPM repository
printf" %b Aborting installation due to unsupported RPM based distribution\\n""${CROSS}"
"${DIALOG_CANCEL}")
exit
# User decided to NOT update PHP from REMI, attempt to install the default available PHP version
else
printf" %b User opt-out of PHP 7 upgrade on CentOS. Deprecated PHP may be in use.\\n""${INFO}"
printf" %b Continuing installation with unsupported RPM based distribution\\n""${INFO}"
;;
# User closed the dialog window
"${DIALOG_ESC}")
printf" %b Escape pressed, exiting installer at Remi dialog window\\n""${CROSS}"
exit1
;;
esac
fi
fi
fi
else
# Warn user of unsupported version of Fedora or CentOS
dialog --no-shadow --keep-tite \
--title "Unsupported RPM based distribution"\
--defaultno \
--no-button "Exit"\
--yes-button "Continue"\
--yesno "Would you like to continue installation on an unsupported RPM based distribution?\
\\n\\nPlease ensure the following packages have been installed manually:\
\\n\\n- lighttpd\\n- lighttpd-fastcgi\\n- PHP version 7+"\
"${r}""${c}"&&result=0||result=$?
case${result} in
# User chose to continue installation on an unsupported RPM based distribution
"${DIALOG_OK}")
printf" %b User opted to continue installation on an unsupported RPM based distribution.\\n""${INFO}"
;;
# User chose not to continue installation on an unsupported RPM based distribution
"${DIALOG_CANCEL}")
printf" %b User opted not to continue installation on an unsupported RPM based distribution.\\n""${INFO}"
exit1
;;
"${DIALOG_ESC}")
printf" %b Escape pressed, exiting installer at unsupported RPM based distribution dialog window\\n""${CROSS}"
exit1
;;
esac
fi
fi
}
}
@ -636,40 +700,45 @@ get_available_interfaces() {
# A function for displaying the dialogs the user sees when first running the installer
# A function for displaying the dialogs the user sees when first running the installer
welcomeDialogs(){
welcomeDialogs(){
# Display the welcome dialog using an appropriately sized window via the calculation conducted earlier in the script
# Display the welcome dialog using an appropriately sized window via the calculation conducted earlier in the script
whiptail --msgbox --backtitle "Welcome" --title "Pi-hole automated installer""\\n\\nThis installer will transform your device into a network-wide ad blocker!""${r}""${c}"
dialog --no-shadow --clear --keep-tite \
--backtitle "Welcome"\
# Request that users donate if they enjoy the software since we all work on it in our free time
--title "Pi-hole Automated Installer"\
whiptail --msgbox --backtitle "Plea" --title "Free and open source""\\n\\nThe Pi-hole is free, but powered by your donations: https://pi-hole.net/donate/""${r}""${c}"
--msgbox "\\n\\nThis installer will transform your device into a network-wide ad blocker!"\
"${r}""${c}"\
# Explain the need for a static address
--and-widget --clear \
if whiptail --defaultno --backtitle "Initiating network interface" --title "Static IP Needed" --yesno "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP ADDRESS to function properly.
--backtitle "Support Pi-hole"\
--title "Open Source Software"\
IMPORTANT: If you have not already done so, you must ensure that this device has a static IP. Either through DHCP reservation, or by manually assigning one. Depending on your operating system, there are many ways to achieve this.
--msgbox "\\n\\nThe Pi-hole is free, but powered by your donations: https://pi-hole.net/donate/"\
"${r}""${c}"\
Choose yes to indicate that you have understood this message, and wish to continue" "${r}" "${c}"; then
--and-widget --clear \
#Nothing to do, continue
--colors \
echo
--backtitle "Initiating network interface"\
else
--title "Static IP Needed"\
printf" %b Installer exited at static IP message.\\n""${INFO}"
--no-button "Exit" --yes-button "Continue"\
exit1
--defaultno \
fi
--yesno "\\n\\nThe Pi-hole is a SERVER so it needs a STATIC IP ADDRESS to function properly.\\n\\n\
\\Zb\\Z1IMPORTANT:\\Zn If you have not already done so, you must ensure that this device has a static IP.\\n\\n\
Depending on your operating system, there are many ways to achieve this, through DHCP reservation, or by manually assigning one.\\n\\n\
Please continue when the static addressing has been configured."\
"${r}""${c}"&&result=0||result="$?"
case"${result}" in
"${DIALOG_CANCEL}"|"${DIALOG_ESC}")
printf" %b Installer exited at static IP message.\\n""${INFO}"
exit1
;;
esac
}
}
# A function that lets the user pick an interface to use with Pi-hole
# A function that lets the user pick an interface to use with Pi-hole
chooseInterface(){
chooseInterface(){
# Turn the available interfaces into an array so it can be used with a whiptail dialog
# Turn the available interfaces into a string so it can be used with dialog
localinterfacesArray=()
localinterfacesList
# Number of available interfaces
# Number of available interfaces
local interfaceCount
local interfaceCount
# Whiptail variable storage
local chooseInterfaceCmd
# Temporary Whiptail options storage
local chooseInterfaceOptions
# Loop sentinel variable
localfirstLoop=1
# Find out how many interfaces are available to choose from
# POSIX compliant way to get the number of elements in an array
printf" %b Using interface: %s\\n""${INFO}""${PIHOLE_INTERFACE}"
fi
fi
}
}
@ -789,57 +858,94 @@ getStaticIPv4Settings() {
local ipSettingsCorrect
local ipSettingsCorrect
local DHCPChoice
local DHCPChoice
# Ask if the user wants to use DHCP settings as their static IP
# Ask if the user wants to use DHCP settings as their static IP
# This is useful for users that are using DHCP reservations; then we can just use the information gathered via our functions
# This is useful for users that are using DHCP reservations; we can use the information gathered
DHCPChoice=$(whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --menu --separate-output "Do you want to use your current network settings as a static address? \\n
--menu "Do you want to use your current network settings as a static address?\\n \
"Skip""I will set a static IP later, or have already done so" 3>&2 2>&1 1>&3)||\
IP address: ${IPV4_ADDRESS}\\n \
{printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}";exit 1;}
Gateway: ${IPv4gw}\\n"\
"${r}""${c}"3\
case${DHCPChoice} in
"Yes""Set static IP using current values"\
"Yes")
"No""Set static IP using custom values"\
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
"Skip""I will set a static IP later, or have already done so")
whiptail --msgbox --backtitle "IP information" --title "FYI: IP Conflict""It is possible your router could still try to assign this IP to a device, which would cause a conflict. But in most cases the router is smart enough to not do that.
If you are worried, either manually set the address, or modify the DHCP reservation pool so it does not include the IP you want.
result=$?
It is also possible to use a DHCP reservation, but if you are going to do that, you might as well set a static address." "${r}" "${c}"
case${result} in
# Nothing else to do since the variables are already set above
"${DIALOG_CANCEL}"|"${DIALOG_ESC}")
setDHCPCD
printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"
;;
exit1
;;
"No")
esac
# Otherwise, we need to ask the user to input their desired settings.
# Start by getting the IPv4 address (pre-filling it with info gathered from DHCP)
case${DHCPChoice} in
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary
# Prompt the user to enter custom upstream servers
# Prompt the user to enter custom upstream servers
piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), separated by a comma. If you want to specify a port other than 53, separate it with a hash.\\n\\nFor example '8.8.8.8, 8.8.4.4' or '127.0.0.1#5335'""${r}""${c}""${prePopulate}" 3>&1 1>&2 2>&3)||\
whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP""One or both entered IP addresses were invalid. Please try again.\\n\\n DNS Server 1: $PIHOLE_DNS_1\\n DNS Server 2: ${PIHOLE_DNS_2}"${r}${c}
dialog --no-shadow --keep-tite \
--title "Invalid IP Address(es)"\
--backtitle "Invalid IP"\
--msgbox "\\nOne or both of the entered IP addresses were invalid. Please try again.\
# Otherwise, show the DNS setting to the user, and break the loop if they confirm them.
dialog --no-shadow --keep-tite \
if(whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\\n DNS Server 1: $PIHOLE_DNS_1\\n DNS Server 2: ${PIHOLE_DNS_2}""${r}""${c}");then
--backtitle "Specify Upstream DNS Provider(s)"\
DNSSettingsCorrect=True
--title "Upstream DNS Provider(s)"\
else
--yesno "Are these settings correct?\\n\\tDNS Server 1:\\t${PIHOLE_DNS_1}\\n\\tDNS Server 2:\\t${PIHOLE_DNS_2}"\
DNSSettingsCorrect=False
"${r}""${c}"&&result=0||result=$?
fi
case${result} in
"${DIALOG_OK}")
DNSSettingsCorrect=True
;;
"${DIALOG_CANCEL}")
DNSSettingsCorrect=False
;;
"${DIALOG_ESC}")
printf" %b Escape pressed, exiting installer at DNS Settings%b\\n""${COL_LIGHT_RED}""${COL_NC}"
exit1
;;
esac
fi
fi
done
done
else
else
@ -1023,106 +1169,121 @@ setDNS() {
# Allow the user to enable/disable logging
# Allow the user to enable/disable logging
setLogging(){
setLogging(){
# Local, named variables
# Ask the user if they want to enable logging
local LogToggleCommand
dialog --no-shadow --keep-tite \
local LogChooseOptions
--backtitle "Pihole Installation"\
local LogChoices
--title "Enable Logging"\
--yesno "\\n\\nWould you like to enable query logging?"\
# Ask if the user wants to log queries
"${r}""${c}"&&result=0||result=$?
LogToggleCommand=(whiptail --separate-output --radiolist "Do you want to log queries?""${r}""${c}" 6)
# The default selection is on
case${result} in
LogChooseOptions=("On (Recommended)""" on
"${DIALOG_OK}")
Off "" off)
# If they chose yes,
# Get the user's choice
printf" %b Query Logging on.\\n""${INFO}"
LogChoices=$("${LogToggleCommand[@]}""${LogChooseOptions[@]}" 2>&1 >/dev/tty)||(printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"&&exit 1)
case${LogChoices} in
# If it's on,
"On (Recommended)")
printf" %b Logging On.\\n""${INFO}"
# set the GLOBAL variable setting to true
QUERY_LOGGING=true
QUERY_LOGGING=true
;;
;;
# Otherwise, it's off,
"${DIALOG_CANCEL}")
Off)
# If they chose no,
printf" %b Logging Off.\\n""${INFO}"
printf" %b Query Logging off.\\n""${INFO}"
# set the GLOBAL variable setting to false
QUERY_LOGGING=false
QUERY_LOGGING=false
;;
;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf" %b Escape pressed, exiting installer at Query Logging choice.%b\\n""${COL_LIGHT_RED}""${COL_NC}"
exit1
;;
esac
esac
}
}
# Allow the user to set their FTL privacy level
# Allow the user to set their FTL privacy level
setPrivacyLevel(){
setPrivacyLevel(){
local LevelCommand
local LevelOptions
LevelCommand=(whiptail --separate-output --radiolist "Select a privacy mode for FTL. https://docs.pi-hole.net/ftldns/privacylevels/""${r}""${c}" 6)
# Function to ask the user if they want to install the dashboard
# Function to ask the user if they want to install the dashboard
setAdminFlag(){
setAdminFlag(){
# Local, named variables
local WebToggleCommand
local WebChooseOptions
local WebChoices
# Similar to the logging function, ask what the user wants
# Similar to the logging function, ask what the user wants
WebToggleCommand=(whiptail --separate-output --radiolist "Do you wish to install the web admin interface?""${r}""${c}" 6)
dialog --no-shadow --keep-tite \
# with the default being enabled
--backtitle "Pihole Installation"\
WebChooseOptions=("On (Recommended)""" on
--title "Admin Web Interface"\
Off "" off)
--yesno "\\n\\nDo you want to install the Admin Web Interface?"\
WebChoices=$("${WebToggleCommand[@]}""${WebChooseOptions[@]}" 2>&1 >/dev/tty)||(printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"&&exit 1)
"${r}""${c}"&&result=0||result=$?
# Depending on their choice
case${WebChoices} in
case${result} in
"On (Recommended)")
"${DIALOG_OK}")
printf" %b Web Interface On\\n""${INFO}"
# If they chose yes,
# Set it to true
printf" %b Installing Admin Web Interface\\n""${INFO}"
# Set the flag to install the web interface
INSTALL_WEB_INTERFACE=true
INSTALL_WEB_INTERFACE=true
;;
;;
Off)
"${DIALOG_CANCEL}")
printf" %b Web Interface Off\\n""${INFO}"
# If they chose no,
# or false
printf" %b Not installing Admin Web Interface\\n""${INFO}"
# Set the flag to not install the web interface
INSTALL_WEB_INTERFACE=false
INSTALL_WEB_INTERFACE=false
# Deselect the web server as well, since it is obsolete then
INSTALL_WEB_SERVER=false
INSTALL_WEB_SERVER=false
;;
;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf" %b Escape pressed, exiting installer at Admin Web Interface choice.%b\\n""${COL_LIGHT_RED}""${COL_NC}"
exit1
;;
esac
esac
# If the user wants to install the Web admin interface (i.e. it has not been deselected above)
# If the user wants to install the Web admin interface (i.e. it has not been deselected above)
if[["${INSTALL_WEB_SERVER}"==true]];then
if[["${INSTALL_WEB_INTERFACE}"==true]];then
# Get list of required PHP modules, excluding base package (common) and handler (cgi)
# Get list of required PHP modules, excluding base package (common) and handler (cgi)
local i php_modules
local i php_modules
for i in "${PIHOLE_WEB_DEPS[@]}";do[[$i=='php'* &&$i != *'-common'&&$i != *'-cgi']]&&php_modules+="${i#*-}";done
for i in "${PIHOLE_WEB_DEPS[@]}";do[[$i=='php'* &&$i != *'-common'&&$i != *'-cgi']]&&php_modules+="${i#*-}";done
WebToggleCommand=(whiptail --separate-output --radiolist "Do you wish to install the web server (lighttpd) and required PHP modules?\\n\\nNB: If you disable this, and, do not have an existing web server and required PHP modules (${php_modules# }) installed, the web interface will not function. Additionally the web server user needs to be member of the \"pihole\" group for full functionality.""${r}""${c}" 6)
dialog --no-shadow --keep-tite \
# Enable as default and recommended option
--backtitle "Pi-hole Installation"\
WebChooseOptions=("On (Recommended)""" on
--title "Web Server"\
Off "" off)
--yesno "\\n\\nA web server is required for the Admin Web Interface.\
WebChoices=$("${WebToggleCommand[@]}""${WebChooseOptions[@]}" 2>&1 >/dev/tty)||(printf" %bCancel was selected, exiting installer%b\\n""${COL_LIGHT_RED}""${COL_NC}"&&exit 1)
\\n\\nDo you want to install lighttpd and the required PHP modules?\
# Depending on their choice
\\n\\nNB: If you disable this, and, do not have an existing web server \
case${WebChoices} in
and required PHP modules (${php_modules# }) installed, the web interface \
"On (Recommended)")
will not function. Additionally the web server user needs to be member of \
printf" %b Web Server On\\n""${INFO}"
the \"pihole\" group for full functionality."\
# set it to true, as clearly seen below.
"${r}""${c}"&&result=0||result=$?
case${result} in
"${DIALOG_OK}")
# If they chose yes,
printf" %b Installing lighttpd\\n""${INFO}"
# Set the flag to install the web server
INSTALL_WEB_SERVER=true
INSTALL_WEB_SERVER=true
;;
;;
Off)
"${DIALOG_CANCEL}")
printf" %b Web Server Off\\n""${INFO}"
# If they chose no,
# or false
printf" %b Not installing lighttpd\\n""${INFO}"
# Set the flag to not install the web server
INSTALL_WEB_SERVER=false
INSTALL_WEB_SERVER=false
;;
;;
"${DIALOG_ESC}")
# User pressed <ESC>
printf" %b Escape pressed, exiting installer at web server choice.%b\\n""${COL_LIGHT_RED}""${COL_NC}"
exit1
;;
esac
esac
fi
fi
}
}
@ -1133,18 +1294,32 @@ chooseBlocklists() {
if[[ -f "${adlistFile}"]];then
if[[ -f "${adlistFile}"]];then
mv "${adlistFile}""${adlistFile}.old"
mv "${adlistFile}""${adlistFile}.old"
fi
fi
# Let user select (or not) blocklists via a checklist
# Let user select (or not) blocklists
cmd=(whiptail --separate-output --checklist "Pi-hole relies on third party lists in order to block ads.\\n\\nYou can use the suggestion below, and/or add your own after installation\\n\\nTo deselect the suggested list, use spacebar""${r}""${c}" 5)
dialog --no-shadow --keep-tite \
# In an array, show the options available (all off by default):
# Check if /etc/dnsmasq.conf is from pi-hole. If so replace with an original and install new in .d directory
# Check if /etc/dnsmasq.conf is from pi-hole. If so replace with an original and install new in .d directory
@ -1934,20 +2101,17 @@ displayFinalMessage() {
# If the user wants to install the dashboard,
# If the user wants to install the dashboard,
if[["${INSTALL_WEB_INTERFACE}"==true]];then
if[["${INSTALL_WEB_INTERFACE}"==true]];then
# Store a message in a variable and display it
# Store a message in a variable and display it
additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin
additional="View the web interface at http://pi.hole/admin or http://${IPV4_ADDRESS%/*}/admin\\n\\nYour Admin Webpage login password is ${pwstring}"
Your Admin Webpage login password is ${pwstring}"
fi
fi
# Final completion message to user
# Final completion message to user
whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!""Configure your devices to use the Pi-hole as their DNS server using:
dialog --no-shadow --keep-tite \
--title "Installation Complete!"\
IPv4: ${IPV4_ADDRESS%/*}
--msgbox "Configure your devices to use the Pi-hole as their DNS server using:\
IPv6: ${IPV6_ADDRESS:-"Not Configured"}
\\n\\nIPv4: ${IPV4_ADDRESS%/*}\
\\nIPv6: ${IPV6_ADDRESS:-"Not Configured"}\
If you have not done so already, the above IP should be set to static.
\\nIf you have not done so already, the above IP should be set to static.\
\\n${additional}" "${r}" "${c}"
${additional}" "${r}" "${c}"
}
}
update_dialogs(){
update_dialogs(){
@ -1967,20 +2131,33 @@ update_dialogs() {
opt2b="Resets Pi-hole and allows re-selecting settings."
opt2b="Resets Pi-hole and allows re-selecting settings."
# Display the information to the user
# Display the information to the user
UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\\n\\nWe have detected an existing install.\\n\\nPlease choose from the following options: \\n($strAdd)""${r}""${c}"2\