由于本博客之前还是手动部署,忍受一段时间后实在受不了了,还是开启了 CI/CD 日子~
实现:
1
| 本地写文章 → git push 到 GitHub → GitHub Actions 自动构建 Hugo → rsync 部署到服务器
|
推荐结构:
1
2
3
4
| GitHub 仓库:保存 Hugo 源码
GitHub Actions:负责构建 public/
deploy 用户:负责 SSH 登录和部署
www / www-data 用户:负责运行网站服务,例如 Nginx
|
一、服务器准备#
以 Debian / Ubuntu 为例,本文默认你已经安装了 nginx。
1. 安装依赖#
1
2
| sudo apt update
sudo apt install -y rsync
|
Hugo 可以在 GitHub Actions 里构建,所以服务器不需要安装 Hugo。
二、创建 deploy 用户#
不要使用 root 部署,也不建议让 www 用户登录 SSH。
1
| sudo useradd -m -s /bin/bash deploy
|
如果已经有 deploy 用户,可以检查:
最后一列应该类似:
如果是:
可以改成:
1
| sudo usermod -s /bin/bash deploy
|
三、网站目录权限配置#
假设网站目录是:
创建目录:
1
| sudo mkdir -p /var/www/blog
|
如果 Nginx 使用 www 用户:
1
2
3
4
| sudo usermod -aG www deploy
sudo chown -R www:www /var/www/blog
sudo chmod -R 775 /var/www/blog
sudo find /var/www/blog -type d -exec chmod g+s {} \;
|
1
2
| deploy 用户:可以写入 /var/www/blog
www 用户:可以读取网站文件
|
四、配置 SSH 密钥登录#
1. 本地生成部署密钥#
在本地电脑执行:
1
| ssh-keygen -t ed25519 -C "github-actions-hugo" -f github-actions-hugo
|
会生成:
1
2
| github-actions-hugo
github-actions-hugo.pub
|
其中:
1
2
| github-actions-hugo 私钥,放到 GitHub Secrets
github-actions-hugo.pub 公钥,放到服务器 deploy 用户
|
2. 把公钥注册到 deploy 用户#
在服务器上执行:
1
2
| sudo mkdir -p /home/deploy/.ssh
sudo cat github-actions-hugo.pub >> /home/deploy/.ssh/authorized_keys
|
把 github-actions-hugo.pub 的内容粘进去。
然后修复权限:
1
2
3
| sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
|
3. 本地测试 SSH#
1
| ssh -i ./github-actions-hugo deploy@你的服务器IP
|
如果可以登录,说明密钥配置成功。
如果报错类似:
1
2
| Permission denied
未注册用户密钥
|
通常是:
1
2
3
4
5
| 公钥没有放到 /home/deploy/.ssh/authorized_keys
authorized_keys 权限不对
.ssh 目录权限不对
文件归属不是 deploy:deploy
登录用户写错
|
五、配置 GitHub Secrets#
进入 GitHub 仓库:
1
| Settings → Secrets and variables → Actions → New repository secret
|
添加:
1
2
3
4
| SERVER_HOST=你的服务器IP或域名
SERVER_USER=deploy
SERVER_SSH_KEY=私钥内容
SERVER_PATH=/var/www/blog
|
六、添加 GitHub Actions 配置#
在 Hugo 仓库中新建文件:
1
| .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
| name: Deploy Hugo Blog
on:
push:
branches:
- main
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Hugo
uses: peaceiris/actions-hugo@v3
with:
hugo-version: latest
extended: true
- name: Build
run: hugo --minify --cleanDestinationDir
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SERVER_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H "${{ secrets.SERVER_HOST }}" >> ~/.ssh/known_hosts
- name: Test SSH connection
run: |
ssh -o ConnectTimeout=20 -i ~/.ssh/deploy_key \
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }} \
"echo connected"
- name: Deploy with rsync
run: |
rsync -rlvz --delete \
-e "ssh -i ~/.ssh/deploy_key" \
public/ \
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ secrets.SERVER_PATH }}/
|
ps: 如果是宝塔,记得在最后一栏 rsync -rlvz --delete 内添加排查.user.ini,否则会提示运行失败。
1
2
3
4
5
| - name: Deploy with rsync
run: |
rsync -rlvz --delete \
--exclude='.user.ini' \
.......
|
如果服务器 SSH 非 22 端口#
假设 SSH 端口是 2222,修改 rsync:
1
2
3
4
| rsync -avz --delete \
-e "ssh -i ~/.ssh/deploy_key -p 2222" \
public/ \
${{ secrets.SERVER_USER }}@${{ secrets.SERVER_HOST }}:${{ secrets.SERVER_PATH }}/
|
七、可选:限制 deploy 用户只能 rsync 到指定目录#
如果不想让 deploy 用户正常登录 shell,可以使用 rrsync 限制它只能访问 /var/www/blog。
安装:
1
| sudo apt install -y rrsync
|
查看路径:
通常是:
编辑 deploy 的 authorized_keys:
1
| sudo nano /home/deploy/.ssh/authorized_keys
|
把原来的公钥:
1
| ssh-ed25519 AAAA... github-actions-hugo
|
改成:
1
| command="/usr/bin/rrsync /var/www/blog",no-agent-forwarding,no-port-forwarding,no-pty,no-X11-forwarding ssh-ed25519 AAAA... github-actions-hugo
|
这样这个密钥只能用于 rsync 部署,不能打开交互式 SSH 终端。
八、发布文章流程#
以后只需要:
1
2
3
| git add .
git commit -m "new post"
git push origin main
|
GitHub Actions 会自动:
1
2
3
4
5
6
| 1. 拉取 Hugo 源码
2. 安装 Hugo
3. 构建 public/
4. 通过 SSH 连接服务器
5. 用 rsync 同步 public/ 到 /var/www/blog
6. 网站自动更新
|
九、常见错误排查#
1. SSH 超时#
错误:
1
2
| ssh: connect to host xxx port 22: Connection timed out
rsync error: unexplained error (code 255)
|
原因通常是:
1
2
3
4
5
| 服务器防火墙没开放 22
云服务器安全组没开放 22
SSH 端口不是 22
SERVER_HOST 填错
服务器只允许特定 IP 登录
|
检查服务器防火墙:
1
2
3
| sudo ufw status
sudo ufw allow 22/tcp
sudo ufw reload
|
云服务器还要检查控制台安全组,开放:
2. 密钥未注册 / Permission denied#
原因通常是 deploy 用户没有配置公钥。
修复:
1
2
3
4
5
| sudo mkdir -p /home/deploy/.ssh
sudo nano /home/deploy/.ssh/authorized_keys
sudo chown -R deploy:deploy /home/deploy/.ssh
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
|
3. deploy 无法写入网站目录#
检查权限:
如果 Nginx 用户是 www-data:
1
2
3
4
| sudo usermod -aG www-data deploy
sudo chown -R www-data:www-data /var/www/blog
sudo chmod -R 775 /var/www/blog
sudo find /var/www/blog -type d -exec chmod g+s {} \;
|
4. Hugo 主题没有被拉下来#
如果主题使用 Git submodule,确保 workflow 里有:
1
2
| with:
submodules: recursive
|
5. Hugo 主题需要 extended 版本#
很多主题需要 Hugo Extended,确保: