引言
架构设计
整体的发布流程简化为:本地 Push 源码 -> GitHub Actions 编译打包 -> 触发服务器 apiservice -> 解压并切换目录 -> 刷新 CDN。
在这个流程中,有几个需要处理的细节:
- 安全性: apiservice 接口直接暴露在公网上,需要通过 HMAC 算法对消息体进行签名。
- 平滑发布: 避免在部署期间出现 404,通过 Linux 软链接 (ln -sfn) 实现新老 Web 目录的原子替换。
- 缓存清理: 站点用了 EdgeOne,静态资源更新后如果不主动通知 EdgeOne 过期缓存会造成访问到旧资源。
实现步骤
服务器基础环境
为了遵循权限最小化原则,首先在服务器上为 apiservice 服务创建一个专用的非特权用户及目录:
1 | # 创建 apiservice 用户及相关目录 |
Web 服务器使用 Caddy,配置反向代理将 /api/deploy 路由转发给后端的 Python 服务,同时托管通过软链接指向的静态页面:
1 | api.sinkalex.ac.cn { |
Python 虚拟环境与依赖安装
为了不污染系统的全局 Python 环境,我们需要为 apiservice 服务单独创建一个虚拟环境(venv)。
1 | # 切换到 apiservice 用户 |
腾讯云 CAM 权限配置
由于部署完成后需要自动刷新 EdgeOne CDN 缓存,我们需要调用腾讯云 API。出于安全考虑,不要使用主账号的 API 密钥。
我们需要在腾讯云访问管理(CAM)中创建一个子账号:
- 新建用户,访问方式仅勾选 “编程访问”。
- 权限策略搜索并勾选 QcloudTEOFullAccess。
- 创建成功后,保存好生成的 SecretId 和 SecretKey。
[!NOTE]
在 /opt/webapp/apiservice/ 目录下创建 .env 文件,存入上述密钥以及自定义的 apiservice secret key。
同时将 .env 所有权转交给 apiservice,并将权限设为 600。
1 | nano /opt/webapp/apiservice/.env |
1 | ``` |
配置 Systemd 守护进程
为了让 apiservice 服务在后台稳定运行并支持开机自启,我们需要编写一个 systemd 服务单元。退出 apiservice 用户,回到拥有 sudo 权限的账号,创建文件 /etc/systemd/system/hexo-apiservice.service:
1 | [Unit] |
保存后,重载 systemd 并启动服务:
1 | sudo systemctl daemon-reload |
GitHub Actions 工作流配置
最后,在 Hexo 仓库根目录新建 .github/workflows/deploy.yml。这里的核心在于通过 Shell 脚本计算与服务端一致的 HMAC 签名,并将其放在 Header 中随文件一同发送。
需要在 GitHub 仓库的 Settings -> Secrets and variables -> Actions 中提前配好 DEPLOY_TOKEN(值与服务端的 SECRET_TOKEN 一致)。
1 | name: Deploy Hexo |

