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?
#!/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 $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>🚨<mark>**DOWN**</mark>🚨</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>🆗👌</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