Shell Script To Monitor Services Such As Web / Http, Ssh, Mail Server

by on April 10, 2008 · 31 comments

#!/bin/bash
# Shell script to monitor running services such as web/http, ssh, mail etc.
# If service fails it will send an Email to ADMIN user
# -------------------------------------------------------------------------
# Copyright (c) 2006 nixCraft project <http://www.cyberciti.biz/fb/>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# ----------------------------------------------------------------------
# See URL for more info
# http://www.cyberciti.biz/tips/processing-the-delimited-files-using-cut-and-awk.html
# ---------------------------------------------------
# Last updated: Jun - 15 - 2009.
ports="22 53 80 25"
 
# service names as per above ports
service="SSH DNS WEB MAIL"
 
#Email id to send alert
ADMINEMAIL="admin@myispname.com"
 
#Bin paths, set them according to your Linux distro
NETSTAT=/bin/netstat
MAIL=/usr/bin/mail
LOGGER=/usr/bin/logger
ID=/usr/bin/id
 
# Red hat usr uncomment
MAIL=/bin/mail
LOGGER=/bin/logger
 
#Counters, set defaults
c=1
status=""
sendmail=0
 
# set the following to 1, if you want message in /var/log/messages via a SYSLOG
logtosyslog=0
 
# Log file used to send an email
LOG="/tmp/services.log.$$"
 
# log message to screen and a log file
log(){
	echo "$@"
	echo "$@" >> $LOG
}
 
# log message and stop script
die(){
	echo "$@"
	exit 999
}
 
# Make sure only root can run it
is_root(){
	local id=$($ID -u)
	[ $id -ne 0 ]  && die "You must be root to run $0."
}
# Look out for all bins and create a log file
init_script(){
	[ ! -x $MAIL ] && die "$MAIL command not found."
	[ ! -x $NETSTAT ] && die "$NETSTAT command not found."
	[ ! -x $LOGGER ] && die "$LOGGER command not found."
	[ ! -x $ID ] && die "$ID command not found."
	is_root
	>$LOG
}
 
# check for all running services and shoot an email if service is not running
chk_services(){
	log "-------------------------------------------------------------"
	log "Running services status @ $(hostname) [ $(date) ]"
	log "-------------------------------------------------------------"
 
	# get open ports
	RPORTS=$($NETSTAT -tulpn -A inet | grep -vE '^Active|Proto' | grep 'LISTEN' | awk '{ print $4}' | cut -d: -f2 | sed '/^$/d' | sort  -u)
 
	# okay let us compare them
	for t in $ports
	do
		sname=$(echo $service | cut -d' ' -f$c)
		echo -en " $sname\t\t\t : "
		echo -en " $sname\t\t\t : " >> $LOG
		for r in $RPORTS
		do
			if [ "$r" == "$t" ]
			then
				status="YES"
				sendmail=1
				break
			fi
		done
		echo -n "$status"
		echo ""
		echo -n "$status" >>$LOG
		echo "" >>$LOG
		# Log to a syslog /var/log/messages?
		# This is useful if you have a dedicated syslog server
		[ $logtosyslog -eq 1  ] && $LOGGER "$sname service running : $status"
 
		# Update counters for next round
		c=$( expr $c + 1 )
		status="NO"
	done
	log "-------------------------------------------------------------"
	log "This is an automatically generated $(uname) service status notification by $0 script."
 
	if [ $sendmail -eq 1 ];
	then
		$MAIL -s "Service Down @ $(hostname)" $ADMINEMAIL < $LOG
	fi
}
 
### main ###
init_script
chk_services
 
### remove a log file ###
[ -f $LOG ] && /bin/rm -f $LOG
4000+ howtos and counting! If you enjoyed this article, join 45000+ others and get free email updates!

{ 31 comments… read them below or add one }

21 hadi February 10, 2010

hi.. can you send to me the external script to my email hadi.utomo@gmail.com

22 shaiju March 22, 2010

Hi thanks for the script..
How to monitor a new port using the scrip.i want to monitor 8080,and i changed port in the ports=”22 53 80 8080″
when running the script it is showing that
SSH : YES
DNS : YES
WEB : YES
tomcat : NO
please help me
Regards
Shaiju

23 Jesse April 9, 2010

It’s emailing me even when all services are up:

$ sudo ./monitor.sh
————————————————————-
Running services status @ sabresboard [ Fri Apr 9 18:50:43 EDT 2010 ]
————————————————————-
SSH : YES
WEB : YES
MAIL : YES
————————————————————-
This is an automatically generated Linux service status notification by ./monitor.sh script

