@ -8,17 +8,15 @@ Works on most Debian and CentOS/RHEL based distributions!
1. Install Raspbian
2. Run the command below (downloads [this script](https://github.com/pi-hole/pi-hole/blob/master/automated%20install/basic-install.sh) in case you want to read over it first!)
If you wish to read over the script before running it, then after the `wget` command, do `nano basic-install.sh` to open a text viewer
If you wish to read over the script before running it, then after the [`wget`](https://linux.die.net/man/1/wget) command, run `nano basic-install.sh` to open the file in a text viewer.
Once installed, [configure your router to have **DHCP clients use the Pi as their DNS server**](http://pi-hole.net/faq/can-i-set-the-pi-hole-to-be-the-dns-server-at-my-router-so-i-dont-have-to-change-settings-for-my-devices/) and then any device that connects to your network will have ads blocked without any further configuration. Alternatively, you can manually set each device to [use the Raspberry Pi as its DNS server](http://pi-hole.net/faq/how-do-i-use-the-pi-hole-as-my-dns-server/).
@ -34,7 +32,7 @@ Once installed, [configure your router to have **DHCP clients use the Pi as thei
## Pi-hole Is Free, But Powered By Your Donations
Send a one-time donation or sign up for Optimal.com's service using our link below to provide us with a small portion of the monthly fee.
Send a one-time donation using our link below to provide us with a small portion of the monthly fee.
- [![Join the chat at https://gitter.im/pi-hole/pi-hole](https://badges.gitter.im/pi-hole/pi-hole.svg)](https://gitter.im/pi-hole/pi-hole?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Technical Details
The Pi-hole is an **advertising-aware DNS/Web server**. If an ad domain is queried, a small Web page or GIF is delivered in place of the advertisement. You can also [replace ads with any image you want](http://pi-hole.net/faq/is-it-possible-to-change-the-blank-page-that-takes-place-of-the-ads-to-something-else/) since it is just a simple Webpage taking place of the ads.
#### Other Operating Systems
This script will work for other UNIX-like systems with some slight **modifications**. As long as you can install `dnsmasq` and a Webserver, it should work OK. The automated install is only for a clean install of a Debian family or Fedora based system, such as the Raspberry Pi. If there are other platforms you'd like supported, let us know.
### Gravity
The [gravity.sh](https://github.com/pi-hole/pi-hole/blob/master/gravity.sh) does most of the magic. The script pulls in ad domains from many sources and compiles them into a single list of [over 1.6 million entries](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0) (if you decide to use the [mahakala list](https://github.com/pi-hole/pi-hole/commit/963eacfe0537a7abddf30441c754c67ca1e40965)).
The [gravity.sh](https://github.com/pi-hole/pi-hole/blob/master/gravity.sh) does most of the magic. The script pulls in ad domains from many sources and compiles them into a single list of [over 1.6 million entries](http://jacobsalmela.com/block-millions-ads-network-wide-with-a-raspberry-pi-hole-2-0) (if you decide to use the [mahakala list](https://github.com/pi-hole/pi-hole/commit/963eacfe0537a7abddf30441c754c67ca1e40965)). This script is controlled by the `pihole` command. Please run `pihole -h` to see what commands can be run via `pihole`.
## Web Interface
@ -67,7 +70,7 @@ The [Web interface](https://github.com/jacobsalmela/AdminLTE#pi-hole-admin-dashb
### Whitelist and blacklist
Domains can be whitelisted and blacklisted using two pre-installed scripts. See [the wiki page](https://github.com/pi-hole/pi-hole/wiki/Whitelisting-and-Blacklisting) for more details ![Whitelist editor in the Web interface](http://i.imgur.com/ogu2ewg.png)
Domains can be whitelisted and blacklisted using either the web interface or the command line. See [the wiki page](https://github.com/pi-hole/pi-hole/wiki/Whitelisting-and-Blacklisting) for more details ![Whitelist editor in the Web interface](http://i.imgur.com/ogu2ewg.png)
## API
@ -119,7 +122,3 @@ You can view [real-time stats](http://pi-hole.net/faq/install-the-real-time-lcd-
- [Pi-hole on Ubuntu](http://www.boyter.org/2015/12/pi-hole-ubuntu-14-04/)
- [Catchpoint: iOS 9 Ad Blocking](http://blog.catchpoint.com/2015/09/14/ad-blocking-apple/)
## Other Operating Systems
This script will work for other UNIX-like systems with some slight **modifications**. As long as you can install `dnsmasq` and a Webserver, it should work OK. The automated install is only for a clean install of a Debian based system, such as the Raspberry Pi.
# Pi-hole: A black hole for Internet advertisements
# (c) 2015, 2016 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Blacklists domains
#
# Pi-hole is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#rootcheck
if[[$EUID -eq 0]];then
echo"::: You are root."
else
echo"::: sudo will be used."
# Check if it is actually installed
# If it isn't, exit because the install cannot complete
if[ -x "$(command -v sudo)"];then
exportSUDO="sudo"
else
echo"::: Please install sudo or run this script as root."
exit1
fi
fi
function helpFunc()
{
echo"::: Immediately blacklists one or more domains in the hosts file"
echo":::"
echo":::"
echo"::: Usage: pihole -b domain1 [domain2 ...]"
echo"::: Options:"
echo"::: -d, --delmode Remove domains from the blacklist"
echo"::: -nr, --noreload Update blacklist without refreshing dnsmasq"
echo"::: -f, --force Force updating of the hosts files, even if there are no changes"
echo"::: -q, --quiet output is less verbose"
echo"::: -h, --help Show this help dialog"
echo"::: -l, --list Display your blacklisted domains"
exit1
}
if[[$#=0]];then
helpFunc
fi
#globals
basename=pihole
piholeDir=/etc/${basename}
adList=${piholeDir}/gravity.list
blacklist=${piholeDir}/blacklist.txt
reload=true
addmode=true
force=false
verbose=true
domList=()
domToRemoveList=()
piholeIPfile=/etc/pihole/piholeIP
piholeIPv6file=/etc/pihole/.useIPv6
if[[ -f ${piholeIPfile}]];then
# If the file exists, it means it was exported from the installation script and we should use that value instead of detecting it in this script
piholeIP=$(cat ${piholeIPfile})
#rm $piholeIPfile
else
# Otherwise, the IP address can be taken directly from the machine, which will happen when the script is run by the user and not the installation script
IPv4dev=$(ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)print $(i+1)}')
piholeIPCIDR=$(ip -o -f inet addr show dev "$IPv4dev"| awk '{print $4}'| awk 'END {print}')
piholeIP=${piholeIPCIDR%/*}
fi
modifyHost=false
# After setting defaults, check if there's local overrides
if[[ -r ${piholeDir}/pihole.conf ]];then
echo"::: Local calibration requested..."
. ${piholeDir}/pihole.conf
fi
if[[ -f ${piholeIPv6file}]];then
# If the file exists, then the user previously chose to use IPv6 in the automated installer
piholeIPv6=$(ip -6 route get 2001:4860:4860::8888 | awk -F " "'{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }')
fi
function HandleOther(){
#check validity of domain
validDomain=$(echo"$1"| perl -ne'print if /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/')
if[ -z "$validDomain"];then
echo"::: $1 is not a valid argument or domain name"
else
domList=("${domList[@]}"${validDomain})
fi
}
function PopBlacklistFile(){
#check blacklist file exists, and if not, create it
if[[ ! -f ${blacklist}]];then
touch ${blacklist}
fi
for dom in "${domList[@]}";do
if"$addmode";then
AddDomain "$dom"
else
RemoveDomain "$dom"
fi
done
}
function AddDomain(){
#| sed 's/\./\\./g'
bool=false
grep -Ex -q "$1"${blacklist}||bool=true
if${bool};then
#domain not found in the blacklist file, add it!
if${verbose};then
echo -n "::: Adding $1 to blacklist file..."
fi
echo"$1" >> ${blacklist}
modifyHost=true
echo" done!"
else
if${verbose};then
echo"::: $1 already exists in $blacklist! No need to add"
fi
fi
}
function RemoveDomain(){
bool=false
grep -Ex -q "$1"${blacklist}||bool=true
if${bool};then
#Domain is not in the blacklist file, no need to Remove
if${verbose};then
echo"::: $1 is NOT blacklisted! No need to remove"
fi
else
#Domain is in the blacklist file, add to a temporary array
if${verbose};then
echo"::: Un-blacklisting $dom..."
fi
domToRemoveList=("${domToRemoveList[@]}"$1)
modifyHost=true
fi
}
function ModifyHostFile(){
if${addmode};then
#add domains to the hosts file
if[[ -r ${blacklist}]];then
numberOf=$(cat ${blacklist}| sed '/^\s*$/d'| wc -l)
plural=;[["$numberOf" !="1"]]&&plural=s
echo":::"
echo -n "::: Modifying HOSTS file to blacklist $numberOf domain${plural}..."
echo"No adlists.list file found... using adlists.default!" >> ${DEBUG_LOG}
printf":::\tNo adlists.list file found... using adlists.default!\n"
fi
gravity_length=$(wc -l "${GRAVITYFILE}")\
&& log_write "${GRAVITYFILE} is ${gravity_length} lines long."\
|| log_echo "Warning: No gravity.list file found!"
# Continuously append the pihole.log file to the pihole_debug.log file
functiondumpPiHoleLog {
dumpPiHoleLog(){
trap'{ echo -e "\n::: Finishing debug write from interrupt... Quitting!" ; exit 1; }' INT
echo -e "::: Writing current Pi-hole traffic to debug log...\n:::\tTry loading any/all sites that you are having trouble with now... \n:::\t(Press ctrl+C to finish)"
# Pi-hole: A black hole for Internet advertisements
# (c) 2015, 2016 by Jacob Salmela
# Network-wide ad blocking via your Raspberry Pi
# http://pi-hole.net
# Whitelists domains
#
# Pi-hole is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#rootcheck
if[[$EUID -eq 0]];then
echo"::: You are root."
else
echo"::: sudo will be used."
# Check if it is actually installed
# If it isn't, exit because the install cannot complete
if[ -x "$(command -v sudo)"];then
exportSUDO="sudo"
else
echo"::: Please install sudo or run this script as root."
exit1
fi
fi
function helpFunc()
{
echo"::: Immediately whitelists one or more domains in the hosts file"
echo":::"
echo"::: Usage: pihole -w domain1 [domain2 ...]"
echo":::"
echo"::: Options:"
echo"::: -d, --delmode Remove domains from the whitelist"
echo"::: -nr, --noreload Update Whitelist without refreshing dnsmasq"
echo"::: -f, --force Force updating of the hosts files, even if there are no changes"
echo"::: -q, --quiet output is less verbose"
echo"::: -h, --help Show this help dialog"
echo"::: -l, --list Display your whitelisted domains"
exit1
}
if[[$#=0]];then
helpFunc
fi
#globals
basename=pihole
piholeDir=/etc/${basename}
adList=${piholeDir}/gravity.list
whitelist=${piholeDir}/whitelist.txt
reload=true
addmode=true
force=false
verbose=true
domList=()
domToRemoveList=()
piholeIPfile=/etc/pihole/piholeIP
piholeIPv6file=/etc/pihole/.useIPv6
if[[ -f ${piholeIPfile}]];then
# If the file exists, it means it was exported from the installation script and we should use that value instead of detecting it in this script
piholeIP=$(cat ${piholeIPfile})
#rm $piholeIPfile
else
# Otherwise, the IP address can be taken directly from the machine, which will happen when the script is run by the user and not the installation script
IPv4dev=$(ip route get 8.8.8.8 | awk '{for(i=1;i<=NF;i++)if($i~/dev/)print $(i+1)}')
piholeIPCIDR=$(ip -o -f inet addr show dev "$IPv4dev"| awk '{print $4}'| awk 'END {print}')
piholeIP=${piholeIPCIDR%/*}
fi
modifyHost=false
# After setting defaults, check if there's local overrides
if[[ -r ${piholeDir}/pihole.conf ]];then
echo"::: Local calibration requested..."
. ${piholeDir}/pihole.conf
fi
if[[ -f ${piholeIPv6file}]];then
# If the file exists, then the user previously chose to use IPv6 in the automated installer
piholeIPv6=$(ip -6 route get 2001:4860:4860::8888 | awk -F " "'{ for(i=1;i<=NF;i++) if ($i == "src") print $(i+1) }')
fi
function HandleOther(){
#check validity of domain
validDomain=$(echo"$1"| perl -ne'print if /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/')
if[ -z "$validDomain"];then
echo"::: $1 is not a valid argument or domain name"
else
domList=("${domList[@]}"${validDomain})
fi
}
function PopWhitelistFile(){
#check whitelist file exists, and if not, create it
if[[ ! -f ${whitelist}]];then
touch ${whitelist}
fi
for dom in "${domList[@]}"
do
if${addmode};then
AddDomain "$dom"
else
RemoveDomain "$dom"
fi
done
}
function AddDomain(){
#| sed 's/\./\\./g'
bool=false
grep -Ex -q "$1"${whitelist}||bool=true
if${bool};then
#domain not found in the whitelist file, add it!
if${verbose};then
echo -n "::: Adding $1 to $whitelist..."
fi
echo"$1" >> ${whitelist}
modifyHost=true
if${verbose};then
echo" done!"
fi
else
if${verbose};then
echo"::: $1 already exists in $whitelist, no need to add!"
fi
fi
}
function RemoveDomain(){
bool=false
grep -Ex -q "$1"${whitelist}||bool=true
if${bool};then
#Domain is not in the whitelist file, no need to Remove
if${verbose};then
echo"::: $1 is NOT whitelisted! No need to remove"
fi
else
#Domain is in the whitelist file, add to a temporary array and remove from whitelist file
#if $verbose; then
#echo "::: Un-whitelisting $dom..."
#fi
domToRemoveList=("${domToRemoveList[@]}"$1)
modifyHost=true
fi
}
function ModifyHostFile(){
if${addmode};then
#remove domains in from hosts file
if[[ -r ${whitelist}]];then
# Remove whitelist entries
numberOf=$(cat ${whitelist}| sed '/^\s*$/d'| wc -l)
plural=;[["$numberOf" !="1"]]&&plural=s
echo":::"
echo -n "::: Modifying HOSTS file to whitelist $numberOf domain${plural}..."
for desiredInterface in ${chooseInterfaceOptions};do
piholeInterface=${desiredInterface}
echo"::: Using interface: $piholeInterface"
done
@ -271,8 +286,8 @@ use4andor6() {
getStaticIPv4Settings(){
# Ask if the user wants to use DHCP settings as their static IP
if(whiptail --backtitle "Calibrating network interface" --title "Static IP Address" --yesno "Do you want to use your current network settings as a static address?
IP address: $IPv4_address
Gateway: $IPv4gw"${r}${c}); then
IP address: ${IPv4_address}
Gateway: ${IPv4gw}"${r}${c}); then
# If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
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.
@ -282,20 +297,19 @@ It is also possible to use a DHCP reservation, but if you are going to do that,
# 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)
# Start a loop to let the user enter their information with the chance to go back and edit it if necessary
piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), seperated by a comma.\n\nFor example '8.8.8.8, 8.8.4.4'"${r}${c}"$prePopulate" 3>&1 1>&2 2>&3)
piholeDNS=$(whiptail --backtitle "Specify Upstream DNS Provider(s)" --inputbox "Enter your desired upstream DNS provider(s), seperated by a comma.\n\nFor example '8.8.8.8, 8.8.4.4'"${r}${c}"${prePopulate}" 3>&1 1>&2 2>&3)
if[[$?=0]];then
piholeDNS1=$(echo"$piholeDNS"| sed 's/[, \t]\+/,/g'| awk -F, '{print$1}')
piholeDNS2=$(echo"$piholeDNS"| sed 's/[, \t]\+/,/g'| awk -F, '{print$2}')
if ! valid_ip "$piholeDNS1"||[ ! "$piholeDNS1"];then
piholeDNS1=$(echo"${piholeDNS}"| sed 's/[, \t]\+/,/g'| awk -F, '{print$1}')
piholeDNS2=$(echo"${piholeDNS}"| sed 's/[, \t]\+/,/g'| awk -F, '{print$2}')
if ! valid_ip "${piholeDNS1}"||[ ! "${piholeDNS1}"];then
piholeDNS1=${strInvalid}
fi
if ! valid_ip "$piholeDNS2"&&["$piholeDNS2"];then
if ! valid_ip "${piholeDNS2}"&&["${piholeDNS2}"];then
whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP""One or both entered IP addresses were invalid. Please try again.\n\n DNS Server 1: $piholeDNS1\n DNS Server 2: $piholeDNS2"${r}${c}
whiptail --msgbox --backtitle "Invalid IP" --title "Invalid IP""One or both entered IP addresses were invalid. Please try again.\n\n DNS Server 1: $piholeDNS1\n DNS Server 2: ${piholeDNS2}"${r}${c}
if[[${piholeDNS1}=="${strInvalid}"]];then
piholeDNS1=""
fi
if[[${piholeDNS2}=="$strInvalid"]];then
if[[${piholeDNS2}=="${strInvalid}"]];then
piholeDNS2=""
fi
DNSSettingsCorrect=False
else
if(whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\n DNS Server 1: $piholeDNS1\n DNS Server 2: $piholeDNS2"${r}${c});then
if(whiptail --backtitle "Specify Upstream DNS Provider(s)" --title "Upstream DNS Provider(s)" --yesno "Are these settings correct?\n DNS Server 1: $piholeDNS1\n DNS Server 2: ${piholeDNS2}"${r}${c});then
whiptail --msgbox --backtitle "Make it so." --title "Installation Complete!""Configure your devices to use the Pi-hole as their DNS server using:
IPv4: ${IPv4_address%/*}
IPv6: $IPv6_address
IPv6: ${IPv6_address}
If you set a new IP address, you should restart the Pi.
@ -859,20 +917,31 @@ View the web interface at http://pi.hole/admin or http://${IPv4_address%/*}/admi
}
update_dialogs(){
# reconfigure
if["${reconfigure}"=true];then
opt1a="Repair"
opt1b="This will retain existing settings"
strAdd="You will remain on the same version"
else
opt1a="Update"
opt1b="This will retain existing settings."
strAdd="You will be updated to the latest version."
fi
opt2a="Reconfigure"
opt2b="This will allow you to enter new settings"
UpdateCmd=$(whiptail --title "Existing Install Detected!" --menu "\n\nWe have detected an existing install.\n\nPlease choose from the following options:"${r}${c}2\
"Update""Update install will retain existing settings."\
"Install""Install will allow you to enter new settings." 3>&2 2>&1 1>&3)
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\
echo"::: $numberOf unique domains trapped in the event horizon."
}
functiongravity_hostFormat(){
gravity_hostFormat(){
# Format domain list as "192.168.x.x domain.com"
echo"::: Formatting domains into a HOSTS file..."
if[[ -f /etc/hostname ]];then
hostname=$(</etc/hostname)
elif[ -x "$(command -v hostname)"];then
hostname=$(hostname -f)
else
echo"::: Error: Unable to determine fully qualified domain name of host"
fi
# If there is a value in the $piholeIPv6, then IPv6 will be used, so the awk command modified to create a line for both protocols
if[[ -n "${IPv6_address}"]];then
# Add hostname and dummy domain to the top of gravity.list to make ping result return a friendlier looking domain! Also allows for an easy way to access the Pi-hole admin console (pi.hole/admin)
# Otherwise, just create gravity.list as normal using IPv4
# Add hostname and dummy domain to the top of gravity.list to make ping result return a friendlier looking domain! Also allows for an easy way to access the Pi-hole admin console (pi.hole/admin)