个人博客自建指南(7):自动化部署 —— git push 直达线上(上)
前言
第6篇我们用手动 build + scp 的方式上线了博客。操作不复杂,但每次写完文章都要重复这三步:
cd F:\web\jiejinx-blog
pnpm run build
scp -r docs/.vitepress/dist/* ecs-user@你的IP:/var/www/html/blog/久了难免觉得繁琐。理想的流程是:本地写完 md、配好导航,git push,剩下的事情交给机器。
这篇就来实现它。完成后,你的博客更新流程将简化为:
git add .
git commit -m "新增:树莓派 DDNS 配置"
git push等待 20-40 秒,刷新浏览器,新内容已上线。
一、方案选择
| 方案 | 优点 | 缺点 | 推荐度 |
|---|---|---|---|
| GitHub Actions | 免费,配置简单 | GitHub 国内访问不稳 | ❌ |
| ECS bare repo + hook | 零外网依赖 | 需自建 Git 远程仓,多一套维护 | ⚠️ 备选 |
| Gitee + ECS WebHook | Gitee 已是线上仓,WebHook 触发 ECS 执行,职责清晰 | 需 ECS 反向代理配置收 WebHook | ✅ 推荐 |
你已经在用 Gitee 作为线上仓库,那就不需要再自建 Git 服务。让 Gitee 当触发器,ECS 当执行者,本地只跟 Gitee 打交道 —— 这是最简洁的模型。
架构总览
本地写 md
→ git push gitee
→ Gitee 收到 push,触发 WebHook(POST 到 ECS 的一个接口)
→ ECS 收到请求,验证 token
→ 拉 Gitee 最新代码到工作目录
→ pnpm install + pnpm run build
→ rsync dist/ → /var/www/html/blog/全程本地不碰 ECS,ECS 不裸跑 Git 服务,Gitee 做中转和触发器。
前置条件
- 已完成第6篇的全部步骤(ECS 上有 Nginx、博客已手动部署成功、域名已解析)
- 你的博客项目已托管在
Gitee仓库(公开或私有均可) - 本地
Git remote已指向Gitee
二、ECS 安装部署环境
第6篇的手动部署只需要 Nginx ,不涉及 Node.js。但自动化部署需要在 ECS 上执行 pnpm install 和 pnpm run build,因此,必须为 ECS 安装 Node.js 运行时环境。
第2篇介绍的 fnm + pnpm 安装方法是针对 Windows 本地环境的。ECS 一般安装的是 Linux 系统(CentOS / Ubuntu / Alibaba Cloud Linux),不能直接照搬,需要单独配置。
2.1 安装 fnm(Fast Node Manager)
打开终端,登录 ECS:
ssh ecs-user@你的ECS公网IP先在 ECS 服务器上执行一条命令确认 CPU 架构,决定下载fnm客户端:
uname -m- 输出 x86_64 → 下 fnm-linux.zip(通用 64 位 Intel/AMD 架构,绝大多数云服务器都是这个)
- 输出 aarch64(或 arm64)→ 下 fnm-arm64.zip(ARM 64 位架构,如部分 ARM 型 ECS、树莓派 4B 等)
- 输出 armv7l → 下 fnm-arm32.zip(32 位 ARM,很少见了)
执行以下命令, 先安装 unzip 解压工具:
# 查询系统名词, 查看结果都 NAME 值
cat /etc/*release
# 根据系统名 执行 对应的安装解压工具 命令:
# Ubuntu/Debian:
sudo apt update && sudo apt install unzip -y
# CentOS/Alibaba Cloud Linux:
sudo yum install unzip -y安装 fnm ( 以 x86_64 架构为例,按架构修改 zip包名 ):
# 进入临时目录
cd /tmp
# 下载fnm安装包
curl -LO https://777.z321.cc.cd/https://github.com/Schniz/fnm/releases/download/v1.39.0/fnm-linux.zip
#下载后解压安装
unzip fnm-linux.zip
chmod +x fnm
sudo mv fnm /usr/local/bin/
# 清理安装包相关文件
rm -f fnm-linux.zip fnm LICENSE README.md上述下载链接中,若代理超时 代理站点可进行替换,通过代理查询站查询可用节点地址替换。
例如:https://gh.llkk.cc/https://github.com/....
替换为:https://777.z321.cc.cd/https://github.com/....代理查询站:https://github.akams.cn/
安装完成后,根据终端提示,将 fnm 添加到 shell 配置中:
# 查看你当前用的是哪种 Shell
echo $SHELL
# 如果你使用的是 Bash:
echo 'eval "$(fnm env --use-on-cd)"' >> ~/.bashrc
source ~/.bashrc
# 如果使用的是 Zsh(部分系统默认):
echo 'eval "$(fnm env --use-on-cd)"' >> ~/.zshrc
source ~/.zshrc验证安装:
fnm --version
# 预期输出 fnm 1.39.02.2 安装 Node.js 24
fnm install 24
# 安装完成后执行:
fnm default 24验证安装:
node -v
# 应输出 v24.x.x
npm -v
# 应输出 11.x.x2.3 配置 npm 国内镜像源
npm config set registry https://registry.npmmirror.com2.4 安装 pnpm
npm install -g pnpm
pnpm --version
# 应输出 11.x.x2.5 配置 pnpm 国内镜像源(加速依赖安装)
pnpm config set registry https://registry.npmmirror.com这一步可选,但推荐配置。ECS 如果在北京/上海区域,从
npmmirror拉包速度远快于官方源。
2.6 配置 pnpm 环境变量
pnpm setup
source /home/ecs-user/.bashrc2.7 验证构建能力
找一个临时目录,测试 pnpm 是否能正常工作:
mkdir ~/test-pnpm && cd ~/test-pnpm
echo '{"name":"test"}' > package.json
pnpm add lodash如果安装成功,说明 Node.js 和 pnpm 环境就绪。
完成后删除测试目录:
cd ~ && rm -rf ~/test-pnpm三、ECS 上准备部署脚本
3.1 生成token
WebHook 的 URL 是暴露在公网上的(即使走 Nginx 反代,也是一个公开可访问的地址)。如果不加校验,任何人只要知道你的 WebHook 地址,就可以触发部署脚本,可能导致:
- 恶意代码被拉取并执行
- 频繁触发部署耗尽服务器资源
- 博客内容被恶意篡改
我们需要引入引入随机 token。token 相当于一把钥匙——只有持有正确 token 的请求才会被放行。没有 token 的人即使知道 WebHook 地址,也无法触发部署。 第一步:生成随机 token 在 ECS 上执行:
openssl rand -hex 16输出类似:
3f8a2c1b9e4d7f0a5c3b8e2d1f6a4c9b这串字符就是你的 token。
3.2 创建部署脚本
复制以下所有命令 到 ECS 服务器中 执行:
⚠️ 复制前修改:
⚠️ 以下命令文本中GIT_REPO=git@gitee.com:你的用户名/jiejinx-blog.git这里替换为你的码云项目仓库ssh链接后 再复制命令执行
⚠️EXPECTED_TOKEN="你的随机token", 这里的token需要自己提前生成并替换
tee /home/ecs-user/deploy-blog.sh > /dev/null << 'SCRIPT'
#!/bin/bash
set -e
# ⚠️ 目录配置区(按你的实际情况修改)
GIT_REPO=git@gitee.com:你的用户名/jiejinx-blog.git
WORK_DIR=/var/www/jiejinx-blog
DIST_DIR=/var/www/html/blog
BRANCH=master
LOG_FILE=/home/ecs-user/deploy.log
# ⚠️ Token 配置
EXPECTED_TOKEN="你的随机token"
TOKEN="$1"
# 日志文件超过 1000 行时自动清理前半部分
if [ -f "$LOG_FILE" ] && [ "$(wc -l < "$LOG_FILE")" -gt 1000 ]; then
tail -n 500 "$LOG_FILE" > "${LOG_FILE}.tmp" && mv "${LOG_FILE}.tmp" "$LOG_FILE"
fi
# Token 校验
if [ "$TOKEN" != "$EXPECTED_TOKEN" ]; then
echo "❌ token 校验失败" | tee -a "$LOG_FILE"
exit 1
fi
{
echo "========================================"
echo "🚀 开始部署:$(date '+%Y-%m-%d %H:%M:%S')"
} >> "$LOG_FILE"
# 1. 拉取最新代码
if [ ! -d "$WORK_DIR/.git" ]; then
echo "首次部署,clone 仓库..." | tee -a "$LOG_FILE"
git clone "$GIT_REPO" "$WORK_DIR"
cd "$WORK_DIR"
else
cd "$WORK_DIR"
git fetch origin "$BRANCH"
git reset --hard "origin/$BRANCH"
fi
echo "✅ 代码更新完成" | tee -a "$LOG_FILE"
# 2. 安装依赖
pnpm install --frozen-lockfile >> "$LOG_FILE" 2>&1
echo "✅ 依赖安装完成" | tee -a "$LOG_FILE"
# 3. 构建静态文件
pnpm run build >> "$LOG_FILE" 2>&1
echo "✅ 构建完成" | tee -a "$LOG_FILE"
# 4. 同步到 Nginx 目录
rsync -a --delete "$WORK_DIR/docs/.vitepress/dist/" "$DIST_DIR/"
echo "✅ 同步完成" | tee -a "$LOG_FILE"
# 5. 记录版本号
COMMIT_HASH=$(git rev-parse --short HEAD)
echo "📝 版本: $COMMIT_HASH ($BRANCH)" | tee -a "$LOG_FILE"
echo "🎉 部署完成:$(date '+%Y-%m-%d %H:%M:%S')" | tee -a "$LOG_FILE"
echo "========================================" >> "$LOG_FILE"
SCRIPT3.3 加执行权限
# 创建并授权工作目录
sudo mkdir -p /var/www/jiejinx-blog
sudo chown -R ecs-user:ecs-user /var/www/jiejinx-blog
#检查目录授权
ls -ld /var/www/jiejinx-blog
# 确认 Nginx 目录权限
sudo mkdir -p /var/www/html/blog
sudo chown -R ecs-user:ecs-user /var/www/html/blog
#检查目录授权
ls -ld /var/www/html/blog
# 授权脚本运行权限
chmod +x /home/ecs-user/deploy-blog.sh3.4 私有仓库处理(开源仓库可跳过)
Gitee 私有仓库 clone/pull 需要认证。推荐使用 SSH 部署密钥。
3.4.1 在 ECS 上生成 SSH 密钥对(如果已有则跳过)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""查看公钥:
cat ~/.ssh/id_ed25519.pub3.4.2 配置公钥
登录码云,打开 码云Gitee 仓库 → 管理 → 部署公钥管理 → 添加公钥,粘贴公钥内容,勾选“授予只读权限”。
3.4.3 连通性验证
部署脚本通过 SSH 协议从 Gitee 拉取代码时,如果是首次连接,SSH 会提示确认主机指纹。由于后续的部署脚本是非交互式运行的,无法响应这个提示,会导致连接被拒绝。
提前将 Gitee 的主机指纹添加到 known_hosts 中,可以跳过这个确认步骤。
执行以下命令:
# 添加 Gitee 主机指纹到 known_hosts
ssh-keyscan -t rsa gitee.com >> ~/.ssh/known_hosts验证连通性:
ssh -T git@gitee.com如果返回以下内容,说明 SSH 连通性正常:
Hi Anonymous (DeployKey)! You've successfully authenticated, but GITEE.COM does not provide shell access.如果返回 Permission denied,请检查2.2中的 SSH 部署密钥的配置是否正确。
3.5 执行验证
手动执行部署脚本:
# 自动提取 token 并验证
TOKEN=$(grep '^EXPECTED_TOKEN=' /home/ecs-user/deploy-blog.sh | cut -d'"' -f2)
bash /home/ecs-user/deploy-blog.sh $TOKEN查看部署日志:
cat /home/ecs-user/deploy.log
#只看最后几次
tail -20 /home/ecs-user/deploy.log