Pocket PiHole

My ad blocking DNS has been a great help in cutting down ads, blocking sites I don’t like, and generally being my friend. It does require maintenance, though, and that’s a PITA.

I’m also at the point where I want to take it with me when I go out. My own little cocoon of ad blocking and protection.

So I’m creating a “Pocket PiHole”. Based loosely on the Dongle Pi I did before; in that it will be a Pi on the road, but power will come from a battery pack and instead of a wired ethernet, I’m going to configure it as a WiFi Access Point. That way any of my devices (phone, tablet, Mac, etc.) can connect to it.

It will provide DHCP IP number assignments on “My Network” along with ad blocking DNS services and be a Squid Proxy Server. Eventually I’ll add more bits to it like some Intrusion Detection / Prevention bits.

The most cumbersome part will be to get it connected to public WiFi at places like StarBucks. They have now gone to some kind of approval email / device acceptance (and track you…) code (so I go to Peet’s Coffee more now) and Peet’s has gone to an automatic “Pop Up” window using some kind of trick bits that don’t play well with my old tablet and Mac. I often open a browser to discover I must turn off the pointer to “My DNS” server and “My Proxy server” and by then the popup has failed. Attempts to get it back often also fail and it doesn’t work at all with some browsers. I did learn last time to drop the link and restart it to get another try at it. So who knows, maybe I’ll be going to Dunkin’ next ;-)

In any case, I’ve decided it’s time for a “do over” on the DNS ad blocking infrastructure. This time I’ll be using PiHole instead of a ‘roll your own’. Installation looks really quick and easy. Biggest issue I’ve got is that they want you to just run a script (As ROOT!) through bash, sight unseen. Yes, I trust these guys… but I don’t trust DNS Hijackers… and phishing folks.

So this posting is about that first step. Setting up a Raspberry Pi M3 with PiHole and doing DNS / DHCP services. Later I’ll add the WiFi access point dongle and make it do the rest. Eventually I’ll buy the battery pack and make it portable.

First just do a basic Devuan install of a minimal sort. I went ahead and did the full build script I’d done before as I wanted a full GUI LXDE environment during the build. Once this is all worked out, I’ll re-do it all with a custom build script that doesn’t install so much. For “On The Road” I’ll need some kind of VNC or remote terminal window system to let me get past the Starbucks / Peets prompts & stuff. That will be the last step after it works at general open WiFi spots.

Then it is just install and configure the PiHole.

On to PiHole:

On their front page level they list this command:

curl -sSL https://install.pi-hole.net | bash

Here’s a video of a guy doing just that and installing PiHole without deeper inspection. About 16 minutes including installation and demonstration. As I’m on a fresh install of Devuan on a R.Pi I could without too much risk do just that. Except I’d not really know what was done to my system.

Well that’s not gonna happen without some inspection so instead I went to a temp directory and did:

curl -L -o Pihole.sh  https://install.pi-hole.net

The -s is silent mode and the -S says toss an error message if you fail. Just leaving them out lets me watch what is happening. Then the -o lets me put the output in a file named Pihole.sh instead of piping it into bash for execution.

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100     5  100     5    0     0      5      0  0:00:01 --:--:--  0:00:01     5
100  108k  100  108k    0     0  85406      0  0:00:01  0:00:01 --:--:-- 85406

About 108k in size.

root@PocketPi:/SG2/tmp# ls -l Pihole.sh
-rw-r--r-- 1 root root 111018 Dec 16 20:34 Pihole
root@PocketPi:/SG2/tmp# wc -l Pihole.sh
2621 Pihole

2621 lines of script. This is gonna take a while to look over ;-)

My major interest is to look for any bad practices and then to make sure it isn’t SystemD centric. It ought to be smart enough to realize some folks run other init systems and do the right thing. About 700 of them are comments:

grep \# Pihole.sh | wc -l

So at this point things are going to diverge and get large. Down below I’ve pasted in the 786 lines so you can look them over. It is fairly well documented and the flow looks appropriate. It is, in fact, bright enough to sort SystemD from Sys V init. Hopefully it will not be confused by a Devuan. I’m going to run through the script (but not post all of it here – you can download your own to look at), just to do a sanity check that the commands issued match the comments describing them. Then I’m basically going to do what was in the video. I’ll be running my local version of the script that I’ve inspected though.

I’m also going to assign a fixed IP to this R.Pi and reboot, rather than needing to change it later.

Some Time Later…

In general the script looks to download and install PiHole, then run you through some configuration options.

OK, I’ve scanned the script and all the commands look like they do what the comments claim. It is still possible some mischief is hidden in some other script it calls, but there’s nothing glaring.

I’m not fond of their setting up a pihole user that’s got sudoers powers, but on a dedicated purpose box I’ll live with it. There’s also a tendency to put things in /etc where I’d rather have it in /usr/local, but that’s just a preference item (and if I really cared I could change that variable and debug…)

It took about 16 minutes to run on the R.Pi M3. I note in passing that at the end when it gives you the notice of where to find the web interface, you will want to write that down along with the passwd it gives you. Mine ended in a _ that was easy to overlook..

It produces a nice set of output, and asks you the expected questions in an ncurses style menu. All pretty easy.

With that, I’m going to paste in the transaction log (minus the menus) and try it out. From here on down is just documentary text. Anything new and interesting I’ll post in a comment. I did need to turn off the proxy settings on my browser to get to the admin screen at: “pi.hole/admin/” (well Duh…) and I now realize I didn’t pay attention to how to change the password, so until I find that again I’m stuck with the ugly one.

For now, I’m off to the Mac in the Livingroom to see how well this works. In first blush look, it seems easy and effective. I have DNS and DHCP turned on and running. (Squid Proxy install and Access Point configuration for another day)

Space Used


Filesystem      1K-blocks      Used  Available Use% Mounted on
/dev/root         6445184   2693388    3406360  45% /


Filesystem      1K-blocks      Used  Available Use% Mounted on
/dev/root         6445184   2761760    3337988  46% /

So about 68 MB.

The Interfaces File for Fixed IP

At present, I’m leaving the Wireless LAN (wlanx) as wpa supplicant controlled. We’ll see if I need to change that later when I transition to wireless use as an Access Point. For now it will be running on my LAN on the 10.x.x.x private network. You can see I’ve commented out the typical eth0 dhcp lines.

root@PocketPi:/etc/network# cat /etc/network/interfaces
# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
# source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

#auto eth0
#iface eth0 inet dhcp

#auto eth1
#iface eth1 inet dhcp

 auto eth0
 iface eth0 inet static

 allow-hotplug wlan0
 iface wlan0 inet dhcp
	wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

 allow-hotplug wlan1
 iface wlan1 inet dhcp
	wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

The Comments In The Script

I’m going to paste in the output of that search on # here:

root@PocketPi:/SG2/tmp# cat Comments_Pihole 
#!/usr/bin/env bash
# shellcheck disable=SC1090
# Pi-hole: A black hole for Internet advertisements
# (c) 2017-2018 Pi-hole, LLC (https://pi-hole.net)
# Network-wide ad blocking via your own hardware.
# Installs and Updates Pi-hole
# This file is copyright under the latest version of the EUPL.
# Please see LICENSE file for your rights under this license.
# pi-hole.net/donate
# Install with this command (from your Linux machine):
# curl -sSL https://install.pi-hole.net | bash
# -e option instructs bash to immediately exit if any command [1] has a non-zero exit status
# We do not want users to end up with a partially working install, so we exit the script
# instead of continuing the installation with something broken
######## VARIABLES #########
# For better maintainability, we store as much information that can change in variables
# This allows us to make a change in one place that can propagate to all instances of the variable
# These variables should all be GLOBAL variables, written in CAPS
# Local variables will be in lowercase and will exist only within functions
# It's still a work in progress, so you may see some variance in this guideline until it is complete
# Location for final installation log storage
# This is an important file as it contains information specific to the machine it's being installed on
# Pi-hole uses lighttpd as a Web server, and this is the config file for it
# shellcheck disable=SC2034
# This is a file used for the colorized output
# We store several other directories and
# These are the names of pi-holes files, stored in an array
# This directory is where the Pi-hole scripts will be installed
# Pi-hole needs an IP address; to begin, these variables are empty since we don't know what the IP is until
# this script can run
# By default, query logging is enabled and the dashboard is set to be installed
# Find the rows and columns will default to 80x24 if it can not be detected
# Set rows variable to contain first number
# Set columns variable to contain second number
printf -v columns '%d' "${screen_size##* }"
# Divide by two so the dialogs take up half of the screen, which looks nice.
# Unless the screen is tiny
######## Undocumented Flags. Shhh ########
# These are undocumented flags; some of which we can use when repairing an installation
# The runUnattended flag is one example of this
# Check arguments for the undocumented flags
# If the color table file exists,
    # source it
# Otherwise,
    # Set these values so the installer can still run in color
    COL_NC='\e[0m' # No Color
    # shellcheck disable=SC2034
# A simple function that just echoes out our logo in ASCII format
# This lets users know that it is a Pi-hole, LLC product
    # Checks for existence of string passed in as only function argument.
    # Exit value of 0 when exists, 1 if not exists. Value is the result
    # of the `command` shell built-in call.
# Compatibility
# If apt-get is installed, then we know it's part of the Debian family
    # Set some global variables here
    # We don't set them earlier since the family might be Red Hat, so these values would be different
    # A variable to store the command used to update the package cache
    # An array for something...
    # grep -c will return 1 retVal on 0 matches, block this throwing the set -e with an OR TRUE
    # Some distros vary slightly so these fixes for dependencies may apply
    # Debian 7 doesn't have iproute2 so if the dry run install is successful,
        # we can install it
    # Otherwise,
        # use iproute
    # Check for and determine version number (major and minor) of current php install
        # Is installed php version 7.0 or greater
    # Check if installed php is v 7.0, or newer to determine packages to install
        # Prefer the php metapackage if it's there
        # fall back on the php5 packages
        # Newer php is installed, its common, cgi & sqlite counterparts are deps
    # We also need the correct version for `php-sqlite` (which differs across distros)
    # Since our install script is so large, we need several other programs to successfully get a machine provisioned
    # These programs are stored in an array so they can be looped through later
    # Pi-hole itself has several dependencies that also need to be installed
    # The Web dashboard has some that also need to be installed
    # It's useful to separate the two since our repos are also setup as "Core" code and "Web" code
    # The Web server user,
    # group,
    # and config file
    # A function to check...
        # An iterator used for counting loop iterations
        # fuser is a program to show which processes use the named files, sockets, or filesystems
        # So while the command is true
            # Wait half a second
            # and increase the iterator
        # Always return success, since we only return if there is no
        # lock (anymore)
# If apt-get is not found, check for rpm to see if it's a Red Hat family OS
    # Then check if dnf or yum is the package manager
    # Fedora and family update cache on every PKG_INSTALL call, no need for a separate update.
    # If the host OS is Fedora,
        # all required packages should be available by default with the latest fedora release
        # ensure 'php-json' is installed on Fedora (installed as dependency on CentOS7 + Remi repository)
    # or if host OS is CentOS,
        # Pi-Hole currently supports CentOS 7+ with PHP7+
        # Check current CentOS major release version
        # Check if CentOS version is supported
            # exit the installer
        # on CentOS we need to add the EPEL repository to gain access to Fedora packages
        # The default php on CentOS 7.x is 5.4 which is EOL
        # Check if the version of PHP available via installed repositories is >= to PHP 7
            # Since PHP 7 is available by default, install via default PHP package names
            : # do nothing as PHP is current
            # The PHP version available via default repositories is older than version 7
                # User decided to NOT update PHP from REMI, attempt to install the default available PHP version
                : # continue with unsupported php version
                # enable the PHP 7 repository via yum-config-manager (provided by yum-utils)
                # trigger an install/update of PHP to ensure previous version of PHP is updated from REMI
        # Warn user of unsupported version of Fedora or CentOS
            exit # exit the installer
# If neither apt-get or yum/dnf package managers were found
    # it's not an OS we can support,
    # so exit the installer
# A function for checking if a directory is a git repository
    # Use a named, local variable instead of the vague $1, which is the first argument passed to this function
    # These local variables should always be lowercase
    # A local variable for the current directory
    # A variable to store the return code
    # Assign the current directory variable by using pwd
    # If the first argument passed to this function is a directory,
        # move into the directory
        # Use git to check if the directory is a repo
        # git -C is not used here to support git versions older than 1.8.4
    # If the command was not successful,
        # Set a non-zero return code if directory does not exist
    # Move back into the directory the user started in
    # Return the code; if one is not set, return 0