Still sends me an email.

24 Samarasa June 15, 2010

Where is updated scripts

25 smeven July 14, 2010

My experience is that if a port of a running service dosn’t show up in the netstat line, it’s because it’s not using the protocol inet, but inet6 istead.
try netstat -tulpn -A inet,inet6 , but the some modifications to the cut part of this line has to be done also.
cut -d: -f2 would fail because of the format of inet6 is different , try cut -d: -f2,4 | cut -d: -f2 instead.

26 Shaiju August 26, 2010

Hi Smeven,
Thanks a lot…its worked Fine…:)
We want ot chane #get open ports section to
RPORTS=$($NETSTAT -tulapn -A inet,inet6 | grep -vE ‘^Active|Proto’ | grep ‘LISTEN’ | awk ‘{ print $4}’ | cut -d: -f2,4 | cut -d: -f2 | sed ‘/^$/d’ | sort -u) .Then only it will works on Ipv6..

Regards,
Shaiju

27 Brian October 10, 2010

Hi,
You have a couple of bugs.
1. The script sends whenever at least one process is UP, you want the opposite.
2 You need to set status to ‘NO’ at the beginning of the loop rather than the end, otherwise if the first service is down it will have a status of empty string.
3. I would recommend using variables more descriptive than a single character, it will make it easier to read.

Here are the changes you need to make (note that I renamed the c variable to ‘count’):

# okay let us compare them
for t in $ports
do
status=”NO”
sname=$(echo $service | cut -d’ ‘ -f$count)
echo -en ” $sname\t\t\t : ”
echo -en ” $sname\t\t\t : ” >> $LOG
for r in $RPORTS
do
if [ "$r" == "$t" ]
then
status=”YES”
break
fi
done
if [ "$status" == "NO" ]
then
sendmail=1
fi
echo -n “$status”
echo “”
echo -n “$status” >>$LOG
echo “” >>$LOG
# Log to a syslog /var/log/messages?
# This is useful if you have a dedicated syslog server
[ $logtosyslog -eq 1 ] && $LOGGER “$sname service running : $status”

# Update counters for next round
count=$( expr $count + 1 )
done

28 Brian October 10, 2010

Whoops forgot to use the code blocks


# okay let us compare them
for t in $ports
do
status="NO"
sname=$(echo $service | cut -d' ' -f$count)
echo -en " $sname\t\t\t : "
echo -en " $sname\t\t\t : " >> $LOG
for r in $RPORTS
do
if [ "$r" == "$t" ]
then
status="YES"
break
fi
done
if [ "$status" == "NO" ]
then
sendmail=1
fi
echo -n "$status"
echo ""
echo -n "$status" >>$LOG
echo "" >>$LOG
# Log to a syslog /var/log/messages?
# This is useful if you have a dedicated syslog server
[ $logtosyslog -eq 1 ] && $LOGGER "$sname service running : $status"

# Update counters for next round
count=$( expr $count + 1 )
done

29 MuaDDip October 17, 2010

RPORTS=$($NETSTAT -tulpn | grep -vE ‘^Active|Proto’ | grep ‘LISTEN’ | awk ‘{ print $4}’ | sed ‘s/[0-9a-z\.\:]*\:\([0-9]\+\)$/\1/’ | sort -u)

30 Aneesh July 12, 2011

On .el5 this is not working . Only SMTP status printed properly.

31 Michael Pivonka April 12, 2012

Had problem with httpd not using a set ip and with the command in script above does not find services that don’t have them attached to an ip. So I have fixed this with the following command.

NETSTAT -tulpn | grep -vE '^Active|Proto' | grep 'LISTEN' | awk '{ print $4}' | awk -F: '{print $NF}' | sed '/^$/d' | sort -u

Leave a Comment

You can use these HTML tags and attributes for UNIX commands or shell scripts: <strong> <em> <ol> <li> <u> <ul> <blockquote> <pre> <a href="" title="">
What is 12 + 8 ?
Please leave these two fields as-is:
Are you a human being? Solve the simple math so we know that you are a human and not a script.



Tagged as: adminemail, delimited, delimiter, echo line, echo service, expr, for loop, grep, loop method, mail service, mail services, monitor mail server, monitore web server, script collection, sendmail, service names, service status, shell loops, sudo, web mail, while loop

Previous Script:

Next Script: