我实际上每周只使用几天,每天使用服务器几个小时。
它是一个备份服务器,它向客户端请求备份数据。
这部分已经处理好了,它通过预定的魔术包唤醒并执行其任务。一切都很好。我可以唤醒它以在计划外使用它,这也很好。
我如何让它知道网络已经有一段时间没有使用了,并让它进入睡眠状态?我想要记录的网络流量是 SSH、SFTP、rsync 和来自 Canonical 的更新。所有其他流量都是我不关心的闲聊。
我可能想将以下伪代码放入 cron 脚本中...每 15 分钟左右检查一次。我并不担心添加 cron 功能,我对此很有信心。
if [ lastSignificantNetworkActivity > 3h ] { hibernate }
我可能遇到了 X->Y 问题。我只想将我的服务器置于低功耗磁盘保存状态,通常 18 小时它不会执行任何操作。我认为网络活动是一个很好的测试指标。我愿意接受更完善、更强大的解决方案或固有的服务器属性来检查是否存在。
(我不确定每天的电源循环是否会比 ZFS 整天运行数据完整性检查而造成的持续磨损更糟糕……只是不确定。)
答案1
一种可能的实现方法是通过防火墙规则来找出 SSH 会话生成的网络流量的迹象:
- 最初,在启动时加载与往返于 22/tcp 端口的流量匹配的规则;
- 然后,脚本定期从防火墙检索统计信息,并将这些规则的命中次数存储到临时文件中;
- 该脚本将能够通过检测任何命中数的变化来检测网络流量。
由于这两个应用程序都通过 SSH 协议运行,因此该方法还可以检测 SFTP 和 RSYNC 生成的流量。
通过防火墙检测更新活动会比较困难,因为软件包下载使用 FTP、HTTP 和 HTTPS 协议,需要调整防火墙规则以区分软件更新和记录的 HTTP 流量。因此,我的建议是通过检查 、 和 的修改时间来检测/var/lib/apt/lists
软件/var/cache/apt/archives
更新/var/lib/dpkg/lock
。
我的实施方案如下:
这些命令行设置iptables
和ip6tables
规则。
# apt-get install iptables-persistent
# iptables -w -N fwstats
# iptables -w -A fwstats
# iptables -w -A INPUT -p tcp --dport 22 -m state --state ESTABLISHED -j fwstats
# iptables -w -A OUTPUT -p tcp --dport 22 -m state --state ESTABLISHED -j fwstats
# iptables-save > /etc/iptables/rules.v4
# ip6tables -w -N fwstats
# ip6tables -w -A fwstats
# ip6tables -w -A INPUT -p tcp --dport 22 -m state --state ESTABLISHED -j fwstats
# ip6tables -w -A OUTPUT -p tcp --dport 22 -m state --state ESTABLISHED -j fwstats
# ip6tables-save > /etc/iptables/rules.v6
这是等效的设置nftables
:
# apt-get install nftables
# nft add chain inet filter fwstats
# nft add rule inet filter fwstats counter
# nft add rule inet filter input tcp dport ssh ct state established jump fwstats
# nft add rule inet filter output tcp dport ssh ct state established jump fwstats
# echo -e \#\!`which nft` -f\\nflush ruleset > /etc/nftables.conf
# nft list ruleset >> /etc/nftables.conf
这是一个监控脚本的模板,具体getStats
功能需要根据使用的防火墙进行调整。
#!/bin/bash
getStats () {
if using_nftables; then
nft list chain inet filter fwstats | grep counter
elif using_xtables; then
for xtable in iptables ip6tables; do
"${xtable}" -w -xnvL fwstats | egrep '^([[:space:]]+[0-9]+){2,2}'
done
fi
}
stateFile="/run/hibernation_state"
currentStats="`getStats`"
if [ "x${currentStats}" != "x" ]; then
previousStats="`cat \"${stateFile}\"`"
if [ "x${currentStats}" == "x${previousStats}" ]; then
# No network traffic has been detected. Check files related do DPKG and APT
clearToHibernate='true'
now="`date '+%s'`"
for path in "${stateFile}" \
'/var/lib/apt/lists' \
'/var/cache/apt/archives' \
'/var/lib/dpkg/lock' ; do
pathModTime="`stat -c '%Y' "${path}"`"
# 10800 seconds = 3 hours
if [ "$((now-10800))" -lt "${pathModTime}" ]; then
clearToHibernate='false'
fi
done
if "${clearToHibernate}"; then
# OK to hibernate.
systemctl hibernate
fi
else
# Network traffic has been detected. Refresh stats.
echo "${currentStats}" > "${stateFile}"
fi
fi
答案2
这个想法太糟糕了!让我们自己想办法吧!
使忽略的 SSH 会话过期
cat > /etc/ssh/sshd_config <<EOF
AcceptEnv LANG LC_*
Banner none
ChallengeResponseAuthentication no
ClientAliveCountMax 0
ClientAliveInterval 1800
PasswordAuthentication yes
PrintMotd no
Subsystem sftp /usr/lib/openssh/sftp-server
UsePAM yes
X11Forwarding yes
EOF
安装 Hibernate
apt install hibernate
设置系统范围的日志格式,为了好玩
echo "HISTTIMEFORMAT=\"%Y-%m-%d %T \"" > /etc/environment
启动一个 cron 任务!
echo "0,12,24,36,48 * * * * root bash /usr/local/sbin/hibernation" >> /etc/crontab
现在,情况变得糟糕透了:
cat <<-EOF > /usr/local/sbin/hibernation
#!/bin/bash -i
# The hibernation delay script
echo "----------------------" >> /tmp/justchecking.txt
EXTEND=0
SCRIPTTIME=$(date +%s)
echo $(date) >> /tmp/justchecking.txt
echo "script timetamp" $SCRIPTTIME >> /tmp/justchecking.txt
# Make sure there is a hibernation time file
if [ ! -f /var/run/hibernation.time.txt ]
then
echo $SCRIPTTIME > /var/run/hibernation.time.txt
echo "created hibernation.time.txt sbin script" >> /tmp/justchecking.txt
fi
SLEEPTIME=$(</var/run/hibernation.time.txt)
if [ $SLEEPTIME -eq 999999999999 ]
then
echo "just came out of suspend, set extend to 360" >> /tmp/justchecking.txt
EXTEND=360
fi
# Check the logs for recent activity
HISTTIMEFORMAT="%Y-%m-%d %T "
HISTFILE=/root/.bash_history
set -o history
history 75 > /tmp/recenthistory.txt
set +o history
unset HISTFILE
ece
echo $(tail -n5 /var/log/apt/history.log | head -n1) "apt" >> /tmp/recenthistory.txt
LASTACTIVITY=$(grep -e apt -e dpkg -e chebackup /tmp/recenthistory.txt | tail -n1 | awk '{print $2" "$3}')
echo "last activity" $LASTACTIVITY >> /tmp/justchecking.txt
#LASTACTIVITYDATE="$(</tmp/recenthistory.txt)"
#echo "last activity date"$LASTACTIVITYDATE"." >> /tmp/justchecking.txt
# Store last activity date time as a timestamp
ACTIVITYTIMESTAMP=$(date -d "$LASTACTIVITY" +%s)
echo "activity time stamp" $ACTIVITYTIMESTAMP >> /tmp/justchecking.txt
# Calculate
ACTIVITYCOOLDOWNTIME=$(( 3960 - ( $SCRIPTTIME - $ACTIVITYTIMESTAMP ) ))
echo "activity cool down time" $ACTIVITYCOOLDOWNTIME >> /tmp/justchecking.txt
(($ACTIVITYCOOLDOWNTIME > 0)) && EXTEND=$ACTIVITYCOOLDOWNTIME
echo "extend variable after activity cool down command" $EXTEND >> /tmp/justchecking.txt
#if [ $ACTIVITYCOOLDOWNTIME > 0 ]
# then
# echo "activity was recent, adding cooldowntime to extend" >> /tmp/justchecking.txt
# EXTEND = $ACTIVITYCOOLDOWNTIME
#fi
# Check for updates or backup currently running
if [ $(ps -aux | grep -e apt -e dpkg -e chebackup | wc -l) -gt 1 ]
then
EXTEND=3960
SLEEPTIME=$(($SCRIPTTIME + $EXTEND))
echo $(ps -aux | grep -e apt -e dpkg -e chebackup | wc -l) > /tmp/justchecking.txt
echo "activity actively running, extended 3960" >> /tmp/justchecking.txt
fi
# Check for any users logged in
if [ $(who -u | wc -l) -gt 0 ]
then
EXTEND=10800
#EXTEND=180
echo $(who -u) >> /tmp/justchecking.txt
echo "extended 10800" >> /tmp/justchecking.txt
#echo "extend 180" >> /tmp/justchecking.txt
fi
echo "sleeptime" $SLEEPTIME >> /tmp/justchecking.txt
if [ $EXTEND -gt 0 ]
then
SLEEPTIME=$(($SCRIPTTIME + $EXTEND))
fi
if [ $SLEEPTIME -lt $SCRIPTTIME ]
then
echo "hibernate" >> /tmp/justchecking.txt
echo $(date +%s) >> /tmp/justchecking.txt
echo "hibernate" >> /tmp/justchecking.txt
echo "999999999999" > /var/run/hibernation.time.txt
hibernate &
disown
else
echo $SLEEPTIME > /var/run/hibernation.time.txt
echo "update sleeptime" $SLEEPTIME >> /tmp/justchecking.txt
fi
tail -n100 /tmp/justchecking.txt > /tmp/justchecking.txt
wc -l /tmp/justchecking.txt >> /tmp/justchecking.txt
exit 0
EOF
不要忘记更改权限
chmod 500 /usr/local/sbin/hibernation