N1搭建守护环境以及重装 Armbian 后完整恢复整套守护环境,清理日志步骤

一,从零搭建守护环境

1,在 root 目录下新建 all-n1-install.sh 文件,内容如下

bash 复制代码
#!/bin/bash
set -e
echo "==== N1盒子自愈全套【无jq版·重新生成守护环境】 ===="

# 不再安装jq依赖
echo "[1/7] 跳过jq依赖,使用pm2 id返回码判断状态"

# 2.生成 /root/n1.sh
echo "[2/7] 生成 /root/n1.sh"
cat > /root/n1.sh <<'INNER_EOF'
#!/bin/bash
# N1盒子服务自愈脚本【无jq最终版】
# 宿主机服务: go-cqhttp sillyGirl xdd
# 青龙容器内服务:默认关闭巡检 QL_APPS=()
QL_CONTAINER="qinglong"
LOCK_DIR="/root/.n1-deploy"
LOG_FILE="/root/ql/logs/selfheal.log"
CRON_LOG="/root/ql/logs/cron-n1.log"
PM2_LOG_DIR="/root/.pm2/logs"

mkdir -p "${LOCK_DIR}"
mkdir -p "/root/ql/logs"
mkdir -p "${PM2_LOG_DIR}"

# ====================== 配置参数 ======================
log_max_size=$((20*1024*1024))   # 单文件上限 20MB
log_keep_days=3                  # 碎片日志保留天数
docker_exec_timeout=8            # docker exec超时秒数
# =====================================================

## ① 主日志超过阈值清空
for logfile in "${LOG_FILE}" "${CRON_LOG}";do
    if [ -f "${logfile}" ];then
        filesize=$(stat -c%s "${logfile}")
        if [ "${filesize}" -gt "${log_max_size}" ];then
            > "${logfile}"
        fi
    fi
done

## ② 碎片日志过期删除
find /root/ql/logs -type f -name "*.log" ! -name "selfheal.log" ! -name "cron-n1.log" -mtime +${log_keep_days} -delete

## ③ 宿主机pm2日志处理
for logfile in ${PM2_LOG_DIR}/*.log;do
    if [ -f "${logfile}" ];then
        filesize=$(stat -c%s "${logfile}")
        if [ "${filesize}" -gt "${log_max_size}" ];then
            > "${logfile}"
        fi
    fi
done
find "${PM2_LOG_DIR}" -type f -name "*.log" -mtime +${log_keep_days} -delete

## ④ docker容器日志截断
docker_log_path=$(docker inspect --format='{{.LogPath}}' "${QL_CONTAINER}" 2>/dev/null || true)
if [ -n "${docker_log_path}" ] && [ -f "${docker_log_path}" ];then
    docker_log_size=$(stat -c%s "${docker_log_path}")
    if [ "${docker_log_size}" -gt "${log_max_size}" ];then
        truncate -s 0 "${docker_log_path}"
    fi
fi

# 互斥锁,防止脚本并发运行
exec 9>"${LOCK_DIR}/n1.lock"
if ! flock -n 9 ; then
    echo "$(date '+%Y-%m-%d %H:%M:%S') n1.sh 已在运行,放弃本次执行" >> ${LOG_FILE}
    exit 0
fi

log(){
    echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> ${LOG_FILE}
    echo "$*"
}

# ---------------- pm2 id方式检测,无jq ----------------
host_is_online(){
    local app="$1"
    pm2 id "${app}" >/dev/null 2>&1
    return $?
}

ql_is_online(){
    local app="$1"
    docker exec --timeout ${docker_exec_timeout} "${QL_CONTAINER}" pm2 id "${app}" >/dev/null 2>&1
    return $?
}

HOST_APPS=("go-cqhttp" "sillyGirl" "xdd")
QL_APPS=()

log "=== N1 夜维 $(date '+%Y-%m-%d_%H:%M') ==="

# 宿主机服务巡检
host_ok=0
host_total=${#HOST_APPS[@]}
for app in "${HOST_APPS[@]}";do
    if host_is_online "${app}";then
        log "✅ 腿[${app}] online"
        host_ok=$((host_ok+1))
    else
        log "⚠️ 腿[${app}] 异常,执行重启"
        log "🔧 重启宿主机 ${app}"
        pm2 restart "${app}" >>${LOG_FILE} 2>&1
    fi
done
log "${host_ok}/${host_total}"

# 容器服务巡检,QL_APPS为空数组时不会循环执行
ql_ok=0
ql_total=${#QL_APPS[@]}
for app in "${QL_APPS[@]}";do
    if ql_is_online "${app}";then
        log "✅ ql[${app}] online"
        ql_ok=$((ql_ok+1))
    else
        log "⚠️ ql[${app}] 异常,执行重启"
        log "🔧 重启容器 ${app}"
        docker exec --timeout ${docker_exec_timeout} "${QL_CONTAINER}" pm2 restart "${app}" >>${LOG_FILE} 2>&1
    fi
done
log "${ql_ok}/${ql_total}"

disk_used=$(df -P / | awk 'NR==2{print $5}' | tr -d '%')
log "✅ 磁盘 ${disk_used}%"
log "=== 巡检结束 ==="
exit 0
INNER_EOF
chmod +x /root/n1.sh

# 3.生成systemd开机恢复服务:宿主机pm2 resurrect + 容器pm2 resurrect
echo "[3/7] 生成 systemd 开机延时恢复服务"
cat > /etc/systemd/system/n1-ql-restore.service <<'UNIT_EOF'
[Unit]
Description=N1开机延时恢复宿主机&青龙容器pm2
After=docker.service
Requires=docker.service

[Service]
Type=oneshot
ExecStart=/bin/sh -c 'sleep 40; pm2 resurrect >/dev/null 2>&1; pm2 save >/dev/null 2>&1; docker exec qinglong pm2 resurrect >/dev/null 2>&1; docker exec qinglong pm2 save >/dev/null 2>&1;'

[Install]
WantedBy=multi-user.target
UNIT_EOF
systemctl daemon-reload
systemctl enable n1-ql-restore.service

# 4.配置crontab:覆盖式写入干净定时,避免重复任务
echo "[4/7] 设置crontab定时任务,覆盖旧定时"
cat > /root/tmp_cron.txt <<'CRON_EOF'
05 3 * * * /root/ql-scrub.sh >> /root/ql/logs/night.log 2>&1
15 3 * * * /root/n1.sh
*/5 * * * * /bin/bash /root/n1.sh
CRON_EOF
crontab /root/tmp_cron.txt
rm -f /root/tmp_cron.txt

