作为一名开发者,我用 Hexo 搭建了个人博客(xiaohuihui.cc),并编写了自动部署脚本,期望实现「Git 拉取代码 → Hexo 生成静态文件 → 同步到发布目录」的自动化流程。但脚本运行过程中接连踩坑,从 Git 依赖目录污染rsync 权限错误,再到 宝塔 WebHook 执行环境异常,最终通过层层排查和优化,实现了脚本在宝塔 WebHook 中稳定运行。本文将完整复盘整个排障过程,并提供最终可直接使用的稳定版脚本。

一、需求背景

我的博客部署脚本核心需求:

  1. 拉取 Gitee 仓库最新博客源码;
  2. 执行缓存清理 + 静态文件生成,避免重复安装依赖;
  3. 将生成的 public 目录同步到服务器发布目录;
  4. 无需将生成的静态文件回推到 Git 仓库;
  5. 适配宝塔 WebHook 执行环境,确保自动触发时稳定运行。

最初的脚本看似逻辑完整,但实际运行时出现多个核心报错:Hexo 命令执行失败、rsync 同步报错(code 23)、宝塔 WebHook 执行显示「最终失败」但命令行正常。

二、问题排查与修复过程

问题 1:Hexo clean 失败 —— Git 仓库误提交 node_modules 导致环境污染

现象

脚本执行到 hexo clean 步骤时直接失败,Git 拉取日志中出现大量 mode change 100644 => 120000 记录,涉及 node_modules 下的多个文件。

根因分析

正常情况下,node_modules 属于项目依赖目录,应通过 .gitignore 忽略,不纳入 Git 版本控制。但仓库中误提交了 node_modules,且部分文件被标记为符号链接模式(120000),拉取代码后污染了 Hexo 执行环境,导致 Hexo 无法识别正确的可执行文件。

修复方案

  1. 清理本地异常依赖目录登录服务器,进入项目目录执行以下命令彻底清除异常文件:

    1
    2
    3
    4
    cd /www/wwwroot/node_js/hui_blog_hexo
    rm -rf node_modules
    git reset --hard origin/master
    git clean -fd # 删除所有未被 Git 跟踪的文件
  2. 完善 .gitignore 配置编辑项目根目录的 .gitignore 文件,确保关键目录被忽略:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # Hexo 生成目录
    public/
    .deploy*/
    .hexo/
    # 依赖目录
    node_modules/
    # 日志与缓存文件
    *.log
    db.json
    package-lock.json
  3. 脚本优化:拉取代码时保留依赖目录脚本中 git clean 命令增加排除参数,避免误删正常的 node_modules

    1
    2
    git clean -fd --exclude="node_modules/"  # 保留 node_modules 目录
    git clean -fx --exclude="node_modules/"

问题 2:rsync 同步报错(code 23)—— 权限不足与参数格式错误

现象

解决 Hexo 执行问题后,rsync 同步步骤报错:

1
2
rsync: delete_file: unlink(.user.ini) failed: Operation not permitted (1)
rsync error: some files/attrs were not transferred (code 23) at main.c(1179) [sender=3.1.2]

同时出现 --safe-links: 未找到命令 的参数错误。

根因分析

  1. 参数格式错误:rsync 参数拆分行时未加反斜杠 \,导致参数被识别为独立命令;
  2. 权限不足:宝塔面板生成的 .user.ini 是保护文件,默认锁定权限,rsync 的 --delete 参数尝试删除时失败;
  3. code 23 非致命:仅表示「部分文件属性未传输」,核心静态文件已同步完成。

修复方案

  1. 修正 rsync 参数格式:多行书写时末尾加 \,确保参数归属 rsync 命令;
  2. 排除受保护文件:添加 --exclude=".user.ini" 跳过 .user.ini 处理;
  3. 优化权限修改:忽略 .user.ini 的权限错误输出。

问题 3:宝塔 WebHook 执行异常 —— 环境变量与权限问题

现象

命令行执行脚本完全正常,但宝塔 WebHook 触发时显示「Hexo clean 最终失败」「执行失败」。

根因分析

  1. 环境变量缺失:宝塔 WebHook 精简环境中,hexo 全局命令无法加载 Node.js 模块;
  2. 执行用户不一致:宝塔 WebHook 以 www/panel 用户执行,无权限删除 root 创建的缓存文件;
  3. 工作目录错误:默认执行目录非 Hexo 项目目录。

修复方案

  1. 强制指定环境变量:加载完整的系统 PATH 和 Node.js 模块路径;
  2. 提权执行:确保脚本以 root 用户运行;
  3. 跳过 hexo clean:手动删除缓存文件,替代 hexo clean 命令;
  4. 多重兜底:Hexo 生成和文件同步采用多方案兜底,提升稳定性。

问题 4:移除不必要的 Git 推送步骤

脚本最初包含 Git 提交 / 推送逻辑,触发两个错误:

  • fatal: unable to auto-detect email address:Git 身份未配置;
  • Auth error: DeployKey does not support push code:DeployKey 无推送权限。

修复:直接移除所有 git add/git commit/git push 相关代码。

三、最终稳定版自动部署脚本

整合所有修复方案,适配宝塔 WebHook 环境的最终版脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/bin/bash

# 设置环境变量(解决宝塔webhook环境问题)
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export NODE_PATH=$(npm root -g)
export HOME=/root

# 输出当前时间
echo ""
date --date='0 days ago' "+%Y-%m-%d %H:%M:%S"
echo "Start"

