前提条件:
sudo apt updatesudo apt install -y vnstat jqsudo systemctl enable --now vnstatsudo vnstat --versionsudo vnstat --iflistsudo vnstat --add -i eth0 # 初始化接口数据库(2.x)sudo systemctl enable --now vnstatsudo systemctl restart vnstatvnstat -i eth0 --days检测脚本:
#!/usr/bin/env bash# v2.9.eth0.monthly.800GiB# 功能:使用 vnStat 读取“本自然月(month[0])”的出站(tx)字节,总量 >= 800 GiB 时关机。# 依赖:vnstat, jq, systemd (用于关机与服务管理)# 用法:作为 systemd oneshot 服务由定时器每分钟/每N分钟调用一次,或手动执行测试。# 注意:需以 root 运行。set -euo pipefail### ======================== 可 配 置 区 =========================IFACE="eth0" # 监控的网卡THRESHOLD_GIB=800 # 本月出站阈值(GiB,1024^3)LOG_TAG="tx-quota" # syslog 标签AUTO_INSTALL=true # 若未安装 vnstat/jq,是否自动安装(基于 apt)SHUTDOWN_CMD="/usr/bin/systemctl poweroff" # 触发动作(可改为 halt/reboot)### ============================================================THRESHOLD_BYTES=$(( THRESHOLD_GIB * 1024 * 1024 * 1024 ))require_root() { if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then echo "This script must run as root." >&2 exit 1 fi}have_cmd() { command -v "\$1" >/dev/null 2>&1; }auto_install_deps() { local missing=() have_cmd vnstat || missing+=("vnstat") have_cmd jq || missing+=("jq") if (( ${#missing[@]} > 0 )); then if [[ "$AUTO_INSTALL" == "true" ]]; then if have_cmd apt-get; then echo "Installing dependencies: ${missing[*]} ..." apt-get update -y apt-get install -y "${missing[@]}" else echo "Missing deps: ${missing[*]} and apt-get not found. Install them manually." >&2 exit 1 fi else echo "Missing deps: ${missing[*]}. Set AUTO_INSTALL=true or install manually." >&2 exit 1 fi fi}ensure_vnstat_running_and_iface() { # 确保 vnstat 服务运行 if have_cmd systemctl; then systemctl enable --now vnstat.service >/dev/null 2>&1 || true fi # 确保接口已被 vnstat 追踪(若数据库不存在则初始化) # vnstat -u -i 不会破坏已有数据;仅在缺失时创建数据库 vnstat -u -i "$IFACE" >/dev/null 2>&1 || true # 尝试读取一次,若失败则再重启服务后重试 if ! vnstat --json m -i "$IFACE" >/dev/null 2>&1; then have_cmd systemctl && systemctl restart vnstat.service >/dev/null 2>&1 || true # 再给数据库一点时间(通常不需要;保险起见) sleep 1 fi}get_monthly_tx_bytes() { # 取“本月”的 tx(bytes)。vnStat JSON 结构:interfaces[0].traffic.month[0].tx # 某些刚初始化的环境可能 month[0] 不存在 -> 用 // 0 兜底 local json tx set +e json=$(vnstat --json m -i "$IFACE" 2>/dev/null) local rc=$? set -e if (( rc != 0 )) || [[ -z "$json" ]]; then echo 0 return fi tx=$(echo "$json" | jq -r '.interfaces[0].traffic.month[0].tx // 0' 2>/dev/null || echo 0) [[ "$tx" =~ ^[0-9]+$ ]] || tx=0 echo "$tx"}main() { require_root auto_install_deps ensure_vnstat_running_and_iface # 读取本月出站总量(bytes) local tx_bytes tx_bytes="$( get_monthly_tx_bytes )" # 记录日志并判断 if (( tx_bytes >= THRESHOLD_BYTES )); then logger -t "$LOG_TAG" "Monthly outbound on ${IFACE}: ${tx_bytes} >= ${THRESHOLD_BYTES}; shutting down." echo "Quota exceeded: ${tx_bytes} >= ${THRESHOLD_BYTES}. Powering off..." # 防止重复触发:如果你用的是 systemd 定时器,关机会终止后续调用;无需额外去重。 $SHUTDOWN_CMD else logger -t "$LOG_TAG" "Monthly outbound on ${IFACE}: ${tx_bytes}/${THRESHOLD_BYTES}; ok." echo "OK: ${tx_bytes}/${THRESHOLD_BYTES} bytes used this month on ${IFACE}." fi}main "$@"配置服务:
# /etc/systemd/system/shutdown-on-monthly-tx-quota.service[Unit]Description=Shutdown when monthly outbound on eth0 exceeds 800GiB (vnStat)[Service]Type=oneshotExecStart=/usr/local/sbin/shutdown_on_monthly_tx_quota.sh配置定时:
# /etc/systemd/system/shutdown-on-monthly-tx-quota.timer[Unit]Description=Run monthly outbound quota checker every 10 minutes[Timer]OnBootSec=10minOnUnitActiveSec=10minUnit=shutdown-on-monthly-tx-quota.service[Install]WantedBy=timers.target定时启动:
sudo systemctl daemon-reloadsudo systemctl enable --now shutdown-on-monthly-tx-quota.timer
评论 (0)