This was a relatively simple project but it certainly gets the most traffic and use, I setup a Pi 3 as a whole house ad blocker using pi-hole. All DNS traffic for my entire house either gets pointed to this DNS server and if a host is being stubborn my router will capture the traffic and NAT it to the DNS server anyways. No exceptions! This server also runs a bash uptime script that checks if all my hosts and services are online and functional, if any service goes down I will get an email. It also builds a convenient HTML page, in bash, so I can view my services in an intranet web page.

To be juvenile, since this server essentially flushes all the unwanted internet traffic, I called it Crapper and built it into a suitable housing. A toilet! The toilet bowl is clear and has pulsing blue LEDs installed that are controlled by a PWM output from the pi and a MOSFET, because why not?

crapper-case

Server Availability Checking Code

#!/bin/bash

email_body=""

#log file is the html file displaying the server status
log_file=/var/www/apache/uptime.html

#define the array in threes; the printable name of the server, the actual server address, searchable keyword in the HTML
#the 'search' variable is a unique keyword you expect to appear in the HTML to confirm the page loaded and it wasn't a 404 re-direct that loaded
#if the 'search' variable is empty it won't scan the HTML for a given snippet of text, you only need to search HTML for pages that go through the reverse proxy
#if the 'email' variable is empty it won't send an email when it goes down. If there is a 1, it will.
#define these in the order you want them to appear on the web page

name[0]="Example Host1"
address[0]="http://192.168.1.2"
search[0]=""
email[0]="1"

name[1]="Example Host2"
address[1]="http://192.168.1.100:89"
search[1]="Apache2"
email[1]="1"

name[2]="Example Host3"
address[2]="http://192.168.50.2"
search[2]="Apache2"
email[2]="1"

name[3]="FTP Server"
address[3]="http://192.168.1.100:21"
search[3]="ProFTPD"
email[3]="1"

#Purge existing file
cat /dev/null > $log_file

#write html auto refresh code
echo "<head>" >> $log_file
echo "<meta http-equiv="refresh" content="60">" >> $log_file
echo "</head>" >> $log_file

#write the date and time in the first line using the 'date' command
current_date=`date +%D`
current_time=`date +%T`
echo "<h3>$current_time&nbsp;&nbsp;&nbsp;&nbsp;$current_date</h3>" >> $log_file
echo "<table>" >> $log_file

#Initialize the variable for the first loop, start as failing values then curl/check
result=1

# NOW START CHECKING ALL THE SERVERS
for ((i=0; i<=${#name[@]}; i++))
do
    #if the variable is empty, print a line break in HTML
    if [ -z "${name[i]}" ];then
        #add an extra break for formatting
        echo "<tr><td><br></td><td><br></td></tr>" >> $log_file
    #if the variable has content, curl the host and save the output to HTML/log file
    else
        echo "Checking ${name[i]}"
        #if the variable 'search' is empty just blindly curl and look for any response
        if [ -z "${search[i]}" ];then
            curl -sfkL --retry-max-time 5 --retry 5 --ipv4 ${address[i]} > /dev/null
            # $? = Exit status of last task
            result=$?
            echo -e "curl return code: $result \n"
        #otherwise, curl and look for a unique search term inside the HTML code to confirm it didn't curl a 404
        else
            echo "Searching for ${search[i]}"
            curl -sfkL --retry-max-time 5 --retry 5 --ipv4 ${address[i]} | grep -q "${search[i]}"
            result=$?
            echo -e "grep return code $result \n"
        fi

        #check the result, if result != 0
        # -ne is 'not equal', not equal to zero
        if [ $result -ne 0 ];then
            echo "<tr><td>${name[i]}</td><td>&#128680;<mark>**DOWN**</mark>&#128680;</td></tr>" >> $log_file
            #Send email only on the top of the hour AND if it's flagged for email notification
            #if the time, in minutes, is less than 5 and email array element contains something (not empty)
            if [ "$(date +%M)" -lt 5 ] && [ -n "${email[i]}" ] ; then
                email_body+="$(date +%F) $(date +%T) - ${name[i]} is 🚨⚠️🚨 DOWN 🚨⚠️🚨\n"
            fi
        else
            echo "<tr><td><a href="${address[i]}">${name[i]}</a></td><td>&#127383;&#128076;</td></tr>" >> $log_file
        fi
    fi
done
echo "</table>" >> $log_file
#look in the html file, if any of the servers are DOWN add a gif to grab attention
if grep -q DOWN $log_file; then
    echo "<img src="web_images/server_down_yipyip.gif" width='250' height='188'>" >> $log_file
fi

#If one of the servers is down, send an email. if the string is empty send the email
if [ ${#email_body} -gt 1 ]; then
    echo -e "Subject: Host DOWN - Crapper Uptime Checking Script\n\n$email_body" | msmtp -v --account=lekatsas.us nicholas@lekatsas.us
fi