web 博客自动化部署 m0ss 2026-07-16 2026-07-16 一、整体架构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 你的 Windows 电脑 阿里云 Ubuntu 服务器 ───────────────── ────────────────── hexo generate ↓ 生成 HTML/CSS/JS SSH免密通道 Git 裸仓库 在 public/ 目录里 ←──────────────→ /var/repo/hexo.git ↓ ↓ hexo deploy 收到推送自动触发 ↓ ↓ git push ─────── 推送到 ──────→ post-receive 钩子执行 ↓ git checkout -f 文件解压到 /var/www/hexo/ ↓ Nginx 读取并对外服务 ↓ 用户访问 https://你的域名
🔑 核心思想:本地负责生成,服务器只负责展示。 服务器不需要 Node.js、不需要 Hexo、不需要 AnZhiYu 主题。只装 Nginx + Git 就够了。
二、前提条件 开始之前,确认以下事情已经完成:
检查项
怎么确认
服务器 Nginx 已配好
SSH 连上执行 nginx -t
服务器 Git 裸仓库已建
ls /var/repo/hexo.git/ 有输出
服务器部署钩子已配
ls -la /var/repo/hexo.git/hooks/post-receive 有 x 权限
服务器 Nginx 站点目录已建
ls /var/www/hexo/ 有输出(可以是空目录)
本地 Hexo 能正常生成
本地执行 hexo generate 不报错
域名已解析到服务器
ping 你的域名 返回服务器 IP
三、本地:生成 SSH 密钥 操作位置
命令
过程 1 2 3 4 Generating public/private rsa key pair. Enter file in which to save the key (C:\Users\你的用户名\.ssh\id_rsa): ← 直接回车 Enter passphrase (empty for no passphrase): ← 直接回车 Enter same passphrase again: ← 直接回车
一路回车,不设密码。
生成的产物
文件
路径
性质
私钥
C:\Users\你的用户名\.ssh\id_rsa
🔒 绝不给任何人
公钥
C:\Users\你的用户名\.ssh\id_rsa.pub
📤 放到服务器上
为什么需要 SSH 密钥? hexo deploy 底层执行的是 git push,通过 SSH 协议把文件传到服务器。没有密钥的话,每次推送都要输入服务器密码。部署依赖自动化,不能让 Hexo 卡在密码输入提示上。
公钥 = 锁,私钥 = 钥匙。你把锁(公钥)装在服务器门上,你用钥匙(私钥)就能直接开门,服务器认钥匙不认密码。
四、本地:传公钥到服务器 操作位置
命令 1 type C:\Users\你的用户名\.ssh\id_rsa.pub | ssh root@ 你的服务器IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
命令拆解
部分
解释
type
Windows 下的文件读取命令(相当于 Linux 的 cat)
C:\Users\...\.ssh\id_rsa.pub
公钥文件路径
|
管道,把左边命令的输出传给右边
ssh root@你的服务器IP
连到服务器
mkdir -p ~/.ssh
确保服务器的 ~/.ssh/ 目录存在
cat >> ~/.ssh/authorized_keys
把公钥追加写入认证文件
效果 执行后需要输入一次服务器密码 。之后 ssh root@你的服务器IP 直接连上,不再要密码。
验证
如果直接进去、不提示密码,说明配置成功。输入 exit 退出回到本地。
为什么要把公钥传到服务器? SSH 认证流程:
1 2 3 4 5 6 7 8 9 本地发起连接 ↓ 服务器说:"证明你的身份" ↓ 本地拿私钥加密一段信息发过去 ↓ 服务器用 authorized_keys 里的公钥解密 ↓ 解密成功 → 身份验证通过 → 免密登录 ✅
authorized_keys 文件里每行一个公钥,你可以放多个公钥(比如家里电脑一个、公司一个),都能免密登录。
五、本地:安装部署插件 操作位置
命令 1 2 cd D:\www\blog\hexopnpm add hexo-deployer-git
说明
部分
解释
cd D:\www\blog\hexo
进入你的 Hexo 项目目录
pnpm add
用 pnpm 安装(你的项目是 pnpm 管理的,不要用 npm)
hexo-deployer-git
Hexo 官方 Git 部署插件
为什么需要这个插件? Hexo 本身只会生成静态文件到 public/ 目录,不会自动把文件传到服务器。hexo-deployer-git 插件让 Hexo 知道 hexo deploy 时要做的事:用 Git 把 public/ 目录推送到远程仓库。
⚠️ 你的项目用的是 pnpm 不是 npm。看 node_modules 路径里如果有 .pnpm 就说明是 pnpm 项目,安装包必须用 pnpm add,用 npm 会报错。
六、本地:配置 deploy 操作位置
文件路径 1 D:\www\blog\hexo\_config.yml
要修改的内容 用记事本或 VS Code 打开 _config.yml,找到 deploy 这一块,改成:
1 2 3 4 deploy: type: git repo: root@你的服务器IP:/var/repo/hexo.git branch: master
每一项的含义
字段
值
为什么这么写
type
git
告诉 Hexo 用 Git 方式部署(除了 git,还有 rsync、ftp 等方式)
repo
root@你的服务器IP:/var/repo/hexo.git
root 是登录用户,冒号后面是服务器上 Git 仓库的绝对路径
branch
master
推送到 master 分支,服务器钩子监听的就是这个分支
⚠️ 缩进注意 1 2 3 4 deploy: type: git repo: root@... branch: master
YAML 语法严格要求用空格缩进,不能混用 Tab ,否则 Hexo 读取文件会报错。
为什么配置是这样? hexo deploy 内部执行的实际命令等价于:
1 2 3 4 5 cd publicgit init git add -A git commit -m "..." git push -f root@你的服务器IP:/var/repo/hexo.git master
Hexo 把 public/ 当作一个独立的 Git 仓库,每次 deploy 都强制推送到你在 repo 里指定的地址和分支。服务器上的 Git 裸仓库收到推送后,触发 post-receive 钩子,自动把文件检出到 /var/www/hexo/。
七、本地:执行推送 操作位置
命令 1 2 3 4 cd D:\www\blog\hexohexo clean hexo generate hexo deploy
或者一行 1 cd D:\www\blog\hexo && hexo clean && hexo generate && hexo deploy
每一步做了什么
命令
作用
输出示例
hexo clean
清空 public/ 目录,删除缓存
INFO Deleted database.
hexo generate
重新生成所有静态页面到 public/
INFO Generated: index.html …
hexo deploy
把 public/ 通过 Git 推送到服务器
To root@IP:/var/repo/hexo.git
正常情况下 deploy 应该看到 1 2 3 4 5 6 7 8 INFO Deploying: git INFO Clearing .deploy_git folder... INFO Copying files from public folder... INFO Committing... To root@你的IP:/var/repo/hexo.git abc123..def456 HEAD -> master Branch 'master' set up to track remote branch 'master' from 'root@你的IP:/var/repo/hexo.git'. INFO Deploy done: git
为什么每次都要三步?
clean — 保证从头开始生成,避免旧文件残留(比如你删了一篇文章,不清的话旧 HTML 还在)
generate — 把 Markdown + 主题渲染成 HTML/CSS/JS
deploy — 把渲染结果上传到服务器
📌 日常写新文章后,只需执行这一条命令即可更新网站。
八、服务器:Git 钩子原理 回顾服务器上的配置 这个已经配置过了,这里解释原理,方便以后排查问题。
钩子文件 1 服务器路径:/var/repo/hexo.git/hooks/post-receive
文件内容 1 2 #!/bin/bash git --work-tree=/var/www/hexo --git-dir=/var/repo/hexo.git checkout -f
触发时机 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 你本地 hexo deploy ↓ 服务器收到 git push ↓ 数据写入 /var/repo/hexo.git ↓ Git 自动查找 hooks/ 目录 ↓ 找到 post-receive → 执行它 ↓ post-receive 里的脚本运行 ↓ git checkout -f 把文件解压到 /var/www/hexo ↓ Nginx 读到新文件 → 网站更新完毕
三个关键点
要素
说明
文件名必须叫 post-receive
Git 只认这个名字,不能改
必须有可执行权限 (chmod +x)
没有执行权限 Git 会跳过,文件不会更新
脚本内容必须是 #!/bin/bash 开头
告诉系统用 bash 解释器执行
手动验证钩子是否正常 SSH 连上服务器:
1 2 3 4 5 6 7 8 9 cd /var/repo/hexo.gitgit log --oneline git --work-tree=/var/www/hexo --git-dir=/var/repo/hexo.git checkout -f ls /var/www/hexo/
九、完整命令速查 服务器侧(一次性配置,已完成) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 apt update && apt upgrade -y apt install nginx git -y fallocate -l 2G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile mkdir -p /var/www/hexomkdir -p /var/repo/hexo.git && cd /var/repo/hexo.git && git init --barecat > /var/repo/hexo.git/hooks/post-receive << 'EOF' git --work-tree=/var/www/hexo --git-dir=/var/repo/hexo.git checkout -f EOF chmod +x /var/repo/hexo.git/hooks/post-receivecertbot --nginx -d www.你的域名.com
本地侧(首次配置) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ssh-keygen -t rsa type C:\Users\你的用户名\.ssh\id_rsa.pub | ssh root@ 你的IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" ssh root@ 你的IP cd D:\www\blog\hexopnpm add hexo-deployer-git
日常更新(每次发文章) 1 cd D:\www\blog\hexo && hexo clean && hexo generate && hexo deploy
十、常见问题排查 ① hexo deploy 报 “Permission denied” 1 2 3 原因:SSH 密钥没配好 排查:ssh root@你的IP → 如果需要密码就说明密钥没生效 解决:重新执行「四、传公钥到服务器」
② hexo deploy 输出正常但网站没变 1 2 3 4 5 6 原因:钩子没触发 排查:SSH 连服务器 → ls /var/www/hexo/ 如果是空目录 → 钩子有问题 解决:检查 hook 文件和权限 cat /var/repo/hexo.git/hooks/post-receive ls -la /var/repo/hexo.git/hooks/post-receive (看有没有 x)
③ hexo deploy 报 “ERROR Deployer not found: git” 1 2 原因:没装 hexo-deployer-git 解决:pnpm add hexo-deployer-git
④ hexo deploy 卡住不动 1 2 原因:SSH 连不上服务器(IP 写错、安全组没开 22 端口、服务器关机) 排查:ssh root@你的IP → 能连上吗?
⑤ 浏览器访问网站是空白/Nginx默认页 1 2 3 4 原因:Nginx 没指向 /var/www/hexo 排查:cat /etc/nginx/sites-enabled/hexo | grep root 应该看到 root /var/www/hexo; 解决:改配置 → nginx -t → systemctl reload nginx