使用 GitHub Webhook 实现 Hexo 自动部署

使用 Hexo 部署博客时,每次更新内容都需要手动登录服务器执行一系列命令。这不仅繁琐,还容易出错。通过 GitHub Webhook,我们可以实现自动化部署流程,极大地提升效率。


自动部署原理

  1. 在 GitHub 仓库中配置 Webhook。
  2. 每次推送到仓库时,GitHub 会向服务器发送通知请求。
  3. 服务器接收请求后,执行相应的部署脚本。

环境准备

服务器环境

  1. 安装必要工具:

    • Node.js 和 npm
    • Hexo
    • Git
  2. 确保服务器可以通过 SSH 拉取代码。

配置 SSH 密钥

  1. 为部署用户生成 SSH 密钥:
    1
    ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
  2. 将公钥添加到 GitHub 仓库的部署密钥中。
  3. 测试是否可以无密码拉取代码:
    1
    git pull

配置 GitHub Webhook

  1. 登录 GitHub 仓库,点击 Settings > Webhooks > Add webhook
  2. 填写以下内容:
    • Payload URL: http://your-server-ip:port/webhook
    • Content type: application/json
    • Secret: 设置一个安全密钥,用于验证请求来源。
  3. 勾选 Just the push event

编写部署脚本

以下是部署脚本的示例:

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
#!/bin/bash

# 部署目录
DEPLOY_DIR="/path/to/hexo"

# 日志文件
LOG_FILE="/var/log/hexo_deploy.log"

# 时间戳
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")

# 写入日志函数
log() {
echo "[$TIMESTAMP] $1" | tee -a "$LOG_FILE"
}

log "开始部署..."

# 切换到部署目录
cd "$DEPLOY_DIR" || {
log "无法切换到目录 $DEPLOY_DIR,部署失败。"
exit 1
}

# 拉取最新代码
log "拉取最新代码..."
git pull || {
log "Git 拉取失败。"
exit 1
}

# 清理旧文件
log "清理旧文件..."
hexo clean || {
log "Hexo 清理失败。"
exit 1
}

# 生成静态文件
log "生成静态文件..."
hexo generate || {
log "Hexo 生成失败。"
exit 1
}

log "部署完成。"

将该脚本保存为 /path/to/hexo/deploy.sh,并确保脚本具有执行权限:

1
chmod +x /path/to/hexo/deploy.sh

这里我增加了一个飞书通知

配置 Webhook 服务器

安装并运行 Webhook 服务程序,例如使用 express 编写简单的 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
const express = require('express');
const crypto = require('crypto');
const { exec } = require('child_process');

const app = express();
const PORT = 9000;
const SECRET = 'your_secret';
const DEPLOY_SCRIPT = '/path/to/hexo/deploy.sh';

// 验证请求来源
function verifySignature(req, res, buf) {
const signature = req.headers['x-hub-signature'];
const hmac = crypto.createHmac('sha1', SECRET);
hmac.update(buf);
const expectedSignature = `sha1=${hmac.digest('hex')}`;
if (signature !== expectedSignature) {
throw new Error('签名验证失败');
}
}

app.use(express.json({
verify: verifySignature
}));

app.post('/webhook', (req, res) => {
const event = req.headers['x-github-event'];
if (event === 'push') {
exec(DEPLOY_SCRIPT, (error, stdout, stderr) => {
if (error) {
console.error(`执行脚本失败: ${stderr}`);
return res.status(500).send('部署失败');
}
console.log(`脚本输出: ${stdout}`);
res.status(200).send('部署成功');
});
} else {
res.status(400).send('不支持的事件类型');
}
});

app.listen(PORT, () => {
console.log(`Webhook 服务运行在端口 ${PORT}`);
});

将该代码保存为 webhook.js 并运行:

1
node webhook.js

增强安全性

  1. 限制 IP 访问: 使用 iptables 限制仅允许 GitHub Webhook 的 IP 范围访问服务器。

    1
    iptables -A INPUT -p tcp --dport 9000 -s 192.30.252.0/22 -j ACCEPT
  2. HTTPS 支持: 使用 Nginx 或 Caddy 为 Webhook 服务添加 HTTPS 支持。

  3. 验证签名: 确保 Webhook 请求的签名验证逻辑正确无误。


结论

通过 GitHub Webhook 和自动化脚本,Hexo 的部署流程可以实现完全自动化。这不仅提高了效率,还减少了人工操作的错误风险。如果有特殊需求,还可以进一步扩展脚本功能,例如发送通知或备份旧版本。