用 Vercel + Hexo + GitHub 打造自动更新发布的个人网站(以 jiangxu.net 为例)

你可能已经把博客搭好了,但每次发文都还要“打包-上传-部署”?今天我们来点优雅的:写完 Markdown,一把 git push,网站自动更新,全程无手动。本文用 Hexo + GitHub + Vercel 的经典三件套,手把手带你把自动化这件事变得像呼吸一样自然。整篇文章以已上线的 jiangxu.net 为例,顺带聊聊背后的技术原理。

术语速查表(新手友好)

术语 解释
Webhook 当仓库发生事件(如 push)时,GitHub 主动向一个 URL 发送 HTTP 请求,通知第三方(这里是 Vercel)触发自动流程。
原子发布 新版本先在后台完整构建并准备好,随后用一次“瞬间切换”替换旧版本;全站要么是旧版,要么是新版,不会出现一半新一半旧;出问题可秒级回滚。
CDN 内容分发网络,把静态资源复制到多个边缘节点,用户就近访问,延迟更低、带宽更大、稳定性更好。
全球 CDN 覆盖全球多个区域的 CDN,让不同地区的访客都能就近获取内容;Vercel 发布会把 public/ 分发到其全球边缘节点。
根域(apex) 不带子域的域名,例如 jiangxu.net。通常用 A 记录指向服务商提供的 IP(如 76.76.21.21)。
www 子域 www 的子域,例如 www.jiangxu.net。通常用 CNAME 指向托管商域名(如 cname.vercel-dns.com),并可在托管侧设置重定向到根域或相反方向。
静态化 预先把页面生成成静态的 HTML/CSS/JS 文件(例如 Hexo 的 hexo generate 生成 public/),上线时无需后端渲染。
PR(Pull Request) 在 Git 平台上发起的“合并申请”,用于变更的讨论与审核;每个 PR 在 Vercel 都会有独立的 Preview 环境,方便预览和评审。

小注:

  • A 记录 = 把域名直接指向一个 IPv4 地址(IPv6 用 AAAA)。例:jiangxu.net -> A 76.76.21.21
  • CNAME = 给域名起“别名”,把一个域名指向另一个域名,再由对方域名解析到 IP。例:www.jiangxu.net -> CNAME cname.vercel-dns.com
  • 通常根域名用 A 记录,www 子域用 CNAME(少数 DNS 支持根域“平展”别名,叫 ALIAS/ANAME)。

我们要得到什么

  • 写文章 → git push → 几十秒后网站自动发布
  • 自定义域名 jiangxu.net,含 www 子域
  • 全站 CDN 加速、原子发布(不会出现“构建到一半页面 404”的尴尬)

项目现状(以本仓库为例)

本项目是一个标准 Hexo 项目,核心配置如下:

1
2
3
4
5
6
# _config.yml(节选)
url: https://jiangxu.net/
theme: pure
post_asset_folder: true
relative_link: true
syntax_highlighter: highlight.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// package.json(节选)
{
"hexo": { "version": "7.3.0" },
"scripts": {
"start": "hexo server",
"build": "hexo generate",
"clean": "hexo clean",
"deploy": "hexo deploy",
"clean:deploy": "hexo clean && hexo generate && hexo deploy"
},
"dependencies": {
"hexo": "^7.3.0",
"hexo-renderer-marked": "^7.0.0",
"hexo-server": "^3.0.0"
}
}

注意:项目里虽然安装了 hexo-deployer-git,但我们将由 Vercel 来托管与发布静态文件,不必再用 hexo deploy 推到 GitHub Pages。Vercel 在构建时会执行 npm ci && npm run build(或者你自定义的命令),生成 public/ 目录并发布。

架构一图流(你可以先收藏再细看)

1
2
3
4
5
6
7
8
flowchart LR
A[本地写 Markdown] --> B[git push 到 GitHub 仓库]
B --> C[GitHub 触发 Webhook 通知 Vercel]
C --> D[Vercel 拉取最新提交]
D --> E[执行构建: hexo generate]
E --> F[生成静态站点 public/]
F --> G[Vercel 原子发布到全球 CDN]
G --> H[用户访问 jiangxu.net 获取最新内容]

一步步搭起来

1)把 Hexo 项目放到 GitHub

如果你已经有仓库,跳过本节。否则:

1
2
3
4
5
6
git init
git remote add origin https://github.com/<your-username>/<your-repo>.git
git add .
git commit -m "init blog"
git branch -M main
git push -u origin main

2)在 Vercel 里“导入”这个仓库

  1. 用 GitHub 账号登录 Vercel。
  2. New Project → 选中你的仓库 → Import。
  3. 配置:
    • Framework Preset:选择 Hexo(或手动)
    • Install Command:默认(推荐 npm ci
    • Build Command:hexo generate
    • Output Directory:public
  4. 点击 Deploy。几十秒后会拿到一个 *.vercel.app 的临时域名。

此后每次 push,Vercel 都会自动构建与发布。开分支提 PR 也会生成“预览环境”,方便你把文章和样式改动发给朋友“云审稿”。

3)绑定自定义域名 jiangxu.net

