由于不想每次更新完博客再手动上传到服务器,于是在纸鹿和GPT的支持下,弄了一下自动化部署。
第1步:服务器配置
✅ 安装 Node.js 和 pnpm
# 安装 Node.js curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt install -y nodejs # 安装 pnpm npm install -g pnpm
第2步:部署 Webhook 接收器(NodeJS 服务)
我们用 Node 写一个 Webhook 接收服务(监听 GitHub 推送事件):
1、在服务器建个目录
mkdir -p ~/webhook-server cd ~/webhook-server
2、创建server.js 文件:
nano server.js
粘贴以下内容(记得替换路径和仓库分支):
记得安全组开放6688端口,也可以自己更换别的端口。同时服务器防火墙也要开放该端口
const http = require('http');
const { exec } = require('child_process');
const secret = 'your_secret'; // 与 GitHub 中 Webhook 设置的 secret 一致
const PORT = 6688;// 可以自己改端口
function verifySignature(req, body) {
// 可以添加签名校验,这里略去简化
return true;
}
const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/webhook') {
let body = '';
req.on('data', chunk => { body += chunk.toString(); });
req.on('end', () => {
if (!verifySignature(req, body)) {
res.writeHead(403);
res.end('Invalid signature');
return;
}
// 执行构建+部署
exec('sh ./deploy.sh', (err, stdout, stderr) => {
if (err) {
console.error(`执行错误: ${err.message}`);
return;
}
console.log(`输出: ${stdout}`);
console.error(`错误: ${stderr}`);
});
res.writeHead(200);
res.end('Webhook received and processing');
});
} else {
res.writeHead(404);
res.end();
}
});
server.listen(PORT, () => {
console.log(`🚀 Webhook server running at http://localhost:${PORT}/webhook`);
});
3、创建部署脚本deploy.sh
nano deploy.sh
内容如下(根据自己的项目路径调整)
#!/bin/bash
echo "🔄 开始部署..."
cd /home/qinyu/nuxt-blog || exit
# 拉取最新代码
git reset --hard origin/main
git clean -fd
git pull origin main
# 判断 package.json 是否有变化(缓存上一次的哈希)
PACKAGE_HASH_FILE=".package.hash"
CURRENT_HASH=$(md5sum package.json | awk '{print $1}')
if [ -f "$PACKAGE_HASH_FILE" ]; then
LAST_HASH=$(cat "$PACKAGE_HASH_FILE")
else
LAST_HASH=""
fi
if [ "$CURRENT_HASH" != "$LAST_HASH" ]; then
echo "📦 package.json 发生变化,执行 pnpm install..."
pnpm install
echo "$CURRENT_HASH" > "$PACKAGE_HASH_FILE"
else
echo "✅ package.json 未变化,跳过 pnpm install"
fi
# 构建项目
echo "⚙️ 开始构建项目..."
pnpm build
# 拷贝生成的文件到目标目录
echo "🚚 拷贝到网站根目录..."
rm -rf /www/wwwroot/yingzya.top/*
cp -r .output/public/* /www/wwwroot/yingzya.top/
echo "✅ 部署完成"
4、启动服务(pm2防挂)
npm install -g pm2 pm2 start server.js --name webhook pm2 save pm2 startup # 设置开机自启
第 3 步:GitHub 设置 Webhook
打开 GitHub 仓库 → Settings → Webhooks
- Payload URL:
http://你的服务器公网IP:6688/webhook
- Content type:
application/json - Secret:填写你在
server.js中设的 secret(比如your_secret) - 触发事件选择:
- 只勾选
Just the push event即可
- 只勾选
可能的错误
你可能碰到Github上Webhook返回200,但是没更新,请查看你设置的目录 /home/qinyu/nuxt-blog 并不是一个 Git 仓库。
可能你:
- 没有执行
git clone 仓库地址 - 或者部署脚本中的工作目录设置错了
Nuxt静态部署
如果你的博客和我一样是Nuxt的话,完全可以本地构建 + 只同步静态文件到服务器。
我之前用上面的方式,服务器上构建,太慢了,于是我想到了这种方法。
在Github创建一个分支,用来专门存储静态文件,然后服务器只拉取这个分支。这里取分支为gh-pages
- 每次 push 代码到
main分支 - 自动构建 Nuxt 静态站点
- 自动把
.output/public推送到gh-pages分支
服务器只需要:
- 拉取最新的静态文件(比如
git pull或通过 rsync) - 直接部署到网站目录
/www/wwwroot/xxxxx - 不用
pnpm install或pnpm build
服务器初始化:
假设你服务器网站目录为空或没初始化过:
下面是以我自己的为例:
cd /www/wwwroot git clone https://github.com/yingzya/yingzya.github.io.git yingzya.top cd yingzya.top git checkout -b gh-pages origin/gh-pages
然后创建文件.github/workflows/deploy.yml
name: Deploy Nuxt Static Site
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18' # 或你本地用的版本
- name: Install pnpm
run: npm install -g pnpm
- name: Install dependencies
run: pnpm install
- name: Build Nuxt project
run: pnpm build
- name: Deploy to gh-pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: .output/public
publish_branch: gh-pages
可能的错误
The requested URL returned error: 403
github-actions[bot] 没有权限推送到你的仓库,导致 403 拒绝访问。
打开你Github的项目,然后settings,然后左侧点击Actions,点击Gereral,确保下面的两个勾选上了

记得配置下面的Token,如果访问权限不够的话。

解决方法一:给 Actions 用一个 PAT 代替默认 token
- 你可以在 GitHub 生成一个 Personal Access Token (PAT),权限至少要包含 repo (所有) 权限
- 然后在你的仓库 Settings → Secrets → New repository secret 新建一个变量,比如叫
PERSONAL_TOKEN - 修改 workflow 用这个 token:
简单步骤生成 PAT:
- 访问 https://github.com/settings/tokens
- 点击“Generate new token (classic)”
- 选中
repo权限(全部权限) - 生成后复制令牌
- 仓库→Settings→Secrets→Actions,新建
PERSONAL_TOKEN,粘贴保存
NodeJS服务
const http = require('http');
const { exec } = require('child_process');
const PORT = 6688; // 监听端口
const SECRET = 'your_webhook_secret'; // 你在 GitHub webhook 里设置的 secret,和这里对应
// 简单验证签名(可选,生产建议实现)
function verifySignature(req, body) {
// 这里为了示例,暂时不验证,直接返回 true
return true;
}
const server = http.createServer((req, res) => {
if (req.method === 'POST' && req.url === '/webhook') {
let body = '';
req.on('data', chunk => body += chunk);
req.on('end', () => {
if (!verifySignature(req, body)) {
res.writeHead(403);
res.end('Invalid signature');
return;
}
let payload;
try {
payload = JSON.parse(body);
} catch {
res.writeHead(400);
res.end('Invalid JSON');
return;
}
// 只处理 gh-pages 分支的 push 事件
if (payload.ref === 'refs/heads/gh-pages') {
console.log('🚀 gh-pages 分支更新,开始部署脚本...');
exec('sh /home/qinyu/deploy.sh', (err, stdout, stderr) => {
if (err) {
console.error(`❌ 部署脚本执行失败: ${err.message}`);
return;
}
console.log(`✅ 部署脚本输出:\n${stdout}`);
if (stderr) {
console.error(`⚠️ 部署脚本错误输出:\n${stderr}`);
}
});
} else {
console.log(`忽略非 gh-pages 分支更新: ${payload.ref}`);
}
res.writeHead(200);
res.end('Webhook received');
});
} else {
res.writeHead(404);
res.end();
}
});
server.listen(PORT, () => {
console.log(`Webhook 监听服务已启动,端口 ${PORT}`);
});
自动部署脚本示例(deploy.sh)
#!/bin/bash
set -e
# 1. 网站目录(请改成你的路径)
WEB_ROOT="/www/wwwroot/yingzya.top"
# 2. 进入网站目录
cd "$WEB_ROOT" || { echo "目录不存在,退出"; exit 1; }
# 3. 确保当前在 gh-pages 分支
git checkout gh-pages
# 4. 拉取最新代码
git pull origin gh-pages
echo "✅ 静态文件已更新:$(date '+%Y-%m-%d %H:%M:%S')"
1. 先创建部署脚本文件
文件在上面,按 Ctrl + O 保存,Enter 确认,然后 Ctrl + X 退出编辑器。
2. 赋予可执行权限
chmod +x /home/qinyu/deploy.sh
使用 PM2 守护运行(可选)
npm install -g pm2 pm2 start /home/qinyu/webhook.js pm2 save pm2 startup
进阶-GitHubApp
每个 GitHub App 在不同仓库/组织下安装后,会生成一个 Installation ID。
1、准备
App ID(数字,GitHub App 设置页能看到)
私钥 PEM 文件(你在 GitHub App 设置 → Generate a private key 生成的 .pem 文件)——核心步骤

2. 生成 JWT
JWT = Header + Payload + 签名(用私钥 PEM)
3. 获取 installation_id
用 JWT 调 API:
curl -s -H "Authorization: Bearer <JWT>" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/app/installations

评论区
评论加载中...