# A function to clone a repo
    # Set named variables for better readability
    # The message to display when this function is running
    # Display the message and use the color table to preface the message with an "info" indicator
    # If the directory exists,
        # delete everything in it so git can clone into it
    # Clone the repo and return the return code from this command
    # Show a colored message showing it's status
    # Always return 0? Not sure this is correct
# We need to make sure the repos are up-to-date so we can effectively install Clean out the directory if it exists for git to clone into
    # Use named, local variables
    # As you can see, these are the same variable names used in the last function,
    # but since they are local, their scope does not go beyond this function
    # This helps prevent the wrong value from being assigned if you were to set the variable as a GLOBAL one
    # A variable to store the message we want to display;
    # Again, it's useful to store these in variables in case we need to reuse or change the message;
    # we only need to make one change here
    # Make sure we know what directory we are in so we can move back into it
    # Move into the directory that was passed as an argument
    # Let the user know what's happening
    # Stash any local commits as they conflict with our working code
    git stash --all --quiet &> /dev/null || true # Okay for stash failure
    git clean --quiet --force -d || true # Okay for already clean directory
    # Pull the latest commits
    # Show a completion message
    # Move back into the original directory
# A function that combines the functions previously made
    # Setup named variables for the git repos
    # We need the directory
    # as well as the repo URL
    # A local variable containing the message to be displayed
    # Show the message
    # Check if the directory is a repository
        # Show that we're checking it
        # Update the repo, returning an error message on failure
    # If it's not a .git repo,
        # Show an error
        # Attempt to make the repository, showing an error on failure
    # echo a blank line
    # and return success?
# Reset a repo to get rid of any local changed
    # Use named variables for arguments
    # Move into the directory
    # Store the message in a variable
    # Show the message
    # Use git to remove the local changes
    # And show the status
    # Returning success anyway?
    # Detects IPv4 address used for communication to WAN addresses.
    # Accepts no arguments, returns no values.
    # Named, local variables
    # Find IP used to route to outside world by checking the the route to Google's public DNS server
    # Get just the interface IPv4 address
    # shellcheck disable=SC2059,SC2086
    # disabled as we intentionally want to split on whitespace and have printf populate
    # the variable with just the first field.
    printf -v IPv4bare "$(printf ${route#*src })"
    # Get the default gateway IPv4 address (the way to reach the Internet)
    # shellcheck disable=SC2059,SC2086
    printf -v IPv4gw "$(printf ${route#*via })"
    # Append the CIDR notation to the IP address, if valid_ip fails this should return
# Get available interfaces that are UP
    # There may be more than one so it's all stored in a variable
# A function for displaying the dialogs the user sees when first running the installer
    # Display the welcome dialog using an appropriately sized window via the calculation conducted earlier in the script
    # Request that users donate if they enjoy the software since we all work on it in our free time
    # Explain the need for a static address
# We need to make sure there is enough space before installing, so there is a function to check this
    # 50MB is the minimum space needed (45MB install (includes web admin bootstrap/jquery libraries etc) + 5MB one day of logs.)
    # - Fourdee: Local ensures the variable is only created, and accessible within this function/void. Generally considered a "good" coding practice for non-global variables.
    # Required space in KB
    # Calculate existing free space on this machine
    # If the existing space is not an integer,
        # show an error that we can't determine the free space
        # exit with an error code
    # If there is insufficient free disk space,
        # show an error message
        # if the vcgencmd command exists,
            # it's probably a Raspbian install, so show a message about expanding the filesystem
        # Show there is not enough free space
        # and exit with an error
    # Otherwise,
        # Show that we're running a disk space check
# A function that let's the user pick an interface to use with Pi-hole
    # Turn the available interfaces into an array so it can be used with a whiptail dialog
    # Number of available interfaces
    # Whiptail variable storage
    # Temporary Whiptail options storage
    # Loop sentinel variable
    # Find out how many interfaces are available to choose from
    # If there is one interface,
        # Set it as the interface to use since there is no other option
    # Otherwise,
        # While reading through the available interfaces
            # use a variable to set the option as OFF to begin with
            # If it's the first loop,
                # set this as the interface to use (ON)
            # Put all these interfaces into an array
        # Feed the available interfaces into this while loop
        # The whiptail command that will be run, stored in a variable
        # Now run the command using the interfaces saved into the array
        # If the user chooses Cancel, exit
        # For each interface
            # Set the one the user selected as the interface to use
            # and show this information to the user
# This lets us prefer ULA addresses over GUA
# This caused problems for some users when their ISP changed their IPv6 addresses
# See https://github.com/pi-hole/pi-hole/issues/1473#issuecomment-301745953
    # first will contain fda2 (ULA)
    # value1 will contain 253 which is the decimal value corresponding to 0xfd
    # will contain 162 which is the decimal value corresponding to 0xa2
    # the ULA test is testing for fc00::/7 according to RFC 4193
        # echoing result to calling function as return value
    # the GUA test is testing for 2000::/3 according to RFC 4291
        # echoing result to calling function as return value
    # the LL test is testing for fe80::/10 according to RFC 4193
        # echoing result to calling function as return value
# A dialog for showing the user about IPv6 blocking
    # Determine the IPv6 address used for blocking
    # For each address in the array above, determine the type of IPv6 address it is
        # Check if it's ULA, GUA, or LL by using the function created earlier
        # If it's a ULA address, use it and store it as a global variable
        # If it's a GUA address, we can still use it si store it as a global variable
    # Determine which address to be used: Prefer ULA over GUA or don't use any if none found
    # If the ULA_ADDRESS contains a value,
        # set the IPv6 address to the ULA address
        # Show this info to the user
    # Otherwise, if the GUA_ADDRESS has a value,
        # Let the user know
        # And assign it to the global variable
    # If none of those work,
        # explain that IPv6 blocking will not be used
        # So set the variable to be empty
    # If the IPV6_ADDRESS contains a value
        # Display that IPv6 is supported and will be used
# A function to check if we should use IPv4 and/or IPv6 for blocking ads
    # Named local variables
    # Let use select IPv4 and/or IPv6 via a checklist
    # In an array, show the options available:
    # IPv4 (on by default)
    # or IPv6 (on by default if available)
    # In a variable, show the choices available; exit if Cancel is selected
    # For each choice available,
        # Set the values to true
    # If IPv4 is to be used,
        # Run our function to get the information we need
    # If IPv6 is to be used,
        # Run our function to get this information
    # Echo the information to the user
    # If neither protocol is selected,
        # Show an error in red
        # and exit with an error
    # Local, named variables
    # 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
        # If they choose yes, let the user know that the IP address will not be available via DHCP and may cause a conflict.
    # Nothing else to do since the variables are already set above
    # 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
        # Ask for the IPv4 address
        # Cancelling IPv4 settings window
        # Ask for the gateway
        # Cancelling gateway settings window
        # Give the user a chance to review their settings before moving on
                # After that's done, the loop ends and we move on
            # If the settings are wrong, the loop continues
    # End the if statement for DHCP vs. static
# configure networking via dhcpcd
    # check if the IP is already in the file
    # If it's not,
        # we can append these lines to dhcpcd.conf to enable a static IP
        # Then use the ip command to immediately set the new address
        # Also give a warning that the user may need to reboot their system
# configure networking ifcfg-xxxx file found at /etc/sysconfig/network-scripts/
# this function requires the full path of an ifcfg file passed as an argument
    # Local, named variables
    # check if the desired IP is already set
    # Otherwise,
        # Put the IP in variables without the CIDR notation
        printf -v CIDR "%s" "${IPV4_ADDRESS##*/}"
        # Backup existing interface configuration:
        # Build Interface configuration file using the GLOBAL variables we have
        echo "# Configured via Pi-hole installer"
        # Use ip to immediately set the new address
        # If NetworkMangler command line interface exists and ready to mangle,
            # Tell NetworkManagler to read our new sysconfig file
        # Show a warning that the user may need to restart
    # Local, named variables
    # For the Debian family, if dhcpcd.conf exists,
        # configure networking via dhcpcd
    # If a DHCPCD config file was not found, check for an ifcfg config file based on interface name
        # If it exists,
    # if an ifcfg config does not exists for the interface name, try the connection name via network manager
            # If it exists,
    # If previous conditions failed, show an error and exit
# Check an IP address to see if it is a valid one
    # Local, named variables
    # If the IP matches the format xxx.xxx.xxx.xxx,
        # Save the old Internal Field Separator in a variable
        # and set the new one to a dot (period)
        # Put the IP into an array
        # Restore the IFS to what it was
        ## Evaluate each octet by checking if it's less than or equal to 255 (the max for each octet)
        # Save the exit code
    # Return the exit code
# A function to choose the upstream DNS provider(s)
    # Local, named variables
    # In an array, list the available upstream providers
    # In a whiptail dialog, show the options
    # exit if Cancel is selected
    # Display the selection
    # Depending on the user's choice, set the GLOBAl variables to the IP of the respective provider
            # Until the DNS settings are selected,
                # If the first
                    # and second upstream servers do not exist
                    # Otherwise,
                # Dialog for the user to enter custom upstream servers
                # Clean user input and replace whitespace with comma.
                printf -v PIHOLE_DNS_2 "%s" "${piholeDNS##*,}"
                # If the IP is valid,
                    # store it in the variable so we can use it
                # Do the same for the secondary server
                # If either of the DNS servers are invalid,
                    # explain this to the user
                    # and set the variables back to nothing
                # Since the settings will not work, stay in the loop
                # Otherwise,
                    # Show the settings
                    # and break from the loop since the servers are valid
                    # Otherwise,
                        # If the settings are wrong, the loop continues
# Allow the user to enable/disable logging
    # Local, named variables
    # Ask if the user wants to log queries
    # The default selection is on
    # Get the user's choice
        # If it's on
            # Set the GLOBAL variable to true so we know what they selected
        # Otherwise, it's off,
            # So set it to false
# Allow the user to set their FTL privacy level
    # The default selection is level 0
    # Get the user's choice
# Function to ask the user if they want to install the dashboard
    # Local, named variables
    # Similar to the logging function, ask what the user wants
    # with the default being enabled
    # Depending on their choice
            # Set it to true
            # or false
    # Request user to install web server, if --disable-install-webserver has not been used (INSTALL_WEB_SERVER=true is default).
        # with the default being enabled
        # Depending on their choice
                # set it to true, as clearly seen below.
                # or false
# A function to display a list of example blocklists for users to select
    # Back up any existing adlist file, on the off chance that it exists. Useful in case of a reconfigure.
    # Let user select (or not) blocklists via a checklist
    # In an array, show the options available (all off by default):
    # In a variable, show the choices available; exit if Cancel is selected
    # For each choice available,
# Accept a string parameter, it must be one of the default lists
# This function allow to not duplicate code in chooseBlocklists and
# in installDefaultBlocklists
# Used only in unattended setup
# If there is already the adListFile, we keep it, else we create it using all default lists
    # In unattended setup, could be useful to use userdefined blocklist.
    # If this file exists, we avoid overriding it.
# Check if /etc/dnsmasq.conf is from pi-hole.  If so replace with an original and install new in .d directory
    # Local, named variables
    # If the dnsmasq config file exists
        # If gravity.list is found within this file, we presume it's from older versions on Pi-hole,
            # so backup the original file
            # and replace it with the default
        # Otherwise,
        # Don't to anything
        # If a file cannot be found,
        # restore the default one
    # Check to see if dnsmasq directory exists (it may not due to being a fresh install and dnsmasq no longer being a dependency)
    # Copy the new Pi-hole DNS config file into the dnsmasq.d directory
    # Replace our placeholder values with the GLOBAL DNS variables that we populated earlier
    # First, swap in the interface to listen on
        # Then swap in the primary DNS server
        # Then swap in the primary DNS server
    sed -i 's/^#conf-dir=\/etc\/dnsmasq.d$/conf-dir=\/etc\/dnsmasq.d/' ${dnsmasq_conf}
    # If the user does not want to enable logging,
        # Disable it by commenting out the directive in the DNS config file
        sed -i 's/^log-queries/#log-queries/' ${dnsmasq_pihole_01_location}
    # Otherwise,
        # enable it by uncommenting the directive in the DNS config file
        sed -i 's/^#log-queries/log-queries/' ${dnsmasq_pihole_01_location}