在项目 → Settings → Domains 里添加 jiangxu.netwww.jiangxu.net,按提示去域名注册商配置 DNS:

  • 根域(apex):添加 A 记录 → 指向 76.76.21.21(Vercel 的 Anycast IP)
  • www 子域:添加 CNAME → 指向 cname.vercel-dns.com

等 DNS 生效后,Vercel 会自动签发 HTTPS 证书(Let’s Encrypt)。如果你想把 www 跳转到根域(或反过来),在 Vercel 域名设置里点一下“Redirect”即可。

顺带一提,Hexo 的 _config.yml 已把 url 设为 https://jiangxu.net/

1
2
3
4
url: https://jiangxu.net/
pretty_urls:
trailing_index: true
trailing_html: true

这会影响站内链接、RSS、Canonical 等生成,记得与实际域名保持一致。

4)写作与发布流程(真正的“自动化”)

日常只做三步:

1
2
3
hexo new "我的新文章"  # 生成草稿/文章
# 写!配图放到同名资源文件夹(post_asset_folder: true)
git add . && git commit -m "post: 我的新文章" && git push

然后泡杯咖啡,等 Vercel 自动完成构建与发布。

这些技术原理,知其所以然更香

  • Webhooks:Vercel 与 GitHub 通过 Webhooks 通知协作。仓库有新提交 → 触发一次构建。
  • CI/CD:Vercel 内置流水线,拉代码 → 安装依赖 → 执行 hexo generate → 上传 public/
  • 静态化:Hexo 预渲染为纯静态文件(HTML/CSS/JS),天然适合 CDN,延迟低、可承载高并发。
  • 原子发布:新版本构建完成后一次性切换,不会出现“部分页面旧、部分页面新”。
  • 缓存与失效:CDN 命中为王。新版本发布后 Vercel 会做缓存失效处理,通常无需你手动清缓存。
  • 预览环境:每个 PR 一条独立的 Preview URL,不影响生产站点。

常用实践与“避坑锦囊”

  • 资源管理:post_asset_folder: true 已开启。用 source/_posts/我的新文章/ 管理配图,Markdown 里直接相对路径引用,迁移/重构都不怕。
  • 相对链接:relative_link: true 可减少跨域/环境差异带来的链接问题。
  • 主题与样式:当前主题为 pure。如果你改了主题静态资源路径,别忘了清缓存再构建:npm run clean && npm run build
  • 不混用两套部署:既然用了 Vercel,就不必再通过 hexo-deployer-git 推 GitHub Pages,避免“双主发布”互相覆盖。
  • Node 与依赖:为一致的构建结果,建议在 Vercel 的 Project Settings → Environment 里设置 NODE_VERSION(如 18/20)并使用 npm ci

DNS 解析小抄(再来一张图)

1
2
3
4
5
6
7
graph TD
User[访客浏览器] -->|jiangxu.net| DNS[权威 DNS]
DNS -->|A 76.76.21.21| Vercel[Vercel Edge Network]
User2[访客浏览器] -->|www.jiangxu.net| DNS2[权威 DNS]
DNS2 -->|CNAME cname.vercel-dns.com| Vercel
Vercel --> CDN[全球 CDN 节点]
CDN --> Site[静态站点 public/]

收尾:写作体验从“还行”升到“上头”

现在,发文这件事就像发朋友圈:写完点发送(push 一下),剩下交给机器。你要做的,不过是保持输出而已。

如果你想继续进阶:

  • 在 PR 的 Preview 环境里做 A/B 尝试(比如新主题、新排版)
  • 接入评论系统(如 Gitalk/Giscus),在 Vercel 环境变量里配置 Token
  • 在构建脚本里加上字数统计、站点地图、SEO 插件

愿你写得开心,站点常新。jiangxu.net 我们下次见!

面试实战自述(段落版)

直白说,我把写博客变成了“像发朋友圈一样简单”:我在本地用 Markdown 写完,git push 一下,几十秒后网站就自动更新。我用 Hexo 把文章提前生成为静态网页(不需要服务器算),代码放在 GitHub,Vercel 负责自动构建和发布,并把网页分发到全球的 CDN 节点,让离用户近的机器来服务,访问更快、更稳定。

它的工作流程很简单:我提交代码后,GitHub 会“提醒”Vercel(这叫 Webhook,就是一次通知)。Vercel 自动安装依赖并运行 hexo generate 生成网页文件,然后一次性把新版本切换上线(原子发布:不是一点点替换,而是“全部准备好再整体切换”,因此不会出现“有的页面新有的页面旧”)。域名这块,我把根域名和 www 都指到了 Vercel,证书是自动签发的,整站都是 HTTPS。

为什么这样做?因为博客是“读多写少”,静态页面最合适:速度快、成本低、出错少。

我为稳定性做了几个小细节:固定 Node 版本并用 npm ci 保证“在哪构建都一样”;文章的配图和资源放在同名文件夹并用相对路径,避免换主题或迁移时出现 404;DNS 按要求配置了根域名的 A 记录和 www 的 CNAME,确保国内外访问都能走最近的节点。

这个项目让我把零散的名词(Webhook、CI/CD、静态化、原子发布、CDN、DNS)串成了一个能跑起来的系统。我能现场演示:改一行文案、git push,几秒钟后就能拿到一个预览地址;确认没问题,再合并上线。如果出问题,我也知道怎么通过日志定位,并在需要时一键回退。