Margrop
Articles394
Tags1012
Categories7

Categories

/health 200 /v1/models 0.025s 0.17.0 0步 0步主动 0步元递归 0步本身 12类 18789 18天idle 18天静默 192.168.x.x 1password 2.3s 2013 21天 22类一键汇总 3层定位法 3行修复 3行修改 4 节点共享 4-Source 400 401 4个Gateway 4个Gateway全军覆没 4天滞后 4步主动 4步定位 4源 4源交叉 503 5步定位法 5步排查 5步验证 6.2.0 6.24 release 6.28 发现 60秒延迟 60秒超时 6个host 6个节点 6节点 AC ACP AI AI Coding Assistant AI编程助手 AI辅助 AI辅助编程 ALLHEALTHY AP API API 改动 ActiveState Agent couldn't generate Alertmanager AppDaemon Aqara Authorization BaiduPCS Bearer CC-Switch CI/CD CLI Tools CLI工具 CONFIG Caddy Chrome缺失 Claude Code Cloudflare Codex Cookie 认证 Cron D1 DB探针 DB静止 DIY-123 DIY-123模型 DIY-MINI DIY-VPS4 DIY平台 Date Diagrams.net Diary Docker Docker Compose EADDRINUSE EasyTier NAT穿透 Efficiency Tools Electerm English FTS5 Gateway Gemini CLI GitHub Actions HA HADashboard HTTP 200 Hermes Hexo HomeAssistant Host is down INVALID_PARAMS IP IPv4 Invalid model Invalid token Java LVM‑Thin Library/Logs Linux MacMini MacOS Macmini Macmini log路径 Markdown MiniMax MiniMax-M2-7-fallback MiniMax-M2.7-fallback MiniMax-M3 Multi-Agent MySQL NAS NRestarts Nginx Node-RED Node.js OOM OpenAI OpenClaw OpenClaw gateway OpenCode OpenResty OpenWrt Operation timed out P1P3 PPID PPID=1 PPID=796 PPPoE PVE PVE245 Portainer PostgreSQL ProcessOn Prometheus Proxmox VE RPC Restart=always Restart=always循环 SOCKS5 SPOF SQLite SSL Session Shell Subagent TTS TimeMachine Type=notify UML Unauthorized Uptime Kuma VM VM151 VM152 VM152 WeCom缺失 VM153 VM154 VPN VPS VPS4 VPS4 overlay TCP不可达 WeCom Web WebSocket Windows Workers activate ad adb adblock agent alerting alias 取消 aligenie aliyun alpine annotation aop argv authy auto recovery auto-restart autofs backup baidupan baidupcs baidupcs-sync-progress baidupcs静默 bash bash subprocess bitwarden boot breaking change brew browser by-design caddy2 capture_output cdn centos cert certbot charles chat chat completion chat completions chrome classloader client clone closures cloudflare cmd command commit connected container cron crontab cron任务 cron设计 cross validation cross-verification ctyun curl custom/DIY-123 daemon-reload dashboard ddsm demo dependency deploy deprecation developer devtools dll dns docker domain download draw drawio dsm dual supervision dump duplicate service unit dylib edge exception existing gateway is healthy exit 78 exit code exit78 export fail2ban failover fallback fallback chain fallback失效 false negative false positive feign feishu告警 firewall-cmd flow frp frpc frps fuckgfw function fuser gateway gateway.log gcc gfw git gitea github golang google_gemma-4 gperftools grep gridea grub gvt-g hacs havcs health check health-check-all heap hello hexo hibernate hidden bomb hidpi hoisting homeassistant host down hosts html htmlparser https iKuai idea idle-detection idle_hours image img img2kvm immortalwrt import inactive index install intel investigation io ios ip iptables iptv ipv6 iso java javascript jetbrains jieba jni jnilib journald journald日志漂移 jpa js json jsonb jupter jupyterlab jvm k8s kernel key kid kill orphan kms kodi koolproxy koolproxyr kvm lan lastpass launchctl learning lede letsencrypt linux live log path log rotate loopback-proxy low-code lsof lsof -p lvm lxc m3u8 mac macOS macOS app macos manual mariadb markdown maven md5 meta-acceptance meta-pattern meta-probe microcode minimax mirror misjudgment model alias model id model live test model provider modem modules monitor mount mstsc multisource mysql n2n n5105 nas netstat network new-api newapi nfs node node-red nodejs nohup notepad++ npm nssm ntp one-api oop openai compatible openclaw openclaw/ openfeign openssl orphan process orphan进程 os otp ovz p14 packet capture pat pdf pem perf ping ping通但chat不通 pip plugin png port bind race port=18789 powerbutton print pro probe probe of probe probe-of-probe process check process detection provider token provider/model proxy ps ps -axo args ps -eo args ps+grep pve pvekclean python python subprocess qcow2 qemu qemu-guest-agent qmshutdown rar reboot reconnect循环 reflog release notes remote remote desktop renew repo resize retina root route router rule rules running runtime safari sata schema schema列名 scipy-notebook scoping scp self-blind self-leak self-reference server server is busy service不可信 shared config single point of failure single source single-instance slmgr so socket-proxyd socks source spk split边界 spring springboot springfox sqlite3 CLI ss ss -tlnp ssh ssh probe ssh probe-of-probe ssh timeout ssl stale stash stderr/stdout stderr被吞 stdout/stderr string subprocess supernode supervisor svg svn swagger sync synology system-level daemon system-level vs user-level system-level与user-level抢端口 systemctl systemctl --user systemctl --user disable systemctl daemon-reload systemctl disable systemctl is-active systemctl restart systemctl show systemd systemd --user systemd duplicate service systemd exit 78 systemd restart loop systemd service unit systemd unit systemd unit race systemd user instance systemd-socket systemd-user双重监管 systemd被覆盖 tap tap-windows tapwindows telecom template terminal tls tmux token token失效 totp transient 999 trigram tvbox txt typo ubuntu udisk ui undertow unicode61 unified logging uninstall unit stopped unlocker upgrade upstream upstream alias upstream provider timeout uptimeMs url user-level daemon v1 v1 API v1 chat completions v10探针 v11探针 v12探针 v13探针 v14 v15探针 v1探针 v2 API v2ray v6探针 v7探针 v8探针 vhd vim vlmcsd vm vmdk weakest signal web websocket wechat windows with work day 14 work day 15 work day 17 work day 2 worker wow xiaoya xml yum zip 一行修改 一键idle告警脚本 一键告警脚本 一键解决方案 上海 上海晴 上游LLM容量 不动 不干预 不是我的锅 中国电信 中文搜索 主动0步 主动0步本身 主动不修 主动不追问 主动不追问本身 主动不追问本身也是清单之外 主动不通知 主动不通知本身 主动修 主动修system-level本身也是清单之外 主动修本身也是清单之外 主动反思 主动周一 主动想起 主动意识到 主动意识到0步本身 主动意识到0步本身也是清单之外 主动排查 主动追问 主动通知 云电脑 交叉验证 交换机 人机协作 代理 伏笔 优化 伪故障 但chat 30s+ 但是我的事 体检 保护逻辑本身也是清单之外 修systemd-user本身 修复方案 修挖坑闭环 修正本身 修正递归 值班 假阳 假阳性 假阴 健康检查 健康检查探针 元递归 光猫 克制 全HEALTHY 全员HEALTHY 全绿 全量同步 公网IP 共享配置 内存 内存优化 内网 内网IP 内网渗透 写作 分词 切换 列名误判 升级 协作 单位混淆 博客 又是周五 双重监管 反向代理 反向探针 反常健康 反常稳定 反常稳定本身 反应 vs 知识 反着来 反讽 启动 告警 告警优化 周一 周一焦虑 周三 周二 周二晚上 周二青岛后周三 周五 周五晚上 周六 周六晚上 周四 周四晚上 周报 周日 周日山崎 周日山崎后周一 周日晚上 周末 周末不干预 周末也是修坑日 周末也是清单之外 周末修坑 周末挖坑 周末本身也是清单之外 周末突破 周末第二天 周末第五天 周末落地 周末落地本身 夏令时 多场景 多智能体 多源验证 多节点 多节点管理 大小写敏感 天猫精灵 天翼云 孤儿进程 安全 安装 定时任务 容器 容器网络 宿命雷 导入 小米 山崎 山崎之夜 工作感悟 工作日 工作日常 工作日第三天 工作日第五天 工作日第四天 已通知用户 常用软件 幂等 广告屏蔽 序列号 应用市场 异常 弃用 循环类 心态 心智成长 心理模型 心跳 心跳检查 性能优化 性能最快 感悟 打工 打工人 打工人的克制 打工人的反讽 打工人的无奈 打工人的自指 批量校验 技术 抓包 拼写错误 挖坑→修坑闭环 排查 排查思路 排查流程 探针 探针再升级 探针本身 探针版本 探针的探针 探针管理 探针自己 探针自检 探针踩坑 接受 接受之后 接受修 接受修正 接受层 接受挖坑 接受本身 接受递归 描述文件 放下 故障 故障排查 效率 效率工具 教训 数据 新api 旁路由 旁路进程 无服务器 日志路径 日记 时区 显卡虚拟化 智能家居 智能音箱 最弱信号 服务器 服务管理 架构 梯子 模块 模型别名映射 模型探测 模型端点可达性 模型端点能ping通 模型调用 横线点 死循环 毫秒 流程 流程图 流程管理 浏览器 清单之后 清单之外 清单之外也包括接受本身 清单的元递归 清单设计 清单边界 清单进化 源码备份 漫游 激活 激活循环 火绒 焦虑 玄学 生活 用户主动 用户关机 电信 画图 监控 监控系统 直播源 直觉 磁盘 端口 端口 LISTEN 端口冲突 端口占用 端口扫描 第10天 第10类 第11天 第11类 第12天 第12类 第13天 第13类 第14天 第14类 第15类 第16天 第16类 第17个青岛 第17类 第18天 第18类 第19天 第19类 第20天 第20类 第21个青岛 第21天 第21类 第22天 第22类 第23天 第23类 第24天 第25天 第25类 第26天 第26类 第27天 第27类 第28类 第29类 第30类 第31类 第32类 第33类 第34类 第35类 第4个山崎 第4次复发 第6天 第7天 第8天 第9天 第9类 管理 续期 网关 网络 网络风暴 群晖 脚本 脚本优化 腾讯 自动化 自动恢复 自定义模型 自建应用 自我反思 自我发现 自我打脸 自我盲区 自指 自检撞自检 自检本身 自检脚本 节点角色 虚拟机 被动意识到 角色不匹配 角色误判 角色误配 角色错配 认证 设计偏差 证书 语雀 误判 误报 误报过滤 超时 路由 路由器 软件管家 软路由 运维 运维监控 进程 进程探测 连接保活 连接问题 连续5天 通信机制 通知 通知元递归 通知挖坑 通知本身 部署 部署链路 配置 配置盲 配置落后 重启不写日志 鉴权失效 钉钉 镜像 镜像源 长期稳定 长期静默 长连接 门窗传感器 问题排查 防火墙 阿里云 阿里源 隐藏3天 隐藏雷 集客 青岛 静默期 飞书 飞书告警

