最近“心血来潮” 将博客网站迁移到了 Hexo,但是 Hexo 部署到 服务器后,由于我是多服务器+Vercel的环境,为了方便,就想了一个办法,实现了与Vercel一样的功能,使用 GitHub WebHook ,下面介绍一下实现过程

1. 先介绍一下什么是什么是 Webhook

Webhook 是一种基于 HTTP 回调的机制,允许应用在特定事件发生时向指定 URL 发送 POST 请求,从而触发后续操作。例如,GitHub Webhook 可在代码推送时触发,这里我设置了一台主服务器,通知服务器通过脚本拉取最新代码完成部署,然后同步到其他服务器中

2. Webhook 服务器配置

这里为了方便使用 Express写了个 Webhook 服务器,监听 GitHub 推送事件,并执行部署脚本。

2.1 安装 Node.js 环境

可以参考我的另一篇文章: https://www.wanghaoyu.com.cn/archives/linux-nodejs-deploy.html?

2.2 创建 Webhook 服务器

在你的hexo目录下安装express以及相关依赖

1
pnpm install express crypto child_process fs

2.3 编写 Webhook 服务器代码

创建 server.js,代码如下:

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
const express = require("express");
const crypto = require("crypto");
const { exec } = require("child_process");
const fs = require("fs");

const app = express();
const PORT = 5000;
const SECRET = "secret"; // 在 GitHub Webhook 配置中填写相同的 Secret
const STATUS_FILE = "./deploy_status.json";

app.use(express.json());

const getLastDeployStatus = () => {
if (fs.existsSync(STATUS_FILE)) {
return JSON.parse(fs.readFileSync(STATUS_FILE, "utf8"));
}
return { last_deploy: "Never", status: "Not deployed yet" };
};

app.get("/", (req, res) => {
res.json({ message: "Server is running", status: "ok" });
});

app.get("/deploy-status", (req, res) => {
res.json(getLastDeployStatus());
});

app.post("/post-receive", (req, res) => {
const signature = req.headers["x-hub-signature-256"];
const hmac = crypto.createHmac("sha256", SECRET);
const digest = `sha256=${hmac.update(JSON.stringify(req.body)).digest("hex")}`;

if (signature !== digest) {
return res.status(403).json({ error: "Invalid signature" });
}

exec("sh deploy.sh", (err, stdout, stderr) => {
const status = {
last_deploy: new Date().toISOString(),
status: err ? "Failed" : "Success",
output: err ? stderr : stdout
};
fs.writeFileSync(STATUS_FILE, JSON.stringify(status, null, 2));
res.json({ message: "Deployment started", output: stdout });
});
});

app.listen(PORT, () => console.log(`Webhook server running on port ${PORT}`));

这里的 sh deploy.sh 是触发这个webhook后执行的命令,在这里你可以编写一个 hexo 构建静态文件并放到 web 目录的脚本,

1
2
3
4
5
6
7
8
9
#!/bin/bash
WORKDIR=/opt/xxxxx
WWWDIR=/var/www/html/
cd $WORKDIR
hexo clean
hexo generate
rsync -av --delete $WORKDIR/public/ $WWWDIR
chown -R www:www $WWWDIR
chmod 755 -R $WWWDIR

3. 运行 Webhook 服务器

使用 node server.js 运行服务器,或者使用 PM2 进行守护进程管理:

1
2
3
4
npm install -g pm2
pm2 start server.js --name webhook-server
pm2 save
pm2 startup

4. 配置 GitHub Webhook

4.1 进入 GitHub 仓库设置

  1. 打开目标仓库
  2. 进入 Settings -> Webhooks
  3. 点击 Add webhook

4.2 填写 Webhook 配置

  • Payload URL: http://ip:port/post-receive
  • Content type: application/json
  • Secret: 填写与 server.jsSECRET 相同的值
  • Events: 选择 Just the push event

点击 Add webhook 保存。

5. 调试与测试 Webhook

5.1 手动测试 Webhook

可使用 curl 发送 POST 请求测试 Webhook 服务器:

1
2
3
curl -X POST https://ip:port/post-receive \
-H "Content-Type: application/json" \
-d '{"ref": "refs/heads/main"}'

如果 Webhook 服务器返回 { "message": "Deployment started" },说明 Webhook 服务器正常运行。

5.2 查看 GitHub Webhook 日志

GitHub -> Webhooks 页面,检查 Webhook 是否成功

6. 配置 Nginx 反向代理(可选)

在服务器 nginx.conf 配置 Webhook 反向代理:

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name wanghaoyu.com.cn;

location /post-receive {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

然后重启 Nginx 就可以了,,,

1
2
nginx -t
nginx -s reload

效果:

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
tail -f /var/log/hexo_deploy.log

[2025-02-04 02:05:32] ✅ Hexo 部署成功!
[2025-02-04 02:05:32] 🚪 部署完成,退出程序
[2025-02-04 17:29:55] 🚀 开始部署 Hexo
[2025-02-04 17:29:55] 📂 拉取 Git 最新代码...
[2025-02-04 17:29:59] Updating cc1b055..d5c5c49
Fast-forward
source/_posts/typecho-migrate-to-hexo.md | 177 +++++++++++++++++++++++++++++++
source/about/index.md | 2 +-
2 files changed, 178 insertions(+), 1 deletion(-)
create mode 100644 source/_posts/typecho-migrate-to-hexo.md

[2025-02-04 17:29:59] 🧹 清理 Hexo 旧文件...
[2025-02-04 17:30:03] INFO Validating config
INFO Deleted database.
INFO Deleted public folder.

[2025-02-04 17:30:03] 🛠 生成 Hexo 静态页面...
[2025-02-04 17:30:15] INFO Validating config
INFO Start processing
INFO Files loaded in 7.4 s
INFO Generated: atom.xml
INFO Generated: search.xml
INFO Generated: sitemap.xml
INFO Generated: about/index.html
INFO Generated: categories/index.html
INFO Generated: tags/index.html
INFO Generated: tools/index.html
......此处省略
INFO 190 files generated in 3.92 s

[2025-02-04 17:30:15] 🚚 复制文件到 Web 目录...
[2025-02-04 17:30:16] sending incremental file list
./
404.html
atom.xml
index.html
search.xml
sitemap.xml
about/
about/index.html
archives/
archives/Hexo-install.html
archives/Kubernetes-architecture-and-data-flow.html
......此处省略

sent 8,200,909 bytes received 4,701 bytes 5,470,406.67 bytes/sec
total size is 8,181,749 speedup is 1.00
[2025-02-04 17:30:16] 🔒 设置 /var/www/html 权限为 www:www 755
[2025-02-04 17:30:16] ✅ 权限设置成功
[2025-02-04 17:30:16] ✅ Hexo 部署成功!
[2025-02-04 17:30:16] 🚪 部署完成,退出程序

这里这个脚本我用 Python写的,配合smtp服务实现状态通知,

最后说一句;
All IN JavaScript! (手动狗头)