在上一篇搭建Hugo网站中,我们完成了静态网站的搭建。为了实现网站的持续更新,这一篇我们来实现编写-上传-构建-部署的自动化流程
由于hugo的构建和部署是分开的,因此可行的思路非常开阔。笔者将提供几种思路以供参考
首先,不建议使用hugo server
部署至web端口或将web端口转发至hugo server
的方式。hugo server
仅为本地开发调试而设计,其默认行为不具备生产环境所需的安全性与性能优化
对博客的版本管理
无论使用什么方式,都建议对内容与配置进行版本管理。版本控制不仅有助于追踪修改历史、恢复误删内容,也便于多设备协作、自动化部署等操作。在本文我们使用git进行版本管理,其余的CVS工具可以使用类似的思路
在建立git仓库时,建议排除public/
(或者仓库目录中你规定的其他输出路径(你为什么要这么干))目录。.gitignore
中加入
public/
本地部署
如果你的web服务就部署在本地,那么每次编辑完后手动构建一次目标目录即可
远程部署
本地构建 + 上传构建文件(不推荐)
当然,你可以选择本地build完后,上传publc/
等输出仓库至服务器的方式。这也可以通过让git管理输出目录来完成上传的部分,思路和下文类似
本地上传修改 + 远程构建
先看需求:我们需要在完成编辑时,先将本地的修改上传,然后在远程自动触发一次构建,并且使用nginx等工具来运行web server。
能完成需求的思路都是好思路,这里提供两个
建立公共远程仓库,服务器同步并构建
graph LR A[本地] --push--> B(公共仓库) --pull--> C[Web Server] --build & run--> D([用户])
笔者选择的方式,因此这部分个人的经验会多一些
首先选择一个公共的远程仓库,需要你的本地和服务器都可以访问到。笔者的服务器位于中国大陆且不想配置代理,因此将仓库建立在了自己托管的git平台上。接下来在服务器建立仓库并添加远程,过程不再赘述。
WebServer从公共仓库的同步也可以采取多种思路。最简单的方式就是规定时间自动拉取。笔者采用了当公共仓库的主分支变动时,向服务器发送一个Webhook并触发拉取和构建的流程,笔者团队托管的gitea自带发送Webhook的功能,这部分也可以用其他平台的类似服务代替。
Webhook的客户端,可以使用apt库中的webhook
。为Webhook写一个配置文件,
// hooks.json
[
{
"id": "DFSiteHook",
"execute-command": "/home/dedfaf/DF-Site/build.sh",
"command-working-directory": "/var/www/DF-Site",
"response-message": "Hugo rebuild.",
"trigger-rule": {
"match": {
"type": "value",
"secret":"xxx",
"value": "refs/heads/master",
"parameter": {
"source": "payload",
"name": "ref"
}
}
}
}
]
令其接收到hooks后执行脚本
# build .sh
#!/bin/bash
# Auto pull and build hugo site when webhook is triggered.
set -e
REPO_DIR="/var/www/DF-Site"
HUGO_BIN="hugo"
cd "$REPO_DIR"
# echo "[`date`] pulling latest changes..."
# git pull
git fetch
git reset origin/master --hard
# echo "[`date`] building hugo site..."
"$HUGO_BIN"
# echo "[`date`] adjusting permissions..."
# chown -R www-data:www-data "$REPO_DIR/public"
为什么使用`git reset origin/master --hard`?
如果使用`git pull`,当公共仓库主分支和远程仓库的分支冲突时,就无法直接拉取,例如笔者有经常`commit --amend`并且强推的习惯,因此笔者使用这种方式。这一部分可以根据实际情况修改另:在实际操作中,建议为Webhook启用sercet并且为其配置反向代理和https。此处不再赘述
在服务器设置裸仓库直接上传
graph LR A[本地] --push--> C[Web Server] C -- 构建文件 --> C C --build & run--> D([用户])
笔者没有实操过这个思路,在这里仅简单讲解思路
什么是裸仓库:32.裸仓库| Git_Learning
总之需要知道普通仓库作为别的仓库的远程仓库因为存在工作区,推送会出现问题,因此服务器上只能建立裸仓库。而问题正是裸仓库没有工作区,因此需要在每次推送后执行一次构建工作区的操作,并以构建的工作区来构建网站。
首先建立好本地上传仓库和远程裸仓库,然后以ssh的方式为本地添加远程仓库。
我们在远程仓库设置一个post-receive
hook,编辑.git/hooks/post-receive
,参考如下内容
#!/bin/bash
set -e
TARGET="/var/www/myproject"
GIT_DIR="/var/git/myproject.git"
# 如果目录不存在,先创建
mkdir -p "$TARGET"
# 如果工作区已经是 git 仓库,强制同步;否则 clone 一份
if [ -d "$TARGET/.git" ]; then
echo "[INFO] Pulling latest changes into $TARGET"
git --work-tree="$TARGET" --git-dir="$GIT_DIR" checkout -f
else
echo "[INFO] Cloning into $TARGET"
git clone "$GIT_DIR" "$TARGET"
fi
# 可选:设置权限或执行构建
# chown -R www-data:www-data "$TARGET"
# 构建
cd "$TARGET"
hugo build
# echo "[DONE] Deployment finished"
记得赋予post-receive
执行权限。
另:如果你的主题是用submodule的方式加入的,那么构建工作区时默认不会下载子模块中的内容,可以在脚本的构建部分添加
# 构建
cd "$TARGET"
git submodule init
git submodule update --recursive --remote
hugo build