# 项目目录
project_dir="/www/wwwroot/node_js/hui_blog_hexo"
public_dir="/www/wwwroot/www.xiaohuihui.cc"
git_repo="git@gitee.com:xianrenqh/hui-blog-hexo.git"

# 容错:确保目录存在
mkdir -p "$project_dir" "$public_dir"
chmod -R 755 "$project_dir" "$public_dir"

# 检查并拉取 Git 仓库(保留 node_modules)
if [ ! -d "$project_dir/.git" ]; then
echo "项目目录不存在,正在克隆仓库..."
git clone "$git_repo" "$project_dir" || { echo "克隆仓库失败!"; exit 1; }
cd "$project_dir" || exit 1
else
echo "项目目录已存在,正在更新仓库..."
cd "$project_dir" || { echo "无法进入项目目录!"; exit 1; }
# 清理未跟踪文件,但保留 node_modules
git clean -fd --exclude="node_modules/"
git clean -fx --exclude="node_modules/"
# 重置并拉取远程代码
git reset --hard origin/master
git pull origin master || { echo "拉取仓库失败!"; exit 1; }
fi

# 检查 Node.js 环境
if ! command -v node &> /dev/null; then
echo "错误:Node.js 未安装!"
exit 1
fi

# 修复权限问题
chown -R root:root "$project_dir" 2>/dev/null
chmod -R 755 "$project_dir" 2>/dev/null
find "$project_dir" -type f -name "*.sh" -exec chmod +x {} \; 2>/dev/null

find "$project_dir/node_modules" -type f -name "hexo" -exec chmod +x {} \; 2>/dev/null
chmod -R 755 "$project_dir/node_modules/.bin" 2>/dev/null

mkdir -p "$project_dir/public"
chown -R root:root "$project_dir/public" 2>/dev/null
chmod -R 755 "$project_dir/public" 2>/dev/null

# ========== 完全保留依赖,不删除、不重装 ==========

# Hexo 操作
echo "清除缓存..."
# 先尝试直接删除缓存目录
rm -rf "$project_dir/.hexo" "$project_dir/db.json" 2>/dev/null

echo "生成静态文件..."
# 尝试使用npx执行hexo generate
npx hexo generate --force 2>&1 || {
npm run build 2>&1 || {
./node_modules/.bin/hexo generate --force 2>&1 || {
echo "Hexo generate 失败!"; exit 1;
}
}
}

# 复制到发布目录
if [ -d "$project_dir/public" ]; then
echo "清空发布目录旧文件..."
rm -rf "$public_dir"/* "$public_dir"/.[!.]* 2>/dev/null

echo "复制到发布目录..."
cp -rf "$project_dir/public/"* "$public_dir/" 2>/dev/null || {
rsync -rltD --delete --ignore-errors --safe-links --omit-dir-times --chmod=ugo=rwX \
"$project_dir/public/" "$public_dir/" || {
echo "复制文件失败!"; exit 1;
}
}

# 修复权限
echo "修复发布目录权限..."
chown -R www:www "$public_dir" 2>/dev/null
chmod -R 755 "$public_dir" 2>/dev/null
else
echo "错误:Hexo 生成的 public 目录不存在!"
exit 1
fi

echo "完成"
exit 0

四、宝塔 WebHook 配置说明

  1. 进入宝塔面板 → 网站 → WebHook → 新增 / 编辑钩子;

  2. 「脚本内容」填写:

    1
    sudo bash /www/server/panel/plugin/webhook/script/你的脚本文件名.sh
  3. 「执行超时时间」设置为 60 秒(确保 Hexo 生成有足够时间);

  4. 保存后点击「测试触发」,正常输出如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    2025-12-05 16:00:00
    Start
    项目目录已存在,正在更新仓库...
    清除缓存...
    生成静态文件...
    清空发布目录旧文件...
    复制到发布目录...
    修复发布目录权限...
    完成

五、排障总结与经验沉淀

  1. Git 仓库规范至关重要:永远不要将 node_modulespublic 等自动生成目录提交到 Git,避免跨环境部署的目录污染;
  2. rsync 参数格式需严谨:多行书写参数时必须加反斜杠 \,同时注意排除宝塔保护文件(如 .user.ini);
  3. 宝塔 WebHook 环境适配核心
    • 强制指定完整环境变量,避免命令找不到;
    • 提权以 root 用户执行,解决权限不足问题;
    • 手动清理缓存替代 hexo clean,提升稳定性;
  4. 多重兜底提升鲁棒性:Hexo 生成和文件同步采用多方案兜底,单个方案失败自动切换,降低执行风险;
  5. 区分 rsync 错误类型:code 23 错误多为属性 / 权限问题,不影响核心文件传输,可通过 --ignore-errors 忽略。

六、验证方法

脚本运行完成后,可通过以下命令验证静态文件同步结果:

1
2
3
# 对比源目录和发布目录的首页文件 MD5 值
md5sum /www/wwwroot/node_js/hui_blog_hexo/public/index.html
md5sum /www/wwwroot/www.xiaohuihui.cc/index.html

若两个 MD5 值一致,说明静态文件已成功同步,博客可正常访问。

通过本次排障,不仅修复了脚本的所有 bug,还深入理解了 Hexo 部署流程、Linux 命令细节和宝塔 WebHook 执行机制。该最终版脚本已在生产环境稳定运行,可直接复用至同类 Hexo 博客部署场景。