I want to shut down my nethserver during night if not used anymore.
Before I used nethserver I had a Ubuntu based server and had a script installed which checked the LAN for active devices. The script was started when the system reached a specific runlevel.
I want to realize the same on my nethserver and I’m not sure which would be a practicable way to do this. Would it be better to configure it with systemd, as a action or …?
Does anybody has a hint or realized the same already?
I’ve had clients requiring something similiar in the past.
First thing is agreeing on time frames: Must be running, can run, should be off…
During the can run period, run a check script eg on connected windows hosts (PCs / Notebooks) Most of the clients requiring this happened to be mostly Windows shops…
If no Windows are registered within two check routines (Every 15 Minutse), the server is then shut down by another script, checking if the f"lags" above are set. (Windows yes, two flags…).
To keep things simple, these were two files created / modified / deleted by the check scripts, in a secified folder (/etc/checkscripts). The simple existance of those files was checked using if exist, then triggering shutdown if true…
All of this of course after the last backup of the day!
In the morning, the server is either started from BIOS at a set time, or waken using WOL (Wake on LAN) from another host, like the OPNsense firewall…
Hi,
here is the script. It is based on script published by the c’t magazine couple of years ago which I modified a little bit.
#!/bin/bash
#
# Server v0.5.1b
#
# Überwacht das LAN auf aktive Rechner und
# fährt den Server runter, wenn niemand mehr
# im LAN aktiv ist
#
# version 0.1 basic features
# version 0.2 add status request, some minor bugfixes
# version 0.2.1 supports gettext for output, checks UID, remove some
# bashish style like function keywords ...
# version 0.2.2 added a init info section for debian and opensuse (dependence boot/init)a
# version 0.3.0 feature added: check of ip range (i.e for IPs given by DHCP)
# version 0.4.0 feature added: set different hours to check depending on day of week
# version 0.4.1 feature added: Toggle added to switch on/off ip range check
# version 0.5.0 changes: Logging to a specific logfile instead of the use of 'logger' using /var/log/syslog
# version 0.5.1 changes: Some changes in code
#
#
# Redaktion c't / heise netze
# http://ct.de
# http://www.heisenetze.de
# mercurial repository: http://mercurial.intuxication.org/hg/server-sleepd
# example: hg clone http://mercurial.intuxication.org/hg/server-sleepd
### BEGIN INIT INFO
# Provides: server-sleepd
# Required-Start: $network $syslog $remote_fs
# Required-Stop: $network $syslog $remote_fs
# Default-Start: 3 5
# Default-Stop: 0 1 2 6
# Short-Description: stopps the server if there is no active host in the lan
# Description: stopps the server if there is no active host in the lan
### END INIT INFO
##
# multilanguage support via get
TEXTDOMAINDIR=/usr/local/share/locale/
TEXTDOMAIN=server-sleepd
#Switch on the debug function
# DEBUG: 1 == an/on, '' == aus/off
DEBUG=''
# Switch on/off the logging to a specific file
# 1 == an/on, '' == aus/off
LOGGING='1'
LOGDATE=$(date +%d.%m.%Y" "%X)
BASENAME=$(basename $0)
LOGFILE="/var/log/${BASENAME%.*}.log"
[ ${LOGGING} ] && echo $"----- ${LOGDATE} Script '${BASENAME}' started ------" >> ${LOGFILE}
##
# Testen ob das Skript mit root Berechtigungen aufgerufen wird
# Check if the script is started with root permissions
if [ ${UID} -ne 0 ]
then
[ ${DEBUG} ] && echo "Missing permissions: The script needs to be started with root permissions!"
[ ${LOGGING} ] && echo ${LOGDATE} $"Missing permissions: You must run the script with root permissions!" >> ${LOGFILE}
exit 1
fi
# Lockfile enthält Prozess-ID (PID)
LOCKFILE="/var/run/${BASENAME}.pid"
# Ping-Befehl mit Parametern
# hier: sendet zwei Anfragen
PING="ping -c 2"
# Liste der zu testenden IP-Adressen in das Array 'HOSTS' schreiben
# Write list of IP-adresses to be checked into array 'HOSTS'
HOSTS=(
192.168.234.9
192.168.234.10
192.168.234.13
)
# Definition eines IP-Subnetzes und eines IP-Adressbereichs (z.B. via DHCP vergebene IP-Adressen)
# Definition of a IP-subnet and IP-addressrange to check (i.e. DHCP)
CheckIPRange=yes # 'yes' = an/on '' == aus/off
subnetIP=192.168.234.0
startIP=151
endIP=179
# Prüfintervall des skripts (Zeit in Sekunden)
# Interval in Seconds
INTERVAL=1800
# Festlegen an welchem Tag zu welcher Stunde geprüft werden soll
# Set the hours when to check depending on day of week
WEEKDAY=$(date +%u)
case $WEEKDAY in
1) # Monday/Montag
TIME2CHECK="00 01 10 11 12 13 14 15 16 17 18 19 20 21 22 23"
;;
2) # Tuesday/Dienstag
TIME2CHECK="00 01 10 11 12 13 14 15 16 17 18 19 20 21 22 23"
;;
3) # Wednesday/Mittwoch
TIME2CHECK="00 01 10 11 12 13 14 15 16 17 18 19 20 21 22 23"
;;
4) # Thursday/Donnerstag
TIME2CHECK="00 01 10 11 12 13 14 15 16 17 18 19 20 21 22 23"
;;
5) # Friday/Freitag
TIME2CHECK="00 01 10 11 12 13 14 15 16 17 18 19 20 21 22 23"
;;
6) # Saturday/Samstag
TIME2CHECK="00 01 10 11 12 13 14 15 16 17 18 19 20 21 22 23"
;;
7) # Sunday/Sonntag
TIME2CHECK="00 01 10 11 12 13 14 15 16 17 18 19 20 21 22 23"
;;
esac
# Vorgabewert für die Zustandsvariable 'ACTIVE'
# Default value for 'ACTIVE'
ACTIVE=false
# shutdown- oder sleep-Befehl samt Parameter
# *BITTE anpassen* /bin/true ist zum Testen gedacht!
#
# CMD="/sbin/shutdown -h now" # now or +10m
# CMD="/sbin/halt"
# CMD="/usr/sbin/pm-suspend"
# CMD="/usr/sbin/pm-powersave"
# CMD="/bin/true"
delay='+3' # +time_of_delay (i.e +3) or 'now'
CMD="/sbin/shutdown -h $delay"
##
# Liste der Hosts überprüfen
# check the list 'HOSTS'
checkhosts()
{
ACTIVE=false
HOSTcount=${#HOSTS[*]}
indexHOSTS='0'
while [ $indexHOSTS -lt $HOSTcount ]
do
${PING} ${HOSTS[$indexHOSTS]} > /dev/null
if [ $? -eq 0 ]
then
[ ${DEBUG} ] && echo $"$0: ${HOSTS[$indexHOSTS]} is active!"
[ ${LOGGING} ] && echo ${LOGDATE} "host ${HOSTS[$indexHOSTS]} is active" >> ${LOGFILE}
ACTIVE=true
break # Schleife beenden wenn ein aktiver Host gefunden wurde / terminate the loop when an active machine is found
else
[ ${DEBUG} ] && echo $"$0: ${HOSTS[$indexHOSTS]} is not active!"
[ ${LOGGING} ] && echo ${LOGDATE} "host ${HOSTS[$indexHOSTS]} is not active" >> ${LOGFILE}
fi
((indexHOSTS++))
done
# Wenn kein Host aus der Liste 'HOSTS' aktiv ist, nach Hosts im angegebenen IP-Adressbereich suchen
# If no host of the list 'HOSTS' is active, then look for hosts in the given IP-adress range
if [ "${ACTIVE}" = "false" ] && [ "${CheckIPRange}" = "yes" ]
then
checkIP=$startIP
while [ ${checkIP} -le ${endIP} ]
do
ADDR=${subnetIP%.*}"."${checkIP}
${PING} ${ADDR} > /dev/null
if [ $? -eq 0 ] # Wenn Ping erfolgreich / If Ping unsuccessful
then
[ ${DEBUG} ] && echo $"$0: IP-adress range: "${subnetIP%.*}"."${startIP}" - "${subnetIP%.*}"."${endIP}": host "${ADDR}" is active!"
[ ${LOGGING} ] && echo ${LOGDATE} "IP-adress range: "${subnetIP%.*}"."${startIP}" - "${subnetIP%.*}"."${endIP}": host "${ADDR}" is active" >> ${LOGFILE}
ACTIVE=true
break # Schleife beenden wenn ein aktiver Host gefunden wurde / terminate the loop when an active machine is found
elif [ $? -eq 1 ] # Wenn Ping nicht erfolgreich / If Ping unsuccessful
then
[ ${DEBUG} ] && echo $"$0: IP-adress range: "${subnetIP%.*}"."${startIP}" - "${subnetIP%.*}"."${endIP}": host "${ADDR}" is not active!"
[ ${LOGGING} ] && echo ${LOGDATE} "IP-adress range: "${subnetIP%.*}"."${startIP}" - "${subnetIP%.*}"."${endIP}": host "${ADDR}" is not active" >> ${LOGFILE}
elif [ $? -eq 1 ] && [ ${checkIP} -eq ${endIP} ] # Wenn Ping nicht erfolgreich und die letzte IP-Adresse überprüft wurde/ If Ping unsuccessful and last IP-adress ist checked
then
[ ${DEBUG} ] && echo $"$0: IP-adress range: "${subnetIP%.*}"."${startIP}" - "${subnetIP%.*}"."${endIP}": No host active!"
[ ${LOGGING} ] && echo ${LOGDATE} "IP-adress range: "${subnetIP%.*}"."${startIP}" - "${subnetIP%.*}"."${endIP}": No host active!" >> ${LOGFILE}
break
fi
(( checkIP++ ))
done
fi
# Wenn 'ACTIVE' immernoch 'false, dann den Server ausschalten
# If 'ACTIVE' is still 'false', switch the server off
if [ "${ACTIVE}" = "false" ]
then
[ ${DEBUG} ] && echo $"$0: No active hosts, no users logged in, running 'CMD' ..."
[ ${LOGGING} ] && echo ${LOGDATE} "No active hosts, no users logged in, running 'CMD' ..." >> ${LOGFILE}
shutoff
else
[ ${DEBUG} ] && echo $"$0: One host is active, continue ..."
[ ${LOGGING} ] && echo ${LOGDATE} "One host is active, continue ...." >> ${LOGFILE}
fi
}
##
# Server ausschalten
# Turn the server off
shutoff()
{
if [ $delay = now ]
then
[ ${DEBUG} ] && echo $"$0: Executing command $CMD ...System is going down $delay!"
[ ${LOGGING} ] && echo ${LOGDATE} $"Executing command $CMD ...System is going down $delay!" >> ${LOGFILE}
else
[ ${DEBUG} ] && echo $"$0: Executing command $CMD ...System is going down in ${delay#+} minutes!"
[ ${LOGGING} ] && echo ${LOGDATE} $"Executing command $CMD ...System is going down in ${delay#+} minutes!" >> ${LOGFILE}
fi
${CMD}
}
##
# Überprüfe auf lokal oder per SSH angemeldete Nutzer, Screen-Sitzungen werden berücksichtigt
# Check for local users or users logged in via SSH, screen sessions are considered
localUsers()
{
countUSers=$(who | sed '/^\s*$/d' | wc -l) # Anzahl der Zeilen der Ausgabe von 'who' / Number of lines of the command 'who'
[ $DEBUG ] && echo $"$0: local users: $countUSers "
if [ $countUSers -gt 0 ]
then
ACTIVEUSERS=$(who -q)
ACTIVEUSERS=${ACTIVEUSERS%#*}
fi
return ${countUSers}
}
##
# Hauptprogramm
# Dauerschleife bis Strg-C, kill, killall ...
# Aufräumarbeiten erledigt das Trap-Kommando oben
case "$1" in
start)
if [ -e ${LOCKFILE} ] # wenn Lockfile vorhanden / if Lockfile exists
then
echo "Script '$BASENAME' is already running!"
exit
else
[ ${LOGGING} ] && echo $"----- ${LOGDATE} Script '${BASENAME}' started ------" >> ${LOGFILE}
echo -ne $"Starting $0 "
$0 run &
while [ ! -e ${LOCKFILE} ] # wenn Lockfile nicht vorhanden / if Lockfile doesn't exist
do
echo -ne "."
sleep 2
done
echo $"(PID: "`cat ${LOCKFILE}`")."
exit
fi
;;
stop)
if [ -e ${LOCKFILE} ]
then
CPID=`cat ${LOCKFILE}`
echo -ne $"Stopping $0 with PID $CPID "
# beenden mit SIGTERM,
# warte bis PID-File entfernt ist
while [ -e ${LOCKFILE} ]
do
echo -ne "."
kill ${CPID}
sleep 3
done
echo $"[done]"
[ ${LOGGING} ] && echo $"----- ${LOGDATE} Script '${BASENAME}' stopped ------" >> ${LOGFILE}
else
echo $"Script '${BASENAME}' is not running."
exit
fi
;;
restart)
[ ${LOGGING} ] && echo $"----- ${LOGDATE} Restarting script '${BASENAME}' ------" >> ${LOGFILE}
$0 stop ; $0 start
;;
run)
if [ -e ${LOCKFILE} ] # wenn Lockfile vorhanden / if Lockfile exists
then
CPID=$(cat ${LOCKFILE})
echo $"Script is already running. (PID: ${CPID})"
exit -1
else
# PID File samt PID speichern
# wird via trap am Programm-Ende wieder
# entsorgt
echo $$ > ${LOCKFILE}
trap "rm -f ${LOCKFILE}; exit" INT TERM EXIT
fi
# foreground
while true
do
sleep $INTERVAL
for hour in ${TIME2CHECK}
do
if [ `date +%H` -eq ${hour} ]
then
[ $DEBUG ] && echo $"$0: (TIME2CHECK) hour '"$hour"' matches current time"
[ ${LOGGING} ] && echo ${LOGDATE} "(TIME2CHECK): hour '"$hour"' matches current time" >> ${LOGFILE}
# Wenn kein Nutzer angemeldet ist die Hosts überprüfen, ansonsten Skript weiter ausführen
# If no user is logged in check the hosts, otherwise continue the script
localUsers
case $countUSers in
0) [ ${DEBUG} ] && echo $"No user logged in"
[ ${LOGGING} ] && echo ${LOGDATE} "No user logged in" >> ${LOGFILE}
checkhosts #hosts überprüfen / check hosts
;;
1) [ ${DEBUG} ] && echo $"$countUSers user logged in. Name of user logged in: ${ACTIVEUSERS}"
[ ${LOGGING} ] && echo ${LOGDATE} "$countUSers user logged in. Name of user logged in: ${ACTIVEUSERS}" >> ${LOGFILE}
;;
*) [ ${DEBUG} ] && echo $"$countUSers users logged in. Names of users logged in: ${ACTIVEUSERS}"
[ ${LOGGING} ] && echo ${LOGDATE} "$countUSers users logged in. Names of users logged in: ${ACTIVEUSERS}" >> ${LOGFILE}
;;
esac
elif [ `date +%H` -lt ${hour} ]
then
break
else
[ ${DEBUG} ] && echo $"$0: (TIME2CHECK) hour '"$hour"' is checked"
[ ${LOGGING} ] && echo ${LOGDATE} "(TIME2CHECK): hour '"$hour"' is checked" >> ${LOGFILE}
continue
fi
done
done
;;
status)
# Statusabfrage
if [ -e ${LOCKFILE} ] # wenn Lockfile vorhanden / if Lockfile exists
then
CPID=$(cat ${LOCKFILE})
echo "Script '$BASENAME' is running with PID $CPID "
else
echo "Script '$BASENAME' is not running."
fi
exit
;;
*)
echo $"usage: $0 start|stop|restart|run|status"
echo $"options:"
echo $" start: runs program in background"
echo $" stop: stops background program"
echo $"restart: restarts a running instance"
echo $" run: runs program in foreground, stopp with Strg-C"
echo $" status: checks whether program is running"
exit
;;
esac
I’m an avid user of OPNsense for my 30 clients.
OPNsense comes with a WOL module and GUI.
Once that’s installed, it’s simply a matter of setting a cron job at the right time.
Create a script file, eg /etc/Jobs/wol.script. Set the command including the MAC Address in there.
Don’t forget to set the right permissions on the script / folder (700, user root/group root).