0%

Hexo 自动化部署实战:从内网服务到公网访问的完整链路

Hexo 博客看起来只是一个静态站点,但一旦进入长期运营,就不能只靠本地 hexo g && hexo d 手工发布。内容越多、协作者越多、商业化入口越多,发布链路越需要工程化:可检查、可回滚、可观察、可自动部署。

这篇文章基于博客实际部署经验,整理一套从内网服务到公网访问的 Hexo 自动化部署方案。

1. 目标架构

一条稳定的 Hexo 自动化发布链路,建议包含这些组件:

  • 内容仓库:存放文章、页面、专题页、Front Matter;
  • 主题仓库:存放 NexT 主题、导航、CTA、样式;
  • 站点总仓库:存放 Jenkinsfile、Dockerfile、Nginx 配置和 CI 检查脚本;
  • Jenkins:负责拉取仓库、构建静态页面、制作镜像、部署容器;
  • Nginx:负责托管静态资源和反向代理;
  • FRP / WireGuard:用于内网服务暴露或远程访问;
  • 域名与证书:用于公网 HTTPS 访问。

推荐流程:

1
2
3
4
5
6
7
Git 提交 / MR 合并
-> Jenkins 拉取 site + source + themes
-> 内容检查 / 产物检查 / 运行时检查
-> Hexo generate
-> Docker build
-> stop old container / run new container
-> Nginx / FRP 对外访问

2. 为什么不建议手工部署

手工部署前期很方便,但长期会出现几个问题:

  1. 本地环境不可复现:Node、Hexo、主题依赖版本容易漂移;
  2. 发布过程不可审计:不知道哪次提交上线了什么内容;
  3. 容易漏检查:Front Matter、链接、冲突标记、专题页缺失都可能直接上线;
  4. 回滚困难:出问题时不知道该回到哪个镜像或 commit;
  5. 多仓库协作混乱:内容、主题、部署脚本容易混在一起改。

博客要做商业化入口,就必须把发布当成产品链路的一部分,而不是个人脚本。

3. Jenkins 构建流程设计

建议 Jenkinsfile 至少包含这些 stage:

3.1 Checkout

拉取总仓库和子模块:

1
2
git submodule sync
git submodule update --init --recursive --remote

如果博客采用“总仓库 + 内容仓库 + 主题仓库”的结构,要特别注意子模块指针和远程 main 的关系。合并内容或主题 MR 后,总仓库也要更新子模块指针或在 Jenkins 中明确拉取最新远程分支。

3.2 Content Check

检查内容侧常见问题:

  • 必备页面是否存在:/services//products//about/
  • Front Matter 是否可解析;
  • 是否存在 Git 冲突标记;
  • 是否误提交测试文章、内部路径或敏感信息;
  • 商业入口链接是否存在。

3.3 Build

典型构建命令:

1
2
3
npm ci
npx hexo clean
npx hexo generate

如果依赖下载慢,可以使用私有 npm 源或缓存,但不要为了速度牺牲可复现性。

3.4 Public Check

构建后检查 public/ 目录:

  • 首页是否生成;
  • sitemap 是否生成;
  • 关键页面是否存在;
  • CSS / JS / 图片资源是否完整;
  • 是否出现空页面或 404。

3.5 Runtime Check

容器启动后做运行时检查:

1
2
3
curl -f http://localhost:8080/
curl -f http://localhost:8080/services/
curl -f http://localhost:8080/products/pr-reviewer/

只检查构建成功是不够的,最终用户访问的是运行时服务。

4. Nginx 与 FRP 暴露链路

如果博客服务运行在内网机器上,可以采用:

1
2
3
4
5
公网域名
-> 公网 Nginx / 入口机
-> FRP / WireGuard 通道
-> 内网 Nginx
-> Hexo Docker 容器

关键点:

  • 公网入口负责 HTTPS 证书和域名;
  • 内网 Nginx 负责转发到本机容器端口;
  • FRP 只暴露必要端口,不要暴露 Docker API;
  • 健康检查要覆盖公网 URL 和内网容器 URL;
  • Nginx 配置变更要有备份和回滚方案。

5. Docker 镜像清理

Hexo 静态站点镜像通常不大,但长期频繁部署会产生大量旧镜像,尤其是重复覆盖 latest 时,旧镜像会变成 <none>:<none> dangling image。

建议部署后清理:

1
2
# 清理无标签、超过 24 小时且未被容器引用的 dangling 镜像
docker image prune -f --filter "dangling=true" --filter "until=24h"

不要直接全量 docker system prune -a,否则可能误删其他项目仍需要的镜像和缓存。

6. 常见故障排查

问题 可能原因 排查方式
首页正常,文章 404 permalink 或 public 产物缺失 检查 Hexo 生成结果和 sitemap
新页面没上线 子模块指针未更新或 Jenkins 未拉最新 检查 git submodule status
样式没变化 主题仓库未更新 检查 themes commit
部署成功但访问失败 容器端口、Nginx 或 FRP 转发错误 检查 docker ps、Nginx 日志、curl
磁盘占满 Docker dangling 镜像堆积 检查 docker images -f dangling=true

7. 架构师点评

博客自动化部署本质上是一个小型 DevOps 系统。它包含代码管理、内容管理、主题管理、构建、发布、运行时检查和回滚。把这个链路做好,不只是为了博客稳定,也是企业知识库、文档中心、营销站点和 AI Agent 内容运营系统的基础能力。

这次博客整改中,我更关注的是“发布链路可治理”:每次内容变化都能检查,每次构建都能验证,每次部署都能回滚。这比单纯追求一次构建成功更重要。

8. 企业落地建议

如果你的团队也在维护 Hexo / VuePress / Docusaurus / MkDocs 这类静态站点,建议优先补齐四件事:

  1. 内容检查脚本;
  2. 构建产物检查;
  3. 运行时健康检查;
  4. 镜像与日志清理策略。

需要把博客、知识库或产品文档站升级为可持续运营的内容平台,可以查看 企业 AI Agent / AI Coding 落地咨询AI Agent 产品与资料