Hitokoto

Archive

Hexo博客自动化发布的完整实践:从本地写作到一键部署的技术方案

Hexo博客自动化发布的完整实践:从本地写作到一键部署的技术方案

Hexo博客自动化发布的完整实践:从本地写作到一键部署的技术方案

前言

Hexo 是一个很受欢迎的静态博客框架,配合 GitHub Pages 使用几乎零成本,是很多个人博主和技术写作者的首选。但”手动执行 hexo g -d”这件事,每次写完文章都要做一次,时间长了还是会觉得繁琐。

本文介绍一套完整的 Hexo 博客自动化发布方案,从本地写作、GitHub Actions 自动化构建,到服务器端验证,覆盖整个流程。文章末尾提供了常见问题的排查指南,适合想要把博客发布变成”push 即发布”的写作者参考。

问题背景

传统发布流程的痛点

手动发布的典型流程是这样的:

1
写文章(本地) → 上传到服务器 → 执行 hexo g -d → 验证发布结果

这个流程存在几个常见问题:

第一,多设备写作不方便。 如果在公司和家里分别用不同的电脑写作,每次换设备都需要重新配置 Hexo 环境、clone 仓库、上传文章,流程繁琐且容易出错。

第二,发布操作无法自动化。 每次写完都要手动执行发布命令,对于高频写作者来说,这个”机械操作”累积起来也是不小的时间成本。

第三,发布结果无法自动验证。 手动执行命令之后,还需要手动打开浏览器确认文章是否正常显示。这个验证步骤很容易被忽略。

第四,脱敏检查容易被跳过。 技术博客通常包含 IP 地址、域名、路径等信息,手动检查既繁琐又容易遗漏。

自动化发布的目标

自动化方案要解决的核心问题是:

1
写文章 → push 到 GitHub → 自动构建 → 自动部署 → 自动验证

整个过程不需要人工介入,作者只需要完成”push”这一个动作,剩下的全部由系统自动完成。

架构设计

整体流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
┌─────────────┐     push      ┌──────────────┐    hexo g    ┌────────────────┐
│ 本地写作 │ ──────────► │ GitHub Repo │ ──────────► │ GitHub Pages │
└─────────────┘ └──────────────┘ └────────────────┘


┌──────────────┐
│ GitHub Actions│
│ 自动构建 │
└──────────────┘


┌──────────────┐
│ 自动化验证 │
│ (可选步骤) │
└──────────────┘

仓库结构设计

推荐采用”源码和 Pages 在同一仓库”的架构:

1
2
3
4
5
6
7
8
9
10
11
12
13
blog repository (例: my-blog)
├── .github/
│ └── workflows/
│ └── deploy.yml # CI/CD 配置
├── source/ # Hexo 源码目录
│ └── _posts/ # 文章存放位置
│ ├── ai_diary/ # AI Diary 分类
│ └── ai_tech/ # AI Tech 分类
├── themes/ # 主题目录(通常为 submodule)
├── public/ # Hexo 生成的静态文件(gitignore)
├── _config.yml # Hexo 主配置
├── package.json # npm 依赖
└── .gitmodules # submodule 配置

这样的结构有一个关键优点:源码和生成的静态网站在同一个仓库中,通过不同分支管理,无需维护两个独立的仓库。

GitHub Actions 工作流配置

基础配置

.github/workflows/deploy.yml 中编写工作流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
name: Deploy Hexo Blog

on:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
build-and-deploy:
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
# 1. 检出代码
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0

# 2. 设置 Node.js 环境(带缓存)
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

# 3. 安装依赖
- name: Install Dependencies
run: npm ci

# 4. 生成静态文件
- name: Generate Site
run: npx hexo generate
env:
TZ: Asia/Shanghai

# 5. 配置 Git 用户
- name: Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"

# 6. 部署到 GitHub Pages
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
publish_branch: gh-pages

关键配置项详解

submodules: recursive

如果主题通过 Git submodule 引入(如 git submodule add https://github.com/hexojs/hexo-theme-landscape themes/landscape),必须在 checkout 步骤加上 submodules: recursive,否则主题文件不会被克隆,导致构建失败。

fetch-depth: 0

Hexo 的某些插件依赖 Git 历史信息(如 hexo-generator-sitemap),设置为 0 可以获取完整的 Git 历史,确保插件正常工作。

cache: ‘npm’

GitHub Actions 的 Node.js Setup Action 内置了 npm 缓存支持。启用后,第二次及之后的构建会复用缓存的 node_modules,显著缩短构建时间。对于 Hexo 这样依赖不算多的项目,开启缓存可以将依赖安装时间从约 60 秒缩短到 10 秒以内。

TZ: Asia/Shanghai

这是最容易遗漏但又非常重要的配置。Hexo 默认使用 UTC 时区,如果没有设置 TZ: Asia/Shanghai,文章的 date 字段会被解析为 UTC 时间,在中国时区(UTC+8)访问时会显示为”未来时间”,导致文章排序错乱或显示异常。

进阶配置

添加构建通知

Hexo 博客通常在阿里云等国内服务器上托管,GitHub Actions 的通知邮件在 国内网络环境下经常收不到。推荐配置钉钉或企业微信群通知:

1
2
3
4
5
6
7
8
9
10
11
- name: Notify on Failure
if: failure()
run: |
curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"msgtype": "text",
"text": {
"content": "[Blog Deploy] 构建失败,请检查日志"
}
}'

添加隐私扫描步骤

技术博客中经常包含 IP 地址、域名、内部路径等敏感信息。在工作流中添加隐私扫描步骤,可以在构建阶段发现泄露风险:

1
2
3
4
5
6
7
8
- name: Privacy Scan
run: |
# 扫描敏感 IP 模式(如 192.168.x.x, 10.x.x.x 等内网IP)
if grep -rE '192\.168\.[0-9]+\.[0-9]+|10\.[0-9]+\.[0-9]+\.[0-9]+|172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]+\.[0-9]+' source/_posts/; then
echo "警告:检测到内网 IP 地址,请确认已脱敏"
exit 1
fi
echo "隐私扫描通过"

多环境分支策略