# Clean an existing installation to prepare for upgrade/reinstall
    # Local, named variables
    # ${1} Directory to clean
    # Make ${2} the new one?
    # ${2} Array of files to remove
    # For each script found in the old files array
        # Remove them
# Install the scripts from repository to their various locations
    # Local, named variables
    # Clear out script files from Pi-hole scripts directory.
    # Install files from local core repository
        # move into the directory
        # Install the scripts by:
        #  -o setting the owner to the user
        #  -Dm755 create all leading components of destination except the last, then copy the source to the destination and setting the permissions to 755
        # This first one is the directory
        # The rest are the scripts Pi-hole needs
    # Otherwise,
        # Show an error and exit
# Install the configs from PI_HOLE_LOCAL_REPO to their various locations
    # Make sure Pi-hole's config files are in place
    # Install empty file if it does not exist
    # Install an empty regex file
        # Let PHP edit the regex file, if installed
    # If the user chose to install the dashboard,
        # and if the Web server conf directory does not exist,
            # make it
            # and set the owners
        # Otherwise, if the config file already exists
            # back up the original
        # and copy in the config file Pi-hole needs
        # Make sure the external.conf file exists, as lighttpd v1.4.50 crashes without it
        # if there is a custom block page in the html/pihole directory, replace 404 handler in lighttpd config
        # Make the directories if they do not exist and set the owners
    # Copy Pi-hole man pages and call mandb to update man page database
    # Default location for man files for /usr/local/bin is /usr/local/share/man
    # on lightweight systems may not be present, so check before copying.
        # if mandb is not present, no manpage support
        # appropriate directory for Pi-hole's man page is not present
        # if not present, create man8 directory
        # if not present, create man8 directory
    # Testing complete, copy the files & update the man db
        # Updated successfully
        # Something is wrong with the system's man installation, clean up
        # our files, (leave everything how we found it).
    # Stop service passed in as argument.
    # Can softfail, as process may not be installed when this is called
# Start/Restart service passed in as argument
    # Local, named variables
    # If systemctl exists,
        # use that to restart the service
    # Otherwise,
        # fall back to the service command
# Enable service so that it will start with next reboot
    # Local, named variables
    # If systemctl exists,
        # use that to enable the service
    # Otherwise,
        # use update-rc.d to accomplish this
# Disable service so that it will not with next reboot
    # Local, named variables
    # If systemctl exists,
        # use that to disable the service
    # Otherwise,
        # use update-rc.d to accomplish this
    # If systemctl exists,
        # use that to check the status of the service
    # Otherwise,
        # fall back to service command
# Systemd-resolved's DNSStubListener and dnsmasq can't share port 53.
    # Check if Systemd-resolved's DNSStubListener is enabled and active on port 53
        # Check if DNSStubListener is enabled
        if ( grep -E '#?DNSStubListener=yes' /etc/systemd/resolved.conf &> /dev/null ); then
            # Disable the DNSStubListener to unbind it from port 53
            # Note that this breaks dns functionality on host until dnsmasq/ftl are up and running
            # Make a backup of the original /etc/systemd/resolved.conf
            # (This will need to be restored on uninstallation)
            sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf
    # Running apt-get update/upgrade with minimal output can cause some issues with
    # requiring user input (e.g password for phpmyadmin see #218)
    # Update package cache on apt based OSes. Do this every time since
    # it's quick and packages can be updated at any time.
    # Local, named variables
    # Create a command from the package cache variable
    # Otherwise,
        # show an error and exit
# Let user know if they have outdated packages on their system and
# advise them to run a package update at soonest possible.
    # Local, named variables
    # Store the list of packages in a variable
# What's this doing outside of a function in the middle of nowhere?
    # Local, named variables should be used here, especially for an iterator
    # Add one to the counter
    # If it equals 1,
    # Install packages passed in via argument array
    # No spinner - conflicts with set -e
    # Debian based package install - debconf will download the entire package list
    # so we just create an array of packages not currently installed to cut down on the
    # amount of download traffic.
    # NOTE: We may be able to use this installArray in the future to create a list of package that were
    # installed by us, and remove only the installed packages, and not the entire list.
        # For each package,
        if [[ "${#installArray[@]}" -gt 0 ]]; then
    # Install Fedora/CentOS packages
    if [[ "${#installArray[@]}" -gt 0 ]]; then
# Install the Web interface dashboard
    # Install the directory
    # and the blockpage
    # Remove superseded file
    # If the default index file exists,
        # back it up
    # Otherwise,
        # don't do anything
    # Install Sudoers file
    # Make the .d directory if it doesn't exist
    # and copy in the pihole sudoers file
    # Add lighttpd user (OS dependent) to sudoers file
    # If the Web server user is lighttpd,
        # Allow executing pihole via sudo with Fedora
        # Usually /usr/local/bin is not permitted as directory for sudoable programs
    # Set the strict permissions on the file
# Installs a cron file
    # Install the cron job
    # Copy the cron file over from the local repo
    # Randomize gravity update time
    # Randomize update checker time
# Gravity is a very important script as it aggregates all of the domains into a single HOSTS formatted list,
# which is what Pi-hole needs to begin blocking ads
    # Run gravity in the current shell
# Check if the pihole user exists and create if it does not
    # If the user pihole exists,
        # just show a success
    # Otherwise,
        # create her with the useradd command
# Allow HTTP and DNS traffic
    # If a firewall is running,
        # ask if the user wants to install Pi-hole's default firewall rules
        # Allow HTTP and DNS traffic
        # Reload the firewall to apply these changes
        # Check for proper kernel modules to prevent failure
    # If chain Policy is not ACCEPT or last Rule is not ACCEPT
    # then check and insert our Rules above the DROP/REJECT Rule.
            # Check chain first, otherwise a new rule will duplicate old ones
    # Otherwise,
        # no firewall is running
        # so just exit
    # If the Web interface is not set to be installed,
        # and if there is not an IPv4 address,
            # there is no block page, so set IPv4 to (all IP addresses)
            # and IPv6 to ::/0
    # If the setup variable file exists,
        # update the variables in the file
    # echo the information to the user
    # Set the privacy level
    # Bring in the current settings and the functions to manipulate them
    # Look for DNS server settings which would have to be reapplied
    # Look for DHCP server settings which would have to be reapplied
# Install the logrotate script
    # Copy the file over from the local repo
    # Different operating systems have different user / group
    # settings for logrotate that makes it impossible to create
    # a static logrotate file that will work with e.g.
    # Rasbian and Ubuntu at the same time. Hence, we have to
    # customize the logrotate script here in order to reflect
    # the local properties of the /var/log directory
    # If the variable has a value,
        sed -i "s/# su #/su ${logusergroup}/g;" /etc/pihole/logrotate
# At some point in the future this list can be pruned, for now we'll need it to ensure updates don't break.
# Refactoring of install script has changed the name of a couple of variables. Sort them out here.
    # Add 'INSTALL_WEB_SERVER', if its not been applied already: https://github.com/pi-hole/pi-hole/pull/2115
# Install base files and web interface
    # Create the pihole user
    # If the user wants to install the Web interface,
            # make the Web directory if necessary
            # Set the owner and permissions
            # Give pihole access to the Web server group
            # If the lighttpd command is executable,
                # enable fastcgi and fastcgi-php
                # Otherwise, show info about installing them
    # For updates and unattended install.
    # Install base files and web interface
    # Install config files
    # If the user wants to install the dashboard,
        # do so
    # Install the cron file
    # Install the logrotate file
    # Check if FTL is installed
    # Configure the firewall
    # install a man page entry for pihole
    # Update setupvars.conf with any variables that may or may not have been changed during the install
# SELinux
    # If the getenforce command exists,
        # Store the current mode in a variable
        # If it's enforcing,
            # Explain Pi-hole does not support it yet
# Installation complete message with instructions for the user
    # If
    if [[ "${#1}" -gt 0 ]] ; then
        # else, if the dashboard password in the setup variables exists,
        # set a variable for evaluation later
        # set a variable for evaluation later
    # If the user wants to install the dashboard,
        # Store a message in a variable and display it
    # Final completion message to user
    # If pihole -r "reconfigure" option was selected,
        # set some variables that will be used
    # Otherwise,
        # set some variables with different values
    # Display the information to the user
    # Set the variable based on if the user chooses
        # repair, or
        # reconfigure,
    # Add upstream branches to shallow clone
    # Return available branches
    # Get reachable remote branches, but store STDERR as STDOUT variable
    # echo status for calling function to capture
    # Check out specified branch
    # Set the reference for the requested branch, fetch, check it put and pull it
    # Check out specified branch
    # If the user wants to reconfigure,
        # Reset the Core repo
        # If the Web interface was installed,
            # reset it's repo
    # Otherwise, a repair is happening
        # so get git files for Core
        # If the Web interface was installed,
            # get the Web git files
# Download FTL binary to random temp directory and install FTL binary
    # Local, named variables
    # Find the latest version tag for FTL
    # Tags should always start with v, check for that.
    # Move into the temp ftl directory
    # Always replace pihole-FTL.service
    # Determine which version of FTL to download
    # If the download worked,
        # get sha1 of the binary we just downloaded for verification.
        # If we downloaded binary file (as opposed to text),
            # Stop FTL
            # Install the new version with the correct permissions
            # Move back into the original directory the user was in
            # Install the FTL service
            # dnsmasq can now be stopped and disabled if it exists
            # Backup existing /etc/dnsmasq.conf if present and ensure that
            # /etc/dnsmasq.conf contains only "conf-dir=/etc/dnsmasq.d"
            # Create /etc/dnsmasq.conf
        # Otherwise,
            # the download failed, so just go back to the original directory
    # Otherwise,
        # The URL could not be found
    # This gives the machine architecture which may be different from the OS architecture...
    # If the machine is arm or aarch
        # ARM
            # set the binary to be used
                # set the binary to be used
            # Otherwise,
                # set the binary to be used
            # set the binary to be used
        # This gives the architecture of packages dpkg installs (for example, "i386")
        # Special case: This is a 32 bit OS, installed on a 64 bit machine
        # -> change machine architecture to download the 32 bit executable
            # 64bit
            # set the binary to be used
        # Something else - we try to use 32bit executable and warn the user
    #In the next section we check to see if FTL is already installed (in case of pihole -r).
    #If the installed version matches the latest version, then check the installed sha1sum of the binary vs the remote sha1sum. If they do not match, then download
    # if dnsmasq exists and is running at this point, force reinstall of FTL Binary
        #Check whether or not the binary for this FTL branch actually exists. If not, then there is no update!
        # shellcheck disable=SC1090
            # We already have a pihole-FTL binary downloaded.
            # Alt branches don't have a tagged version against them, so just confirm the checksum of the local vs remote to decide whether we download or not