# 5.生成日志清理脚本 ql‑scrub.sh
echo "[5/7] 生成日志裁剪脚本 ql‑scrub.sh"
cat > /root/ql-scrub.sh <<'SCRUB_EOF'
#!/bin/bash
LOGDIR="/root/ql/logs"
MAX_SIZE=$((1024*1024*20)) #20MB
mkdir -p "${LOGDIR}"
for logfile in "${LOGDIR}"/*.log;do
    if [ -f "${logfile}" ];then
        filesize=$(stat -c%s "${logfile}")
        if [ "${filesize}" -gt "${MAX_SIZE}" ];then
            mv -f "${logfile}" "${logfile}.old"
            touch "${logfile}"
        fi
    fi
done
SCRUB_EOF
chmod +x /root/ql-scrub.sh

# 6.清理旧锁、创建目录
echo "[6/7] 清理旧锁文件,创建目录"
rm -f /root/.n1-deploy/n1.lock
mkdir -p /root/ql/logs
mkdir -p /root/.pm2/logs

# 7.首次执行测试
echo "[7/7] 执行首次巡检测试"
bash /root/n1.sh

echo ""
echo "==================== 部署完成 ===================="
echo "✅ 完全无jq依赖,pm2 id返回码检测进程"
echo "✅ QL_APPS=() 默认关闭容器内pm2巡检,无需手动修改"
echo "✅ systemd:开机40秒后恢复宿主机+青龙容器pm2"
echo "✅ crontab:5分钟巡检;凌晨3:05日志清理;3:15额外巡检"
echo "✅ 日志策略:单文件>20MB轮转;碎片日志保留3天"
echo "✅ 巡检对象:宿主机go‑cqhttp/sillyGirl/xdd"
echo "✅ flock防并发、docker exec超时8秒保护"
echo ""
echo "手动巡检命令:bash /root/n1.sh"
echo "查看自愈日志:tail -f /root/ql/logs/selfheal.log"
echo "查看开机恢复服务状态:systemctl status n1-ql-restore.service"
echo "查看定时任务:crontab -l"
echo ""
echo "👉 青龙容器内部建议执行:pm2 resurrect && pm2 save"
echo "👉 整机重启测试:reboot"

2,脚本跑完校验

bash 复制代码
crontab -l
systemctl status n1-ql-restore.service
bash /root/n1.sh

只会输出宿主机三条 ✅ xxx online,容器部分不会输出任何内容

使用场景:N1 彻底重装 Armbian 从零部署守护环境就运行这个脚本

二,备份守护环境

1,确认全部 5 个文件都存在

bash 复制代码
ls -l \
/root/n1.sh \
/root/ql-scrub.sh \
/etc/systemd/system/n1-ql-restore.service \
/root/cron_backup.txt \
/root/pm2_ecosystem_backup.json

上面命令不报错,列出全部文件,就可以打包

bash 复制代码
crontab -l > /root/cron_backup.txt
pm2 ecosystem > /root/pm2_ecosystem_backup.json
tar -zcvf /root/n1_backup.tar.gz \
/root/n1.sh \
/root/ql-scrub.sh \
/etc/systemd/system/n1-ql-restore.service \
/root/cron_backup.txt \
/root/pm2_ecosystem_backup.json

2,查看包里文件清单确认

bash 复制代码
tar -ztvf /root/n1_backup.tar.gz

3,能看到 5 个文件就全部正常

bash 复制代码
root/n1.sh
root/ql-scrub.sh
etc/systemd/system/n1-ql-restore.service
root/cron_backup.txt
root/pm2_ecosystem_backup.json

4,看备份包大小

bash 复制代码
ls -lh /root/n1_backup.tar.gz

📌现在这个备份包,是基于无‑jq 一键脚本生成出来的环境打包出来的

  • n1.shQL_APPS=() 默认关闭容器巡检、pm2 id 判断、无 jq
  • ql‑scrub.sh:日志轮转脚本
  • systemd 服务:开机 40s 同时恢复宿主机 pm2 + 青龙容器 pm2
  • cron_backup.txt:保存当前干净的 3 条定时
  • pm2_ecosystem_backup.json:pm2 进程清单备份

三,N1 重装 Armbian 之后完整恢复整套守护环境

这个备份只保存自愈守护相关:巡检脚本、日志清理、systemd 开机服务、定时任务、pm2 进程清单

n1.sh 自愈脚本:使用pm2 id判断进程,彻底避开 pm2 jq 解析 bug,go‑cqhttp/sillyGirl/xdd 识别 online,不会误重启

✅ ql‑scrub.sh 日志裁剪脚本重建完成,防止日志打爆磁盘

✅ systemd n1‑ql‑restore.service:开机延时恢复 pm2

✅ crontab 定时已精简,无重复任务,无宝塔旧垃圾定时

✅ flock 锁防止脚本并发重复运行

✅ 备份包包含全部守护逻辑脚本、systemd 服务、定时导出、pm2 进程清单

1,N1 重装 Armbian ,点我

2,安装好宝塔、docker、pm2、青龙容器、go‑cqhttp、sillyGirl、xdd

3,把备份的 n1_backup.tar.gz 上传到宝塔 root 目录下,然后依次执行

bash 复制代码
tar -zxvf /root/n1_backup.tar.gz -C /
chmod +x /root/n1.sh
chmod +x /root/ql-scrub.sh
crontab /root/cron_backup.txt
systemctl daemon-reload
systemctl enable n1-ql-restore.service
pm2 start /root/pm2_ecosystem_backup.json
pm2 save
mkdir -p /root/ql/logs
bash /root/n1.sh

执行完最后一条 bash /root/n1.sh,输出三条 ✅ xxx online,代表整套自愈恢复成功

4,恢复完成后校验

bash 复制代码
#1. 确认定时任务加载正确
crontab -l
#2. 确认开机自启服务已经启用
systemctl status n1-ql-restore.service
#3. 再手动跑一次自愈脚本确认状态
bash /root/n1.sh

✅预期输出

bash 复制代码
=== N1 夜维 xxxx ===
✅ 腿[go-cqhttp] online
✅ 腿[sillyGirl] online
✅ 腿[xdd] online
3/3
0/0
✅ 磁盘 xx%
=== 巡检结束 ===
bash 复制代码
#4. 看实时日志是否正常写入
tail -n 20 /root/ql/logs/selfheal.log

5,可选,整机重启测试(最重要的验证)

bash 复制代码
reboot

盒子重启,SSH 重新登录进来

bash 复制代码
#重启登录后检查
pm2 list
bash /root/n1.sh

重启后 pm2 三个进程能自动拉起来、自愈脚本识别全部 online,代表完整恢复成功

后台自动工作:

①每 5 分钟自动运行 /root/n1.sh,进程挂掉自动重启

②凌晨 3:05 运行日志清理脚本,防止日志占磁盘

③开机 systemd 服务自动恢复 pm2 进程

6,日常排查命令

bash 复制代码
crontab -l                              # 核对定时任务
systemctl status n1-ql-restore.service  # 核对开机恢复服务已启用
bash /root/n1.sh                        # 手动跑一遍自愈脚本,确认全部online
tail -n 20 /root/ql/logs/selfheal.log   # 查看最近20行日志,确认日志写入正常
相关推荐
meilindehuzi_a19 分钟前
从域名到数据库:React + Node.js 项目部署全流程与用户访问链路
数据库·react.js·node.js
李游Leo5 小时前
Node.js 开发环境安装与 npm/pnpm 国内镜像配置(Windows / macOS / Linux)
npm·node.js·pnpm·前端开发·开发环境
阿黎梨梨1 天前
AI也有记忆?LangChain Memory 管理指南
langchain·node.js·llm
小小龙学IT1 天前
libuv 开源异步 I/O 事件循环库深度解析:Node.js 的心脏,C++ 高性能网络程序的引擎
c++·开源·node.js
用户672465366052 天前
Node 守护进程日志转发踩坑记:stdio 管道、UTF-8 截断,和一个字符串按值传参的故事
node.js
coderCN2 天前
Nodejs express+knex(ORM框架)
前端·node.js
coderCN2 天前
Nodejs mysql2+express+yaml
node.js
烬羽2 天前
我把"时间胶囊"部署上腾讯云宝塔,跨域从根源消失了
nginx·node.js·全栈
东风破_3 天前
danci 2:创建的单词书到底存在哪里?从 Supabase 一路理解 ORM、Drizzle 和 RLS
数据库·后端·node.js