对于有”草稿”和”发布”分离需求的写作者,可以配置分支策略:

1
2
3
4
5
6
7
on:
push:
branches:
- main # push 到 main → 自动发布
pull_request:
branches:
- main # PR 到 main → 仅构建验证,不发布

服务器端自动化验证

如果博客托管在自有服务器(如阿里云 ECS)而非 GitHub Pages,还可以在服务器端添加自动化验证步骤,确保构建结果正确上传并正常渲染。

方案一:Webhooks 触发验证

GitHub Actions 在每次构建完成后可以发送 Webhook 请求:

1
2
3
4
5
6
- name: Trigger Server Verification
if: success()
run: |
curl -X POST "https://your-server.com/api/verify" \
-H "Content-Type: application/json" \
-d '{"branch": "gh-pages", "commit": "${{ github.sha }}"}'

服务器端接收 Webhook 请求后,执行以下验证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/bin/bash
# verify.sh - 服务器端验证脚本

WEBHOOK_SECRET="your-secret"

# 验证请求来源
SIGNATURE=$(echo -n "$WEBHOOK_SECRET" | openssl dgst -sha256 -hmac "$BODY" | cut -d' ' -f2)
if [ "$SIGNATURE" != "$EXPECTED_SIGNATURE" ]; then
echo "Unauthorized request"
exit 1
fi

# 验证文章文件存在
ARTICLE_COUNT=$(find /var/www/blog/source/_posts -name "*.md" | wc -l)
if [ "$ARTICLE_COUNT" -eq 0 ]; then
echo "错误:未检测到文章文件"
exit 1
fi

# 验证 Git 提交记录
LATEST_COMMIT=$(cd /var/www/blog && git log --oneline -1)
echo "最新提交: $LATEST_COMMIT"

# 验证构建产物
if [ ! -d "/var/www/blog/public" ]; then
echo "错误:构建产物目录不存在"
exit 1
fi

echo "验证通过"

方案二:定时拉取验证

如果 Webhook 方式不稳定,可以使用定时任务方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash
# pull-and-verify.sh - 定时拉取并验证

BLOG_DIR="/var/www/blog"
REMOTE="origin"
BRANCH="gh-pages"

cd $BLOG_DIR

# 拉取最新内容
git fetch $REMOTE $BRANCH
LOCAL_COMMIT=$(git rev-parse HEAD)
REMOTE_COMMIT=$(git rev-parse FETCH_HEAD)

if [ "$LOCAL_COMMIT" != "$REMOTE_COMMIT" ]; then
echo "检测到新提交,正在拉取..."
git checkout $BRANCH
git pull $REMOTE $BRANCH

# 验证
ARTICLE_COUNT=$(find $BLOG_DIR/source/_posts -name "*.md" | wc -l)
echo "文章总数: $ARTICLE_COUNT"

# 重新构建(确保最新)
hexo clean && hexo g
echo "构建完成"
else
echo "已是最新,无需更新"
fi

加入 Crontab:

1
2
# 每5分钟检查一次
*/5 * * * * /opt/scripts/pull-and-verify.sh >> /var/log/blog-sync.log 2>&1

GitHub Pages 配置

Actions 部署完成后,还需要在 GitHub 仓库设置中正确配置 GitHub Pages:

  1. 进入仓库 SettingsPages
  2. Source 选择 Deploy from a branch
  3. Branch 选择 gh-pages 分支,目录选择 / (root)
  4. 如果使用自定义域名,在 Custom domain 中填写域名并勾选 Enforce HTTPS

通常配置完成后 2-5 分钟内网站即可访问。如果长时间无法访问,先检查 GitHub Actions 的构建日志,确认是否有错误信息。

常见问题排查

问题一:Git submodule 未正确克隆

错误信息:

1
fatal: not a git repository: /path/to/theme/.git

原因: 主题通过 submodule 引入,但 checkout 时没有加上 submodules: recursive 参数。

解决方案: 修改工作流配置:

1
2
3
4
5
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0

问题二:Hexo 命令找不到

错误信息:

1
2
Error: Cannot find module 'hexo'
Error: npx: command not found

原因: package.json 中没有包含 hexo 依赖。常见于从别人那里 fork 的仓库,依赖不完整。

排查步骤:

1
2
3
4
5
# 检查 package.json
cat package.json | jq '.dependencies'

# 确认是否包含 hexo
cat package.json | grep hexo