# Detect suitable FTL binary platform
    # Create a random temporary file for the log
    # Open handle 3 for templog
    # https://stackoverflow.com/questions/18460186/writing-outputs-to-log-file-and-console
    # Delete templog, but allow for addressing via file handle
    # This lets us write to the log without having a temporary file on the drive, which
    # is meant to be a security measure so there is not a lingering file on the drive during the install process
    # Copy the contents of file descriptor 3 into the install log
    # Since we use color codes such as '\e[1;33m', they should be removed
    ######## FIRST CHECK ########
    # Must be root to install
    # If the user's id is zero,
        # they are root and all is good
        # Show the Pi-hole logo so people know it's genuine since the logo and name are trademarked
    # Otherwise,
        # They do not have enough privileges, so let the user know
        # If the sudo command exists,
            # Download the install script and run it with admin rights
        # Otherwise,
            # Let them know they need to run it as root
    # Check for supported distribution
    # If the setup variable file exists,
        # if it's running unattended,
            # Use the setup variables
            # also disable debconf-apt-progress dialogs
        # Otherwise,
            # show the available options (repair/reconfigure)
    # Start the installer
    # Verify there is enough disk space for the install
    # Update package cache
    # Notify user of package availability
    # Install packages used by this installation script
    # Check if SELinux is Enforcing
        # Display welcome dialogs
        # Create directory for Pi-hole storage
        # Determine available interfaces
        # Find interfaces and let the user choose one
        # Decide what upstream DNS Servers to use
        # Give the user a choice of blocklists to include in their install. Or not.
        # Let the user decide if they want to block ads over IPv4 and/or IPv6
        # Let the user decide if they want the web interface to be installed automatically
        # Let the user decide if they want query logging enabled...
        # Let the user decide the FTL privacy level
        # Setup adlist file if not exists
        # Source ${setupVars} to use predefined user variables in the functions
        # Get the privacy level if it exists (default is 0)
            # If no setting was found, default to 0
    # Clone/Update the repos
    # Install the Core dependencies
        # Install the Web dependencies
    # On some systems, lighttpd is not enabled on first install. We need to enable it here if the user
    # has chosen to install the web interface, else the `LIGHTTPD_ENABLED` check will fail
    # Determine if lighttpd is correctly enabled
    # Install and log everything to a file
    # Copy the temp log file into final log location for storage
        # Add password to web UI if there is none
        # If no password is set,
            # generate a random password
            # shellcheck disable=SC1091
    # Check for and disable systemd-resolved-DNSStubListener before reloading resolved
    # DNSStubListener needs to remain in place for installer to download needed files,
    # so this change needs to be made after installation is complete,
    # but before starting or resarting the dnsmasq or ftl services
    # If the Web server was installed,
    # Start services
    # Enable FTL
    # Ensure the service is enabled before trying to start it
    # Fixes a problem reported on Ubuntu 18.04 where trying to start
    # the service before enabling causes installer to exit
    # Download and compile the aggregated block list
    # Force an update of the updatechecker
    # If the Web interface was installed,
        # If there is a password,
        if (( ${#pw} > 0 )) ; then
            # display the password
        # If the Web interface was installed,
        # Explain to the user how to use Pi-hole as their DNS server
    # Display where the log file is

The Install Log / Notes On Screen

root@PocketPi:/usr/local/pihole# ./Pihole.sh 

  [✓] Root user check

         :cccclll:.      ..,,
          :ccccclll.   ;ooodc
           'ccll:;ll .oooodc
                 .. ','.
        .........  ....  .........
        ..........      ..........
        ..........      ..........
        .........  ....  .........

  [✓] Disk space check
  [✓] Update local cache of available packages

  [✓] Checking apt-get for upgraded packages... up to date!

  [i] Installer Dependency checks...
  [✓] Checking for apt-utils
  [i] Checking for dialog (will be installed)
  [✓] Checking for debconf
  [i] Checking for dhcpcd5 (will be installed)
  [✓] Checking for git
  [✓] Checking for iproute2
  [✓] Checking for whiptail
  [i] Using interface: eth0
  [i] Using Cloudflare servers
  [✓] Set IP address to 
  You may need to restart after the install is complete
  [i] Unable to find IPv6 ULA/GUA address, IPv6 adblocking will not be enabled
  [i] IPv4 address:
  [i] IPv6 address: 
  [i] Web Interface On
  [i] Web Server On
  [i] Logging On.
  [✗] Check for existing repository in /etc/.pihole
  [✓] Clone https://github.com/pi-hole/pi-hole.git into /etc/.pihole

  [✗] Check for existing repository in /var/www/html/admin
  [✓] Clone https://github.com/pi-hole/AdminLTE.git into /var/www/html/admin

  [i] Main Dependency checks...
  [i] Checking for bc (will be installed)
  [✓] Checking for cron
  [✓] Checking for curl
  [✓] Checking for dnsutils
  [✓] Checking for iputils-ping
  [i] Checking for lsof (will be installed)
  [i] Checking for netcat (will be installed)
  [✓] Checking for psmisc
  [✓] Checking for sudo
  [✓] Checking for unzip
  [✓] Checking for wget
  [i] Checking for idn2 (will be installed)
  [i] Checking for sqlite3 (will be installed)
  [✓] Checking for libcap2-bin
  [✓] Checking for dns-root-data
  [i] Checking for resolvconf (will be installed)
  [i] Checking for lighttpd (will be installed)
  [i] Checking for php-common (will be installed)
  [i] Checking for php-cgi (will be installed)
  [i] Checking for php-sqlite3 (will be installed)
  [✓] Enabling lighttpd service to start on reboot...
  [✓] Creating user 'pihole'
  [✓] Installing scripts from /etc/.pihole

  [i] Installing configs from /etc/.pihole...
  [i] Existing dnsmasq.conf found... it is not a Pi-hole file, leaving alone!
  [✓] Copying 01-pihole.conf to /etc/dnsmasq.d/01-pihole.conf

  [i] Installing blocking page...
  [✓] Creating directory for blocking page, and copying files
  [✓] Backing up index.lighttpd.html

  [✓] Installing sudoer file

  [✓] Installing latest Cron script

  [✓] Installing latest logrotate script

  [i] FTL Checks...

  [✓] Detected ARM-aarch64 architecture
  [i] Checking for existing FTL binary...
  [✓] Downloading and Installing FTL
  [i] FTL can now resolve DNS Queries without dnsmasq running separately
  [✓] Stopping dnsmasq service...
  [✓] Disabling dnsmasq service...
  [i] Backing up /etc/dnsmasq.conf to /etc/dnsmasq.conf.old

  [i] Skipping firewall configuration
  [✓] man pages installed and database updated
  [i] Testing if systemd-resolved is enabled
  [i] Systemd-resolved is not enabled
  [✓] Starting lighttpd service...
  [✓] Enabling lighttpd service to start on reboot...
  [i] Restarting services...
  [✓] Enabling pihole-FTL service to start on reboot...
  [✓] Starting pihole-FTL service...
  [✓] Deleting existing list cache
  [i] Pi-hole blocking is enabled
  [i] Neutrino emissions detected...
  [✓] Pulling blocklist source list into range

  [i] Target: raw.githubusercontent.com (hosts)
  [✓] Status: Retrieval successful

  [i] Target: mirror1.malwaredomains.com (justdomains)
  [✓] Status: Retrieval successful

  [i] Target: sysctl.org (hosts)
  [✓] Status: Retrieval successful

  [i] Target: zeustracker.abuse.ch (blocklist.php?download=domainblocklist)
  [✓] Status: Retrieval successful

  [i] Target: s3.amazonaws.com (simple_tracking.txt)
  [✓] Status: Retrieval successful

  [i] Target: s3.amazonaws.com (simple_ad.txt)
  [✓] Status: Retrieval successful

  [i] Target: hosts-file.net (ad_servers.txt)
  [✓] Status: Retrieval successful

  [✓] Consolidating blocklists
  [✓] Extracting domains from blocklists
  [i] Number of domains being pulled in by gravity: 159557
  [✓] Removing duplicate domains
  [i] Number of unique domains trapped in the Event Horizon: 136336
  [i] Nothing to whitelist!
  [i] Number of regex filters: 0
  [✓] Parsing domains into hosts format
  [✓] Cleaning up stray matter

  [✓] Force-reloading DNS service
  [✓] DNS service is running
  [i] Pi-hole blocking will be enabled
  [i] Enabling blocking
  [✓] Reloading DNS service
  [✓] Pi-hole Enabled
  [i] Web Interface password: OwnIGLeS_
  [i] This can be changed using 'pihole -a -p'

  [i] View the web interface at http://pi.hole/admin or

  [i] You may now configure your devices to use the Pi-hole as their DNS server
  [i] Pi-hole DNS (IPv4):
  [i] If you set a new IP address, please restart the server running the Pi-hole

  [i] The install log is located at: /etc/pihole/install.log

Subscribe to feed

About E.M.Smith

A technical managerial sort interested in things from Stonehenge to computer science. My present "hot buttons' are the mythology of Climate Change and ancient metrology; but things change...
This entry was posted in Tech Bits and tagged , , , . Bookmark the permalink.

38 Responses to Pocket PiHole

  1. E.M.Smith says:

    Well, looks like it is doing a nice job of blocking the intrusive Google crap:
    (scroll right to see the whole record)

    2018-12-16 18:07:12 	A	www.google-analytics.com	ems-macbook-air.chiefio.home	Blocked (gravity)	
    2018-12-16 18:08:08 	A	pixel.wp.com	ems-macbook-air.chiefio.home	Blocked (gravity)	- (0.3ms)	
    2018-12-16 18:07:57 	A	googleads.g.doubleclick.net	ems-macbook-air.chiefio.home	Blocked (gravity)
    2018-12-16 18:05:56 	A	static.doubleclick.net	ems-macbook-air.chiefio.home	Blocked (gravity)

    And a whole lot more. Running about 15% of my DNS lookups going to “blocked”. That’s a whole lot of bytes on the wire blocked too ;-)

  2. Larry Ledwick says:

    Not directly related but I have recently switched to hard coded DNS lookup from the new cloudflare dns and it seems to be working very well. Not quite as good as your method but all dns queries are anonymous and very fast. Might try them as your external dns when you need to go to global web to find something.

    DNS Servers . . . . . . . . . . . :
    . . . . . . . . . . . . . . . . . . . . . . :

  3. E.M.Smith says:

    In the http interface, under settings, privacy, it has a nice set of choices (Each of these is a menu choice):

    DNS resolver privacy level

    Specify if DNS queries should be anonymized, available options are:
    Show everything and record everything
    Gives maximum amount of statistics
    Hide domains: Display and store all domains as “hidden”
    This disables the Top Domains and Top Ads tables on the dashboard
    Hide domains and clients: Display and store all domains as “hidden” and all clients as “”
    This disables all tables on the dashboard
    Anonymous mode: This disables basically everything except the live anonymous statistics
    No history is saved at all to the database, and nothing is shown in the query log. Also, there are no top item lists.
    No Statistics mode: This disables all statistics processing. Even the query counters will not be available.
    Note that regex blocking is not available when query analyzing is disabled.
    Additionally, you can disable logging to the file /var/log/pihole.log using sudo pihole logging off.

    The privacy level may be increased at any time without having to restart the DNS resolver. However, note that the DNS resolver needs to be restarted when lowering the privacy level. This restarting is automatically done when saving.

    I like that. You can choose to have your DNS history lost.

    This article details how to use PiHole with DNScrypt to make your DNS traffic invisible to your ISP (and prevent DNS Hijackng). So that is next on my list todo.


    At that point your DNS use and history becomes truly private.

    Switching DNS providers would be an easy way to subvert restrictions on copyright infringing material that ISPs are legally ordered to block by the High Court, and surprisingly enough ISPs are savvy to this. Whilst HTTPS traffic is encrypted, DNS traffic (on port 53) is not. DNS has remained relatively untouched since its inception in 1985 and has lagged behind the curve when it comes to privacy (although they did take a stab at it with DNSSEC). The fact that DNS traffic moves around in plaintext makes it trivial for ISPs to soak up traffic bound for port 53 when destined (for example) to Google’s DNS servers and replace the response to point to their own destination. Additionally, although the content of the sites you browse may use HTTPS, the fact that you visited that site is completely transparent to any snooping party.

    I recently setup my home DNS server to encrypt all outbound DNS requests from my LAN. This traffic is in fact completely indistinguishable from web traffic, as it too all happens over port 443. Hopefully this post can serve as a tutorial for anyone who wishes to do this themselves!

    He uses a neat trick of 127.10.10.x addresses to have DNScrypt tunnels show up on localhost, then points PiHole at them! Suddenly all PiHole DNS queries go via encrypted tunnel to the server (and country!) of your choice. Neatly bypassing DNS based geography blocks and ISP snooping or interference.

    This is way cool!

    I’ll be doing those changes in the next few hours or tomorrow morning.

  4. E.M.Smith says:


    My PiHole points to Cloudflare as the upstream ;-)

    I’ll likely add another site too as I turn on DNSCrypt. It will depend on who supports it…

    But yeah, we’re thinking in the same path.

  5. E.M.Smith says:

    This is another “How to install PiHole” posting:

    He does it more command line & long hand:

    Install Pi-hole
    Install git and net-tools packages.
    $ sudo apt-get install git net-tools
    Clone pi-hole repository.
    $ git clone --depth 1 https://github.com/pi-hole/pi-hole.git pi-hole
    Execute installation script.
    $ sudo bash pi-hole/automated\ install/basic-install.sh 

    That last script launches similar configure ncruses panels as the all up version I used, but his site specific set up is SystemD / Pi centric.

    It does show you all the Q&A panels you will get in his posting.

    Then he has a lot of the command line configuration choices if you choose not to use the web admin panel:

    Add domain to the whitelist.
    $ pihole -w example.com
    Remove domain from the whitelist.
    $ pihole -w -d example.com
    List blacklisted domains.
    $ pihole -b -l

    At the bottom, a couple of nice links. One to another DNScrypt page:


    Another to a large blocklist repository:


    The Big Blocklist Collection

    The Internet is full of unsavoury content: advertisers wanting to sell you stuff you don’t need, trackers extracting and selling your data as if it were oil, and malicious content vying to hijack your favourite device. This collection hopes to help you minimise these issues, and to maintain a more enjoyable online presence, using the wonderful, free and open source utility known as Pi-hole.

    On arrival, like a growing number of websites, Forbes asked readers to turn off ad blockers in order to view the article. After doing so, visitors were immediately served with pop-under malware, primed to infect their computers, and likely silently steal passwords, personal data and banking information. Or, as is popular worldwide with these malware “exploit kits,” lock up their hard drives in exchange for Bitcoin ransom.
    ‘Forbes Site, After Begging You To Turn Off Adblocker, Serves Up A Steaming Pile Of Malware ‘Ads” – Techdirt, 2016

    Before starting, here are some reading points:

    Lists bulleted with a tick are least likely to interfere with browsing
    Lists bulleted with a cross block multiple useful sites (e.g: Pi-hole updates, Amazon, Netflix)
    A guide on how to add these lists is found here
    If you wish to automate the update of your adlists.list, a text-only version is found here
    Using lists hosted at v.firebog.net allows me to view very basic ongoing aggregated statistics via CloudFlare
    These lists are painstakingly curated by their respective maintainers. Please contact them first if you find false positives
    Avoid using mirrored consolidated lists, if possible; it deprives the original list maintainer of visits (meaning they may be less inclined to keep it up to date!)

    So some alternate POV / way / docs on the setup…

  6. E.M.Smith says:

    Well, that dnscrypt page was doing things the 1.0 way and “everything is different now” in 2.0


    So you do it that way instead… (and another couple of hours of my life go down the change hole).

    The list of available servers is set automagically for you so if you want to make it particuliar ones you now look here:
    and not in that config file specified…

    They have an install wiki:
    that points to a particular version with PiHole:
    (It stated on that page they have versions of dnscrypt for iOS, Android, etc. with links)
    The pihole one is where I started from at the link above…

    I note on that last page this ringing endorsement of Google (and Cisco) … NOT!!

    Test site — Note that the output of this test is not enough to confirm the absence of leaks. In particular, Cisco and Google will transparently send a copy of your real network address to companies they partner with (edns-clientsubnet mechanism).

    So I’ll be looking to NOT use any Google services or DNS sites and as soon as this is all running cleanly I’ll be looking into running through a VPN… I’ve already done a VPN from the tablet, so not that big a leap, but still, one more layer…

    I did follow their directions and the install went easy & quick. Then I backed it out until I can figure out what DNS providers I want to use, how many, and what geographies. I’d also done an apt-get install dnscrypt-proxy so that was in /usr/local/bin too and not needed. Essentially I’d done some of each path and needed to back out to zero and restart ;-) So now that I’ve done it 1.5 x I’m ready to do it right… almost ;-)

  7. CoRev says:

    Thanks E.M. for breaking this ground for us. I too was messing, unsuccessfully, with my Pi M3 and pihole this weekend.

    On a Rock64/Rockpro64 side note, remember my mentioning that separate PSU thing I mentioned? Well don’t make your (mine) life more complex and expensive by crossing the polarity of the connections. IT DOES LET THE SMOKE OUT OF YOUR Rock64.

    After i ordered a Rockpro64 replacement, and totally agree with your prior analysis, the the OS versions are still too early for prime time. Like you I did not get the DietPi desk top to load with boot. Went to look it over on the Pi M3 install and decided to stay with the ayufan Ubuntu install. Even that is not completely operational and when installing parts and pieces after initial install tends to break it.

    The bottom line is that once more mature the Rockpro64 should be as fast as my current MS desk top machine, and will eventually become my daily driver. I’m not sure it will ever be stable enough for my wife’s use.

    These things have been my Winter indoors projects for the past few years. Maybe by next Winter the Rockpro64 will have stabilized???

  8. E.M.Smith says:

    Some times….

    So I wanted to move my PiHole from the testing network to the whole house net. Change of IP. Bring it up (turning off DHCP)…

    The OS sees the new IP (set in /etc/network/interfaces) but the managment screen of PiHole still says the 10.x address… WT?

    Some searching later…

    Seems PiHole things it can serve DNS out an address that isn’t on any interface. It sets the IP address in a file…

    root@PocketPi:/etc/pihole# ls -l setupVars.conf 
    -rw-r--r-- 1 root root 599 Dec 17 22:34 setupVars.conf
    root@PocketPi:/etc/pihole# head setupVars.conf 

    Why? Don’t ask why, down that path lies insanity and ruin…

  9. E.M.Smith says:

    And more network nuttyness….

    wpa_supplicant.conf isn’t right OR wifi just doesn’t play well with PiHole or something. Can’t get it to work as both access point and pihole, I’ve found several different modes of failure though :-)

    Also a THIRD config file with the IP num in it… /etc/dhcpcd.conf or some such. Why on God’s Earth folks keep duplicating config data that ought to be set in ONE Place is beyond me.

    Seems about every 5 years someone trys to make over networking configs and adds another parrallel system. Then the GUI managers packrat stuff in their configs and casches. It was better when you just put an interface in the interfaces file and said “ifup”…

    So I’m knocking off for a while to sort out networking config another day…

  10. E.M.Smith says:

    Just using vanilla PiHole as ad blocker DNS server works well. Using the tablet to look at typically ad heavy sites like The Newyorker or National Enquirer is spooky in how ad free they are…

    FWIW I’ve decided to set up one PiHole just dedicated to the house and a second for portable.

  11. CoRev says:

    E.M. thanks for doing the ground breaking. I also want to use PiHole for the house or at lest my cluster and personal computers.

    BTW, my 1st impressions of the Rockpro64 are same as yours,software support not mature enough for prime time. I do like its speed, and when mature it or something of its performance caliber will become my daily driver.

    If you remember I was playing with a separate PSU build, well my experience is be CAREFUL when connecting the lines. I swapped them and let the smoke out of my Rock64?!? Now, a Rockpro64 owner.

  12. E.M.Smith says:


    Found your first comment off in SPAM (no clue why) and fished it out. So both are up here now.

    Sorry to hear about your Rock64 being smoked! The good news is it is a cheap board to buy a replacement! OTOH, it is just a slightly faster R.Pi M3 with USB 3.0 interface. Though I have forgotten if it has WiFi built in… (I don’t use wifi for most things Pi …)

    Since the PSUs for these things are so cheap I’ve not bothered building one, but as I pointed out in another thread, the round bbl connectors can match size with different volts. The XU4 uses a 5V of a size that matches the 12 V RockPro64… so I’ve adopted the habit of physically removing those PSUs from the desktop and only moving them with the board into / out of service. I almost stuck the 12 v into my 5 v XU4 and I’m sure it would have smoked. Lucky for me the other end was also unplugged and I noticed in time.

    I’m also quite impressed with the RockPro64 speed. I’m hoping a clean Debian / Devuan / Armbian port shows up soon. At present I’m still using the Odroid XU4 in preference as it is also quite fast, but software more mature and stable. I think in about 6 months the RockPro64 will be “mature enough” on the SW front and that in a year it will be quite nice. Until then I’ll be using it from time to time as more project testing than Daily Driver. But that is the joy of having more SBCs than monitors… you can rotate them to use each one for what it does best or what you want at the moment ;-)

    The Odroid XU4 has A15 cores, so only 32 bit, but fast and 4 of them. It is very much slower on bulk 64 bit math than the A72 cores that are native 64 bit, but I don’t know how much that matters to daily stuff. I’m looking at the RockPro64 as a great cluster compute engine, though. Once I get motivated to go back to that parallel computes / modeling project… As the software ports to it get cleaned up it will become a great desktop Daily Driver. The single core performance and large memory let it really fly even on single threaded processes. It is even big enough to run FireFox ;-)

    Per PiHole on Pi M3: Why unsuccessful? On Devuan I just ran the script and it was pretty much a done deal. Only really hit problems when I tried to convert it to a router / WiFi access point too.

    You might want to try a fresh uSD chip, direct Devuan 2.0 install, update/upgrade, and run the script. That’s basically all I did (other than giving it a fixed IP address). I did install some packages that I typically use (like file systems, nfs, lxde, etc.) but don’t see how those would be an issue. I’m going to re-do it all in the next day or two and I’ll post my build script then. I was hoping to get WiFi Access Point running first, but now I’m thinking that may need to become 2 separate steps / postings…

  13. E.M.Smith says:

    This comment is coming to you via the Macbook, WiFi to a Raspberry Pi M3 AP (Access Point) running PiHole. 99% Success!

    The 1% is I need to go back to the PiHole and tell it to serve DNS to this interface… so at present I’m using my old DNS server Pi that is all of one IP digit different – so I know all the networking is working and it is just that the PiHole thinks it only ought to respond out the Ethernet hardwire for DNS requests…

    Now I I can just remember and recreate what I did ;-)

    The Final Bit was just that in the /etc/hostapd/hostapd.conf file I had a – where _ was required in one of the config names… Running hostapd manually told me that. Finding out you could run it manually took most of the morning to realize:

    hostapd /etc/hostapd/hostapd.conf

    as root gave me the error message that line 3 had a name hw- that was wrong…

  14. E.M.Smith says:

    Well, it survives a reboot and is now serving up dhcp IP addresses to the WiFi port as well!

    As of now, I’ve got a fully operational and configured WiFi Access Point / PiHole device.

    I’m going to make an archive copy of the chip, then make a summary posting of config, and then the only bit left is shifting it from using Ethernet for the path to the Internet to instead using a 2nd WiFi Dongle. Then it can become a portable Pocket Pi that will let me use it on the road.

    So it’s now all I need for home use. Just need to add the portability feature to be done.

    Not only that, but now I’ll never need to buy a new WiFi router for my office /home private use. The Telco provides one for connectivity to them, but for, for example, my Cluster System, I have it plugged into an old Netgear AP / Router. It only has 4 ports, so I have an 8 port switch plugged into it for the cluster. Now I can instead use one of the R.Pi boards as WiFi / uplink if desired. (For fully wired use I’d need a 2nd hardware Ethernet port via USB dongle, but I’m not going to bother until / unless the Netgear dies.

    For now, it’s Folgers Time ;-)

    It’s about noon-thirty, the sun is out, and the patio / coffee is calling my name ;-)

  15. CoRev says:

    E.M. do you have a monitor switch? I have a 4X1 switch which works quite well. I don[‘t remember the cost , but think it was in the $20 range.

  16. E.M.Smith says:

    Just because it took me a while to get this all working, I’m going to just post some of the config files here. THEN I’m going to do a backup of the chip, try it all from scratch, and work out any final polish points… then make the final “how to” posting.

    These may show some of my “odd bits” pre-cleaning, but that can also let you see where things were stated as needed in various guides by got commented out by me and it now works.

    First up, /etc/network/interfaces. The file that used to define your network configuration but where generations of folks have now written various overlays and glue-ons and generally made a mess of network configuration:

    root@PocketPi:~# cat /etc/network/interfaces
    # interfaces(5) file used by ifup(8) and ifdown(8)
    # Please note that this file is written to be used with dhcpcd
    # For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'
    # Include files from /etc/network/interfaces.d:
    # source-directory /etc/network/interfaces.d
    auto lo
    iface lo inet loopback
    #auto eth0
    #iface eth0 inet dhcp
    #auto eth1
    #iface eth1 inet dhcp
     auto eth0 
     iface eth0 inet static
     auto wlan0
     allow-hotplug wlan0
     iface wlan0 inet static
    #	wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
    # allow-hotplug wlan1
    # iface wlan1 inet dhcp
    #	wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
    #auto br0
    #iface br0 inet manual
    #bridge_ports eth0 wlan0

    Note that I’ve got wlan1 commented out as I’ve not got the dongle in yet. Also note at the bottom I’e commented out the bridge interface br0. Some pages said it was needed. Don’t know if it helps to comment it out, but I did at one point when reverting to “just a PiHole” and then had not un-commented it when things started working.

    Note the line where for wlan0 I commented out wpa-conf/etc/wpa_supp….

    That was necessary to get wpa_supplicant to let go of the interface so I could bring it up manyally with a “ifup wlan0”. Until that line was removed, attempts to bring up wlan0 failed.

    Next, some dnsmasq comments. PiHole comes with its own bundled copy. It is Very Picky about the config file and replaces the default with this:

    root@PocketPi:/etc# cat dnsmasq.conf
    #	dhcp-range=,,,1h

    Here you can see where I tried to get dhcp running out the WiFi wlan0 interface, but that causes PiHole to kill its “FTL” service… so commented it back out. The use of the directory leads to their actual config file:

    root@PocketPi:/etc/dnsmasq.d# cat 01-pihole.conf 
    # Pi-hole: A black hole for Internet advertisements
    # (c) 2017 Pi-hole, LLC (https://pi-hole.net)
    # Network-wide ad blocking via your own hardware.
    # Dnsmasq config for Pi-hole's FTLDNS
    # This file is copyright under the latest version of the EUPL.
    # Please see LICENSE file for your rights under this license.
    #                                                                             #
    #                      /etc/pihole/setupVars.conf                             #
    #                                                                             #
    #                    WITHIN /etc/dnsmasq.d/yourname.conf                      #

    This is automagically created by PiHole. Attempts to put another file here for wlan0.conf had the same “FTL fail” result. Configuring “out all interfaces” and changing DHCP settings to the 10.x addresses IN PiHole had it add a second file:

    root@PocketPi:/etc/dnsmasq.d# cat 02-pihole-dhcp.conf 

    So that’s how you get DHCP to happen out your wlan interface… You do it IN PiHole web admin panel that you get to by pointing your browser at your main ethernet address.

    Then there’s the default hostapd config file:

    root@PocketPi:/etc/default# cat hostapd 
    # Defaults for hostapd initscript
    # See /usr/share/doc/hostapd/README.Debian for information about alternative
    # methods of managing hostapd.
    # Uncomment and set DAEMON_CONF to the absolute path of a hostapd configuration
    # file and hostapd will be started during system boot. An example configuration
    # file can be found at /usr/share/doc/hostapd/examples/hostapd.conf.gz
    # Additional daemon options to be appended to hostapd command:-
    # 	-d   show more debug messages (-dd for even more)
    # 	-K   include key data in debug messages
    # 	-t   include timestamps in some debug messages
    # Note that -B (daemon mode) and -P (pidfile) options are automatically
    # configured by the init.d script and must not be added to DAEMON_OPTS.

    Here you set the DAEMON_CONF variable to where you put the hostapd settings.

    Note at the bottom I set DAEMON_OPTS to get maxium diagnostics after way tooo long of not getting hostapd to start. Than ran it by hand pointed at the /etc/hostapd/hostapd.conf file:

    root@PocketPi:/etc/hostapd# cat hostapd.conf 

    You will find examples with “quotes” around ssid values and wpa_passphrase values. At first success I’d done that, but then your ssid is exactly “PiHoleNet” including the quotes on the display… and you must enter the quotes as part of your password… so I took the quotes off and rebooted… ;-)

    Note that “WPA-PSK” uses a DASH not an UNDERSCORE while “hw_mode” uses an underscore not a dash. One model page had WPA_ and that isn’t right. I’d typo’ed “hw-mode” and that was the last failure caught via the manual start of hostapd with debugging set high.

    I tried a LOT of wpa_supplicant configs trying to get wlan0 up before discovering the change in /etc/network/interfaces. Here’s my present config file, but I don’t know how much it matters now:

    root@PocketPi:/etc/wpa_supplicant# cat wpa_supplicant.conf 

    Note that the name “PiHole” does not show up in my WiFi list on my tablet, so I suspect this is presently not doing much. I’m keeping it as I think I’ll need it for the 2nd WiFi interface when connecting to a WiFi upstream…

    Finally, the dhcdcd (dhcpCLIENTdaemon) wants to fight over who does what with interfaces too, so here is that config file:

    root@PocketPi:/etc# cat dhcpcd.conf 
    # A sample configuration for dhcpcd.
    # See dhcpcd.conf(5) for details.
    # Allow users of this group to interact with dhcpcd via the control socket.
    #controlgroup wheel
    # Inform the DHCP server of our hostname for DDNS.
    # Use the hardware address of the interface for the Client ID.
    # or
    # Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
    # Some non-RFC compliant DHCP servers do not reply with this set.
    # In this case, comment out duid and enable clientid above.
    # Persist interface configuration when dhcpcd exits.
    # Rapid commit support.
    # Safe to enable by default because it requires the equivalent option set
    # on the server to actually work.
    option rapid_commit
    # A list of options to request from the DHCP server.
    option domain_name_servers, domain_name, domain_search, host_name
    option classless_static_routes
    # Most distributions have NTP support.
    option ntp_servers
    # Respect the network MTU. This is applied to DHCP routes.
    option interface_mtu
    # A ServerID is required by RFC2131.
    require dhcp_server_identifier
    # Generate Stable Private IPv6 Addresses instead of hardware based ones
    slaac private
    interface wlan0
    	static ip_address=
    	nohook wpa_suplicant
    #interface eth0
    #        static ip_address=
    #        static routers=
    #        static domain_name_servers=

    Note here I’ve commented out where I was playing with the eht0 interface as dhcp server when I first started on a hardware network. You can see how I pointed DNS at itself.

    The key bit here seems to be that nohook wpa_supplicant, but it isn’t enough until you also remove the wpa line in /etc/network/interfaces too.

    OK, I think that’s all the big bits. Now I feel more comforable making the backup (so if I get dd going the wrong way and blank the chip I’m not totally hosed ;-)

    I’ll be back in an hour or two after backups made, a final pass of “is that everything, really?” is done, and then I’ll try a “from scratch do over QA proof”… (Sometime after that a nice clean article that makes it look like it all just works first time for me and never any wandering in the woods ;-)

  17. E.M.Smith says:


    I have a monitor switch somewhere in the junk pile, but it is for something prior to DVI that is now obsoleting toward {something else} and where what I’ve got is HDMI cables…

    I do have space on my desktop for 2 x monitors, and that’s plenty. Most of the time the TV is just a 19 inch HD TV, but it can do monitor duty when I want.

    For my Headless Stack, I generally just ssh in (as I’m a command line kind of guy) but can also use various “remote GUIs” if I want (vnc variations).

    As long as one system can do remote GUI shells, you don’t really need to swap monitors….

    The only place that gets messy is when I want a Daily Driver up and running but I’m also doing a new system install / configure that wants lots of reboots and doesn’t have tightvnc or similar running yet. Then I’ll just use both monitors.

    My actual biggest limit at the moment is only enough space on the desk for one KB & Mouse (USB) so while I have 2 x kb and 2 x mice, I can’t run them at the same time without juggling who gets put on the floor ;-)

    Often I’ll just use the Tablet or Mac instead ;-)

    So I’ve not felt the need for a KVM (Keyboard, Video, Mouse) swtich enough to bother getting one for all the new interfaces (HDMI, USB)… mine are all PS-2 round things and VGA spigots ;-)

  18. CoRev says:

    E.M. thanks again for the ground breaking.

    As to the keyboard/mouse switch I have considered that also. Now I just move the separately powered USB hub from SBC to SBC. Once I have a stable version of the cluster running that will be enough, so will probably just stay with that method. I do have a 27″ monitor on the desk, so the hdmi switch became almost mandatory while trying to build a cluster of 4-5 SBCs.

    Next I need to decide what i want to do with the cluster. Clearly PiHole is one of my preferred options. At least TODAY!?!

    Also, I will soon need to get new shorter cables to clean up this ?configuration? or mouse house of tangles. The desktop space is mostly taken up with excess cables.

  19. E.M.Smith says:

    I’ve got KB/Mouse on a USB hub as well, so just move one cable.

    On my “todo” as of now is to re-do the PiHole build on one of my Pi M2 boards in my stack. This will take it out of the distcc cluster (since I don’t want some big compile of things to clog up DNS / ad blocking for the whole house) and have 2 Pis “on” all the time. I’m keeping the old Pi 1 B+ model running with my prior DNS on it as a backup, and with Squid still on it as a proxy server. Once I get Squid running on the Pi-M2 I’ll be faced with the question of decommissioning the Pi M1… or trying to redo all this on it using Alpine Linux… With the browser window open to monitor it, the Pi M3 has a pretty big load on it. I doubt it would be responsive enough on the Pi M1 B+. Then again, running headless (no load from LXDE windows) and without the web browser, it might be just fine… But first I need to get the Pi M2 running stable and well so a decommission for a few days of rebuild of the M1 B+ won’t disrupt anything…

    Given the much better math performance of the v8 (64 bit) cores over the v7 (32 bit) cores on complex math with double precision, I’m planning to make a 2nd cluster stack. It will get the v8 core boards I’ve got. The v7 cores will be used for infrastructure ( file server, DNS server, Squid Proxy server…) and the XU4 will remain a desktop platform. In the end, I’ll have 2 x desktops — the XU4 and the RockPro64, each as “headend” of a cluster. One for math heavy things like Climate Model playing and distcc for 64 bit OS builds, the other for infrastructure and general purpose tasks (like distcc for 32 bit OS builds and such).

    At present I have 4 boards in “mostly constant” use. File Server, DNS/Squid server, Desktop (sometimes 2), and now the Pocket Pihole that’s dedicated to being mobile. The rest of the stack gets fired up for distcc (building big code / compiles) and trying out various distributed computing things, like OpenMP / Mpich.

    Oh, and I’ve got time service running on the Squd / DNS server so I can repoint my various other machines “time” queries to it and avoid that internet traffic. It keeps it’s clock right by looking to others on the internet, and anything in the house can just ask it. The avoids another batch of “information leakage” as nobody needs to see those various machines doing time queries.

    My project to make a PXE server (so boards can just boot images over the network) will absorb one board (or part of a board) at some point; but for now it’s on hold (as I had to deal with just what OSs to boot and getting things running the way I wanted. At some point that will return, but for now, just doing the boot from uSD is fine and I keep a backup copy on disk.

    Hopefully that list gives you some project ideas ;-)

    As per the cable issue… I bought a multi-USB port power supply and some short cables for the cluster. Match them with an Ethernet hub with short (1 ft) cables and you can have a fairly neat stack. My Ethernet is recycled so not short – instead it’s about 4 foot long bits each coiled and wire tied, for a couple of them. The others about 2 foot…

    On the desktop it’s more chaotic as things ‘come and go’… plus the “round end” barrel connector power supplies are “special” so I just need to keep them wire tied… On my “tobuy” list is some 6 inch or 1 foot USB cables but I need to inspect the USB hub first to make sure it’s cable can be replaced (i.e. normal socket…) As far as the 2 x phone chargers and the tablet charger, not much I can do about them…

    But yes, “cable management” of some kind matters.

  20. E.M.Smith says:

    Just did a straight PiHole install on one of my Pi M2 boards running Jessie Devuan 1.0 release. Installed fast with only one issue…

    The board had not been booted up in “a while” and the certs for the site were dated to START Nov 22 (of some year) while the Pi thought it was Nov. 18 (of that year or earlier)… After resetting the date/ clock to today, it the stopped complaining about invalid certs and just ran.

    I’ve now got a PiHole DNS for the whole house (took about 10 minutes all up to do… MUCH simpler than reading the script and much much easier than putting a WiFi router on it too ;-)

    The Pocket PiHole can now move on to the All WiFi solution. Basically adding a WiFi dongle so that’s the network uplink instead of wired Ethernet.

    “someday” I’ll need to get back to the Pi M2 and update it to Devuan 2.0, but not today.

    I’ll add a Squid Proxy to it at some point this evening and then I’ll be free to discontinue my Pi M1-B+ from duty as DNS/proxy server… and decide what’s next for it ;-) For now I’m planning to leave it up for a few weeks since A) it costs nothing. B) Don’t have any other use in mine. C) I don’t really want to go to everything in the house finding out what all and what all “chips” in offline condition depend on it / have it configured in ;-) Even after I shut it off, I’ll leave it “as is” for a long time until certain it isn’t needed by something or other…

  21. E.M.Smith says:

    I probably ought to note here that I brought up PiHole on a Pi M2 in my home network and then turned on DHCP for it, while turning it off on my AT&T router. Now it looks like anything DHCP connecting to that network automagically gets the PiHole protection ;-)

    I put some stuff in a comment here:

    but a few months from now finding that from this article needs this pointer…

  22. E.M.Smith says:


    Sometimes you learn things…

    So I was fighting the computer to get 2 x WiFi interfaces up. I had my usual WiFi dongle that’s worked before. A TP-Link 725N. Eventually I figured out the necessary driver (module) wasn’t loaded. A general idea how to install a module can be found here:
    though where they tell you to get a module is wrong…

    So i think: “I’ve had this dongle work on another Devuan…” and got the bright idea to just copy the module from it. 8188eu.ko is the kernel module. I stick in the adapter with the uSD card for that one and copy the module over… Won’t install…

    Doing a “file -s 8188eu.ko” informs me it is a 32 bit module… and this board is running a 64 bit kernel. Now the arm chip will run both 64 bit and 32 bit programs, BUT not as parts of the kernel. There the assumption is that you run ONE consistent arch.

    So this older Devuan1.0 doesn’t have the needed driver, the newer build I’m running on another system has the driver, but is the wrong word length. So now I get to play a game of “Go Fish!”.

    Does the newer 64 bit Devuan 2.0 have the driver? Has anyone built a 64 bit version? (This is the kind of thing you run into on relatively new OS builds and newer hardware. While this dongle is old, Devuan arm64 is very new… In fact, all arm64 is still a bit developmental.)

    The “easy” fix is just install a 32 bit v7 build of Devuan. It isn’t like this is going to be a heavy computes box. I do need to do the QA Rebuild From Scratch at some point. But really….

    There’s also the chance I can find the needed kernel module with an apt-get… I went looking for drivers for my other bigger antenna dongle, the WN722N:


    I did the following to get it working on my system, also Wheezy.

    Added the non-free packages to /etc/apt/sources.list

    apt-get update
    apt-get install firmware-atheros

    And it showed up in iw list :)
    HTHs someone!

    Kicking around, I’ve already got the Atheros drivers on this system… but when you try to install the module (insmod) it gives unknown symbol error…

    OK module newer than kernel or just doesn’t work? Donno…

    SO, OK, in any case I need to sort out OS & Driver Compatibility Hell before I can get my WiFi dongles to work, then work my way back up from whatever OS level I end up running…

    Living on the leading edge of OS & hardware (New Toys!) can be a bit grim sometimes ;-)

    So OK, I’ve moved the 725N over onto the Odroid (where an insmod / depmod -a later it is running fine) and I can at least stop swapping the ethernet cable to / from it ;-) (It is 32 bit and has the 32 bit driver already on the install)

    Adventures In Kernel Driver / Module Land…

  23. jim2 says:

    On the bright side, the arrows in your back are merely virtual.

  24. E.M.Smith says:


    If I didn’t at some level like this sort of thing I would not have been an I.T. Guy for 35+ years ;-)

    I just hope it is of use, or at least good schadenfreude material, to others ;-)

  25. jim2 says:

    I’m frequently getting into areas unknown to me at work. Not at the OS level, but in the programming and new application area. I love it. So, laughing with you, not at you.

  26. E.M.Smith says:

    Including Roku traffic, and after a couple of days:

    16.8% of DNS requests actually go to the upstream DNS provider.

    62.6% are blocked.

    20.6% are serviced from cache.

    IMHO, that’s a hell of a success.

    My “upstream” DNS interrogations are down by 83.2% and my traffic to “things I don’t want” down a whole lot (probably 100% of what I don’t want but about 62% of “things” in total)

    I’m really really happy with PiHole. It, alone, IMHO, is worth all the money and time I’ve put into SBC playing and stuff.

  27. E.M.Smith says:


    2018-12-21 19:46:22 A scribe.logs.roku.com Blocked (gravity) – (0.4ms)
    2018-12-21 19:46:13 A pi-hole.net OK (forwarded)

    A DNS lookup for “pi-hole.net”? Um, is PiHole ratting me out?! Or just saying a new one exists….

    I’m not Tooo worried as I can blacklist it, but really…

  28. jim2 says:

    Does pi-hole update its DNS list via the home site?

  29. E.M.Smith says:

    There are a set of something like a half dozen to 8 lists to which you may choose to subscribe, or not. (Looks like 7 in my settings – see below) These are lists other folks have chosen to maintain at other locations. It also looks like you could, should you wish, maintain your own list.

    There are “click boxes” on each item in the DNS log. Just sit there looking at the logs every day or two, saying “yes this, no that” and you eventually build a list that’s just yours. I chose to just take all the block lists figuring if some “issue” with too much blocking showed up I’d whitelist (click box) it in the log file later. So far I’ve not changed any choices PiHole has made with all the blocklists included. At present it is blocking over 130,000 sites in the block lists, but only about a dozen have made my frequent block graph (i.e. I don’t try to visit most of the sites…)

    Under “Settings Blocklists” there is a place to enter a URL of those you would like to add, or you can enable / disable those already in place. Here’s the URLs that come with it:

  30. jim2 says:

    I also read something about auto-updates on their FAQ. If you have an x-box you have to whitelist a bunch of sites. And, I’m not sure how it would work with an IP phone. I may give this a shot at some point. My RPi3 is just collecting dust and this would be a use worth the effort.

  31. E.M.Smith says:

    Just as an FYI, here’s my block statistics to date:

     Top Blocked Domains
    Domain 	Hits 	Frequency
    scribe.logs.roku.com 	6614 	
    giga.logs.roku.com 	4690 	
    pixel.wp.com 	1223 	
    cooper.logs.roku.com 	766 	
    ssl.google-analytics.com 	496 	
    googleads.g.doubleclick.net 	382 	
    www.googleadservices.com 	324 	
    www.google-analytics.com 	121 	
    e.crashlytics.com 	108 	
    stats.wp.com 	95 	

    Most “chatty” is the Roku logging what I’m watching or had presented but did not choose to watch.

    2nd most is “pixel.wp.com” that I think is a WordPress “hot pixel” in pages to phone home “something”; maybe… I’d noticed often “waiting for pixel.wp.com” when wordpress web pages were very slow loading for various network reasons. This seems to be an irrelevant-to-opertion tracker of some kind.

    Then third on the list is Google Analytics and Google Doubleclick and Google Add Services and…

    I’d blocked all things Google in my personal DNS list on my DIY DNS server prior, but was not blocking the Roku (had not thought about it, really) nor the WP Pixel (that I had thought about but didn’t care that much…)

    After a burst up to over 65% blocked, I’m now settling back to just 55% of DNS queries being blocked. It seems to burst upward when we’ve got a couple of TVs going, and the Roku seems to have a “once in a while big burst” about 1/day. Likely it picks a moment to upload a big log file when you are scrolling for new shows to watch; while doing minor logging during shows – just to assure log management doesn’t interact with viewing experience. It seems to drift dowward toward 1/2 when it is just me on the computer doing WP stuff…

    Frankly, I find it “worth it” just for the way it presents the log of all DNS activity. Just being able to SEE the DNS lookups is enlightening. I always knew it was possible, but I’d never bothered to deal with DNS logging. Having seen what-all is happening, I’m now MUCH more interested in encrypted DNS. I really don’t need the telco or TLAs looking at what on-line sites I visit, TV I watch, email servers I use, etc. etc. Essentially the DNS Logs are a “contact trace” of everywhere you go and contact on-line. HTTPS just encrypts the “what is sent”, not the who sent it from where. For that you need encrypted DNS and a VPN to somewhere private. (2 more things on my todo list…) But step 1 of “just don’t go there” is nicely served by PiHole.

  32. E.M.Smith says:

    For ANY site, be it an IP phone, a game, or otherwise; To whitelist things, you just look at the log file. Say, for example, phone.att.com was showing up blocked (red text and word BLOCKED), you would just click the little button next to it that says “Whitelist” (green text) and it is no longer blocked.

    For bulk actions on known sites, there are both Whitelist and Blacklist pages from the top (side bar menu) level of PiHole web page manager. Just click it and they present a line for domain name entry along with whatever you have already got in your file. So your 1/2 dozen domains for games would just be “type them in” and be done.

    It’s all very conveniently laid out and nicely done.

    Oh, and if your IP phone comes straight out of your Telco Router (as mine would if I had it turned on by AT&T) that’s all internal to the router / telco and doesn’t involve your LAN / WiFi network spigots or DNS services.

    Your Pi M3 would be able to do this and not notice. If you set it up to do this, it would be reasonable to also have it where you can plug your monitor / kb into it and use it as a GP Desktop. Also load a Squid Proxy on it to be a web proxy. That adds a bit more protection to your web lookups / activity. It also caches web pages so your uplink traffic drops on things you visit more than once. Especially useful if you pay “by the byte” or just have a slow link. Squid is also very easy to install and configure.

    Only downside to Squid Proxy is that for some things you need to tell your browser not to proxy them. Like the Web Management Engine of PiHole ;-) So when I want that panel up I either have to tell the browser to not use a proxy server; or tell the proxy server not to proxy it. Being lazy I just toggle the proxy settings in the browser ;-) IIRC the default is port 3128, so you just put the IP of your proxy server and that port in the settings of what proxy server to use. In FireFox Settings: General at the very bottom : network proxy : then HTTP set to IP / 3128 and click “use for all services” or some such.

    My Pi B+ (model 1…) is running Squid Proxy, DNS (now deprecated but still up), time server and a few other minor things; and it is 99% idle most of the time. So this is something that is just not going to be even noticed by a Pi M3 – so no worries about it slowing down your web pages ;-)

    I would strongly encourage anyone and everyone to set up at least one Pi class machine as their PiHole DNS and Squid Proxy service. (Though as a caveat I’ve not actually combined the two on one board yet. I don’t see any reason for them to be incompatible though.) It is a good base level of protections.

    Later, on top of that, you could add on some IDS / IPS stuff if really worried, and maybe add a VPN to mask your traffic and/or a Tor gateway if really worried about “Officials”…

    OH! And one more sidebar: As implied by my Pi B+ still running DNS; nothing prevents you from having 2 different DNS services available. Point things you want filtered at the PiHole, point things that you don’t want filtered at some other DNS.

    IF the object doesn’t do DHCP but lets you set the DNS manually, just point it at directly and have no internal DNS involved. Some devices let you do DHCP but still do static DNS. Only PITA has been that when my laptop is pointed to my home DNS and then I go to Starbucks, I need to tell it not to point at that now unavailable DNS inside my private network. One of the features of this PiHole setup is that it DOES DHCP its DNS address, so the laptop and phone can now just be left on “do DHCP”. But to bypass the PiHole I’d need to use a manual setting at home.

    And yes, I’ve got a few dozen gadgets and uSD systems to one-at-a-time swap from the Pi B+ over to the PiHole as I used a lot of static IP / DNS settings. Part of why I’m not shutting off the Pi B+ any time soon.

    By my count, I’ve got at least 3 different DNS choices inside my home network. The first is the Telco Router. Even though I’m not taking it as the DHCP served choice, it is still there and working, so I can just point DNS requests at it if desired (and some of my Linux systems do just that). Then I’ve got the couple of year old DIY Pi B+ blocking DNS server. It just sits there doing Proxy and serving what is asked of it. Then there is the new PiHole. So I’ve got three levels of DNS filtering available on my network and they do not interfere with each other. Further, any device can be configured to not look at my interior DNS services, but just directly look outward to or Google (GAK!) or whoever DNS servers.

    There’s also a 4th in that my lab router serves DNS to the things there; but it is configured to look at the Pi B+ and PiHole for upstream service, so really it’s just them. But I could, if I wanted, load different upstream DNS server choices into that Netgear router and it would be using different upstream providers. So, for example, I could point it at and and then put a gaming system in the lab network and that gaming system would never see the PiHole DNS. It would take an extra router hop to get out, but that is only about 20 ms latency IIRC.

    Oh, and some of my desktop uSD images have dnsmasq installed and are their own DNS servers with their own upstreams… Don’t really need that anymore. Did it on the compute cluster / stack so it was not tied to my general infrastructure and I could just move it around. Probably worth changing that as it isn’t going walkies anymore ;-)

    DNS is really highly flexible…

  33. Pouncer says:

    How low can you go?

    You recommend and ” would strongly encourage anyone and everyone to set up at least one Pi class machine as their PiHole DNS and Squid Proxy service. (Though as a caveat I’ve not actually combined the two on one board yet. I don’t see any reason for them to be incompatible though.) It is a good base level of protections.”

    I’m seeing a Pi Zero kit at Amazon with USB hub, heat sink, case, NOOBS on SD, power brick, OTG cable … Under $50 all in.

    My primary “Use Case” would be a WiFi print server but second would be a way to isolate the rest of the internal LAN and “Smart TVs” from snooping, and third would be to bring in new IoT gadgets like the thermostat, garage door opener, and water heater WITHOUT going out to the “cloud” and getting “Mother May I?” permission from Alexa or Siri or Google to ensure, for example, the garage is closed 10 p.m.

    Last time I considered the purchase I went, instead, for a Windows 10 touch tablet, on the theory that I had to have a screen and i/o ANYHOW and the tablet offered that; and that I knew (albeit, hated) Windows while didn’t know anywhere near enough about *nix; and $50 for the tablet WITH MS-Windows cost less that the Windows 10 license all by itself, so me buying the tablet was somehow costing Microsoft money; — and I got a Skype terminal out of it, which was the primary Use Case at that time. Which was all well and good until I found that the vendor supplied version of Windows 10 just barely fit into the onboard memory and storage but COULD NOT BE SUPPORTED, PATCHED, UPGRADED etc with more recent MS stuff because MS insisted it all go inside the tablet and the tablet assumed everything but the bare bones OS would be on the SD card. Also, the whole “PC” only had one port, (USB) used for both charging and EVERYTHING ELSE, so I couldn’t, like, hook up the printer AND have the PC keep working for more than a couple hours. So my decision wasn’t exactly a waste of $50 but it was less a “good deal” than I’d hoped.

    Pi 3 kits (anything more than the zero) seem to run half again to twice the expense, which may be worth it, I would be pleased to stipulate so. But as a time sink and hobby investment, I try to keep such ventures to, or below, that $50 price point.

    So anyhow, I’m wondering now, based on your experiences, what you think the bare minimum investment might be? Assuming the kit can be assembled and configured from a regular desktop and then run stand alone, headless, at a remote part of the house. Can the Zero even run as a “peer” or “host” or do I understand correctly it may be intended only as a “client” device?

  34. E.M.Smith says:

    Issues with the Pi Zero (or why I’ve not bought one…)


    Only 512 MB memory. For running a desktop with browser that is about 1/2 what you need.

    Single core slow CPU. The Pi B+ was just NOT enough CPU for things like browsers and such. Usable for minor headless servers, but a PITA once you hooked up a monitor AND wanted it to do something.

    And the killer:

    NO Ethernet or WiFi. How do you talk to the thing? Oh, that’s right, buy MORE stuff…

    What WOULD I get?

    First off, Amazon is NOT your friend for SBCs. Costs are significantly higher than elsewhere. Yes, you MAY get “free shipping” if you are already on the Prime plan… but I like Ameridroid MUCH better.

    Second, the nice already made for you “kits” are nice, but in the end cost more than a DIY kit.

    Third, you can get much more bang / buck in non-Raspberry Pi boards. In particular the Orange Pi set (unless tariffs have jacked them up a lot…)

    Then if you get a board with a few USB connectors you don’t need a USB hub – so less costs there too.

    Get something with a barrel connector for power, you dodge the power limiting micro-USB and then you can actually power things out the USB ports of your board. Don’t need a powered USB hub just to use a hard disk…

    So that is why I’m particularly fond of the low end boards with just that kind of power connector and more than one USB port.

    So looking at their choices:


    The Pi Zero is $10 and to jump up to the Pi Zero W with WiFi takes you to $15. I doubt you can get Ethernet onto a Pi Zero for less than $5 of added stuff, so that’s realistically your lower bound. Then for just a couple of bucks more at $18 you get the Pine 64. It has 64 bit quad core processing so WAYYYY more computes, you can get it with more memory for a few $$$ more (IIRC mine was $22 with a GB ) and has built in Gbit Ethernet (where the Pi M3 is limited to 300 Mb on it’s “gig” Ethernet). Oh, and 2 x big USB ports (though only 2.0 speed)

    It does get warm in use, so you need a heat sink for a couple more $$ and it needs a $5 PSU and a $10 uSD card, a case is $9. Add that up = $45 and it is much more system than the Pi Zero.

    The other one I looked at, and bought, and like more, is the Rock64 for $30. That comes with 2 x USB 2.0 ports, 1 x USB 3.0 port, GigE Ethernet, and uses a “round plug” PSU that lets you use them without a powered hub for things like a disk drive. You still need a PSU, uSD and case, so add $8, $9, and $8 (based on prices listed in the sidebar of ‘usually added’). This is WITH the 1 GB memory that you pay $5 more to get in the Pine A64. so $$= $55. About $5 over your goal, but even more board and it ran cool enough that you don’t really need a heat sink (though I bought one for $2 anyway).

    At the real bottom end, I’d go for the Orange Pi One. In fact, I did, and bought 2 of them. They cost me about $10 at that time. Not sure what they run now:


    Round plug power connector (that originally offended me but I’ve come to like more as they have higher power possible) IIRC I bought a uUSB to round plug switching adapter for like $3? for mine and just reused regular USB power. So a regular USB to uUSB cable, then the adapter and the other end plugged into whatever USB power you have. I’ve used a $3 USB mini-cube from the “bin” at the car parts store, and I’ve used the USB outlets on my 2 to 6 regular house socket adapter that has 4 x USB outlets too. Or you can buy a PSU just for it. The heat sink is needed for heavy computes or it thermally limits, but if doing light weight stuff isn’t needed. It will do more than a Pi Zero even without a heat sink on it. I’ve not bought a case. One is “zip tied” on top of my 4 board Pi Cluster as a contributing member ;-) and the other sits on top of the big disk drive as my file server ( i keep thinking of getting a zip tie for it, but no need to be extravagant, really… ;-)

    So there’s your low end. $10 + cheap $8 uSD + $4 for ersatz PSU bits. $22 plus shipping.

    BTW, Amazon sells it for $22, so don’t know if that’s Amazon price bump, tariff impact, both… or just folks figured out it was a hot board for too cheap ;-)


    $14.26 shipping included to the USA (but you get to deal with China… so I would not use my Big Credit Card but instead my small cash load only debit card from Walmart…)

  35. E.M.Smith says:

    Oh, and probably ought to mention the 2 things folks never think about that matter far more than a $5 to$15 price difference in the SBC:

    1) Software availability & maturity.
    2) HDMI “robustness”.

    That #2 is kind of code for “Does it REQUIRE a real HDMI display?”. The Orange Pi One initially put me off greatly due to me thinking it was broken or the display was hideously hard to get configured right. Then I finally worked out that it just refused to work with my DVI monitor on an HDMI adapter. Similar problem with some other boards at the low end ( the Pine A64 IIRC). But the Raspberry Pi M3 just works with everything. So IF you are getting one of these for a kid or even yourself as a Nooby and you do NOT have a real HDMI monitor, it will be a frustrating experience. If you DO have a real HDMI monitor (or HD TV), it will be fine. For things intended to run “headless” like a PiHole server, you only use the display long enough to get it running the first time. After that you ssh in or use a remote terminal interface; so the display doesn’t matter.

    For #1, it is just that popular boards get a Million programmers stamping out bugs in the software and porting their favorite things to it. Unpopular boards have a thin following, so not much software or much slower to show up. Even then, with fewer eyeballs looking at all the odd cases they don’t get bugs identified as fast. Mostly this just shows up as them having, say, Ubuntu MATE ported but no Lubuntu or Suse or RedHat. Or sometimes the OS is there, but the slick auto sizing at boot for the monitor wasn’t ported to that HDMI chipset so you get to set resolution by hand. Things are all just sort of “rougher” around the edges. This is substantially the same as high end boards when they are “new”, but popular board get polished software sooner and that “young port” effect rapidly smooths out.

    So again, for someone who has very low experience levels and doesn’t do well with “issues”, getting The Most Popular board is worth more than a few more cycles / $ (faster Ghz) or more than a $5 higher price. But for folks who have some time in the saddle and are not going to be too frustrated by figuring out they need to plug it into a real HDMI or config settings longhand, and just want a gizmo that will do a job, then the $10 Orange Pi One from China is just fine.

    That is why, despite my early frustration with the monitor, I bought a 2nd one. For me, knowing the limits, it is a “go to” board for headless / low end uses where I want minimal cost. The fact I can get a Devuan download for the R. Pi but not for it just means I install a different OS and “move on”… Armbian can get the Devuan uplift done and it’s a good OS too.

    In Summary:

    Issue free fun thing with all the software choices you could want: Pay the extra $5 to $15 and get the more popular boards.

    Low cost works fine just needs some of your time to figure out the picky bits and tune it up, maybe not with the exact operating system or cool code you wanted: Buy the $10 wonder and a $5 cup of Starbucks while you do your OS R&D for it ;-) like how to install Armbian.

  36. E.M.Smith says:

    Realized I’d not addressed this:

    ” Can the Zero even run as a “peer” or “host” or do I understand correctly it may be intended only as a “client” device?”

    The various SBCs discussed are able to do all the same roles – it just depends on how much added hardware you attach (usually to GPIO pins) for things lacking Ethernet or a monitor spigot.

    At the high end, all the places to plug things in are there (Gig Ethernet, USB 3.0, WiFi built in, etc) and you pay about $5 extra / thingy to have it already there. Ditto the move from 512 MB memory to 1 GB. So out of the box they work well as a “desktop” (meaning with monitor, maybe some speakers, keyboard, mouse, USB storage all plugged into 3 USB ports).

    At the low end, why ought I pay for 3 x USB ports for a device that will be run without a keyboard, mouse, or USB storage attached. In the limit case even Ethernet is removed (Pi zero) since my little robot doesn’t connect to Ethernet in use anyway. You get some kind of “rig” to bring up and configure it, but then can just clone the uSD card for each subsequent robot in your swarm. Saving $15 / bot for 20 of them is $300 so Well Worth It!!! rip out those USB spigots and Ethernet…

    You can still turn that robot driving board into one that can be a network server (PiHole / DNS / etc.) by attaching a $5 outboard Ethernet device, and you can get more USB on it with another $5 gadget and on it goes. Just like you can use your $35 Pi M3 as a robot driver or headless network appliance – you are just wasting the USB, Ethernet, and extra memory / cores a lot of the time.

    The only exception to this is that the very very low end boards (Pi Zero) while the CAN be used as a desktop or server are just way slower ( single core 700 MHz) than the other boards and there is nothing you can do to make the experience faster / snappier. You will have lags as things get worked on longer. 4 cores at 1.4 GHz is just 8 times faster and that’s that. Similarly, you can make a desktop run in 512 MB but if you open a lot of web pages in FireFox you WILL be dealing with swap. Plug in a fast disk that isn’t so bad. Do it to a slow cheap class 2 uSD card and it is grief.

    Note that Armbian for the Orange Pi One was built expecting more limited memory and actually was reasonably frugal and worked well in 512 MB. This is something you can adjust at OS build time (size of buffers, number, etc. etc.) so even that has some “wiggle room”. Linux can run nicely in 128 MB ( I’ve done it, but some years back) so it isn’t like 512 MB is all that small. Just FireFox is a pig and people are building the OS on a 8 GB 16 Core Intel Wunderbox and don’t think about the build parameters for frugal machines quite as much as they ought…

    So the “use case” pushes the hardware choice toward certain things you want on the board, and that raises the price a bit for each thing. For me, I like being able to just bring up a full GUI desktop when I’m working to configure a board, and I like being able to just plug it into the Ethernet when downloading software; so I generally require any board I buy to have some kind of Ethernet or WiFi and a USB spigot. I’ll pay the extra $5 for it if needed. As the Orange Pi One has those already built in, I could never bring myself to pay just as much for the Pi Zero and then have to buy all the stuff to “make it go” too.

  37. E.M.Smith says:

    Interesting oddity:

    I’ve run into my first ‘issue’ with using the PiHole / Roku together. Al Jazeera has an “accept our privacy policy” check box when you launch it. That just showed up a week or three ago. When I do that, it runs. When I do that on a system with PiHole in place, some log files are blocked and Al Jazeera does NOT run.

    I’m not sure exactly what information Al Jazeera is collecting from Roku log files that others are not collecting, but suspect it is part of their “Did you accept?” test; that is, are they seeing the information they wanted from the Roku device.

    In any case, what this says is that in order to watch Al Jazeera I must either turn off the PiHole, add an exception (whitelist) the particular log it is looking for, or move it to a non-PiHoled subnet.

    I think it will be easier to just not watch Al Jazeera. They are mostly useful for getting the Arab / other side news from Middle East wars, and as Trump is getting us out of those messes, I’m not seeing the need… Seeing “the other side of the enemy lines” when it is Kurds vs Turkey vs Saudi vs Russia isn’t very interesting to someone who mostly cares about US involvement.

    But just FYI, that’s the only issue so far. Though it could indicate a class of issue that might change over time. I’d been a bit bothered by the “accept privacy terms” click box (and no other channel has that, or at least none I’d been watching) and thought of just dumping it anyway. Now I have a better reason ;-)

  38. llanfar says:

    Interesting article on TCP DNS issues: https://link.medium.com/xdY9zzHhbT

Comments are closed.