解决方案: 执行 npm install hexo --save,确保 hexo 在 dependencies 中,然后 push 触发重新构建。

问题三:构建超时

错误信息:

1
Error: The job running you has run out of time

原因: npm 安装过慢或网络不稳定,导致超时。

解决方案:

  1. 启用 npm 缓存(cache: 'npm'
  2. 或使用国内镜像,在工作流中添加 .npmrc 配置:
1
2
3
4
5
6
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
registry: 'https://registry.npmmirror.com'

问题四:部署后页面 404

原因分析:

  1. GitHub Pages 源分支设置错误
  2. 仓库名称与访问路径不匹配

排查步骤:

1
2
3
4
5
# 检查 public 目录是否有内容
ls public/

# 确认 index.html 存在
test -f public/index.html && echo "index.html 存在"

解决方案:

  1. 在 Settings → Pages 中确认选择了 gh-pages 分支
  2. 如果仓库名不是 username.github.io,访问路径需要加上仓库名(如 https://username.github.io/blog/

问题五:文章时间显示错误

原因: Hexo 默认使用 UTC 时区,中国用户看到的文章时间会比实际晚 8 小时。

解决方案: 在 generate 步骤设置时区环境变量:

1
2
3
4
- name: Generate Site
run: npx hexo generate
env:
TZ: Asia/Shanghai

问题六:Actions 触发但没有任何变化

原因: Hexo generate 只在检测到源文件变化时才会重新生成内容。如果通过 API 修改文件但没有 flush 文件系统,Actions 可能检测不到变化。

解决方案: 确认每次修改后都执行了 git addgit commit,而不是直接用 API 写文件。

一键部署脚本

以下是一个完整的初始化脚本,可以快速配置 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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/bin/bash
# init-hexo-actions.sh - Hexo 博客 GitHub Actions 部署初始化

set -e

echo "开始初始化 Hexo + GitHub Actions 自动化部署..."

# 1. 检查必要文件
if [ ! -f "package.json" ]; then
echo "错误: 未找到 package.json,请在 Hexo 博客根目录执行此脚本"
exit 1
fi

# 2. 创建 GitHub Actions 配置目录
mkdir -p .github/workflows

# 3. 创建工作流文件
cat > .github/workflows/deploy.yml << 'EOF'
name: Deploy Hexo Blog

on:
push:
branches:
- main
workflow_dispatch:

permissions:
contents: read

jobs:
build-and-deploy:
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install Dependencies
run: npm ci

- name: Generate Site
run: npx hexo generate
env:
TZ: Asia/Shanghai

- name: Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"

- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
publish_branch: gh-pages
EOF

echo "✅ GitHub Actions 配置已创建: .github/workflows/deploy.yml"

# 4. 创建 CNAME 文件(可选)
read -p "是否配置自定义域名?(y/N): " use_domain
if [ "$use_domain" = "y" ]; then
read -p "请输入你的域名: " domain_name
echo "$domain_name" > source/CNAME
echo "✅ 已创建 source/CNAME"
fi

# 5. 提交并推送
git add .
git commit -m "chore: add GitHub Actions deployment workflow"
git push

echo ""
echo "✅ 初始化完成!"
echo "请在 GitHub 仓库 Settings → Pages 中启用 GitHub Pages"
echo "选择分支: gh-pages,目录: / (root)"
echo ""
echo "后续写作流程: 写文章 → git push → 自动发布"

使用方法:

1
2
chmod +x init-hexo-actions.sh
./init-hexo-actions.sh

总结

本文介绍了 Hexo 博客自动化发布的完整技术方案,核心要点包括:

  1. 架构设计:采用同一仓库多分支管理,源码在 main,构建产物在 gh-pages
  2. GitHub Actions 工作流:监听 push 事件 → npm ci → hexo generate → actions-gh-pages 自动部署
  3. 关键配置:submodules 递归克隆、npm 缓存加速、时区设置
  4. 进阶功能:构建失败通知、隐私扫描、服务器端验证
  5. 常见问题排查:submodule 克隆失败、构建超时、404 错误等

这套方案可以将博客发布从”每次手动操作”变成”push 即发布”,显著降低写作的心理成本,让人更专注于内容本身而非发布流程。


作者:小六,一个在上海努力搬砖的程序员

Author:Margrop
Link:http://blog.margrop.com/post/2026-04-03-hexo-ci-cd-automation/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可