金秋麦粉化云裳
水火交融满室香
体态浑圆承万物
气味芬芳不思娘
以上是定场诗。
本文介绍将 Hugo 静态网站从GitHub私有仓库自动化部署到又拍云(Upyun)存储桶的方法。
C 缘起
我有两个网站,一个存在GitHub,另一个也存在GitHub~~

区别是,其中一个是私有仓库,部署到Cloudflare Pages,另一个部署到GitHub Pages (下称GHP)。部署到GHP这个仓库是被强制公开的,除非付费,付费是不可能的,这辈子都不会付费,所以就忍着这么用。但是这几天我实在忍不又折腾了。想了个办法停止使用GHP,搬家到又拍云。
整体工作流程是不变的:
除了将仓库恢复到私有之外,还有一个可能的收益:以前我是用国内域名CNAME给GHP套CDN的,而GHP时不时就被和谐,所以CDN回源的时候可能不见得稳定。现在改放在国内的桶,就不会有这个问题。
⚠️ 涉及到 API 密钥的操作请务必保密。继续阅读代表您认可您对自己的行为负有全部责任。⚠️
D 又拍云端的准备工作
首先你得有个又拍云账号,并且实名认证&备案(国内基操)。
存储桶与操作员
- 在控制台创建一个 云存储服务(其实就是存储桶)。
- 又拍云的程序还是蛮花心思的,创建桶的时候就可以创建一个专门的操作员。

静态网站配置
之后给桶绑定域名、开启强制SSL就好啦,就这么简单。

E 本地测试:UPX 工具
不嫌烦的话可以用他家这个控制台自己去上传内容。
在让GitHub Actions自动干活前,我得先在本地古法手作,测试一下。
从又拍云官方下载 upx 二进制文件。它解压出来就是一个孤零零的可执行文件。
安装
我不喜欢放在/usr/local/bin里,所以放自己的家目录。
1
2
3
4
5
6
|
mkdir -p ~/.local/bin
mv upx ~/.local/bin/
chmod +x ~/.local/bin/upx
# 别忘了把这路径加到.zshrc里
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc # 或者~/.bashrc
|
㊟ macOS 可能会跳弹窗说无法验证开发者。去系统设置 -> 隐私与安全性 帮它“仍要打开”一下。

可以登录试试,假如Hugo渲染好的文件夹在当前的public文件夹下:
1
2
3
4
5
|
upx -v
# 登录
upx login <服务名> <操作员> <密码>
# 同步测试
upx sync ./public/ /
|
F 正文:GitHub Actions自动化
GitHub Actions(下称GHA)的原理无非是启动一个虚拟机,做的事情和我在自己电脑上做的一样:渲染和上传。
密码
我们利用GitHub Secrets来存密钥。在仓库的 Settings -> Secrets and variables -> Actions 里新建三个 Repository secrets:
-
UPYUN_BUCKET
-
UPYUN_OPERATOR
-
UPYUN_PASSWORD

Workflows
去仓库编辑一个文件:.GitHub/workflows/foobar.y(a)ml
内容如下:(我这个是在原有GHP基础上改的)
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
90
91
92
|
name: Deploy Hugo site to Upyun
on:
push:
branches:
- main # 建议只在主分支触发,或者保留需要的其他分支
workflow_dispatch:
concurrency:
group: "pages"
cancel-in-progress: true
# 权限简化:不再需要写入 Pages 权限,只需要读取仓库内容
permissions:
contents: read
defaults:
run:
shell: bash
jobs:
# 任务一:渲染网页
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: 0.121.1
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 0
- name: Install Hugo CLI
run: |
wget -O ${{ runner.temp }}/hugo.deb https://GitHub.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
&& sudo dpkg -i ${{ runner.temp }}/hugo.deb
- name: Install Dart Sass
run: sudo snap install dart-sass
- name: Install Node.js dependencies
run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true"
- name: Build with Hugo
env:
HUGO_ENVIRONMENT: production
HUGO_ENV: production
run: |
hugo \
--gc \
--minify
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: hugo-site-data
path: ./public
# 任务二:部署到又拍云
deploy:
runs-on: ubuntu-latest
needs: build
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: hugo-site-data
path: ./public
- name: Install UPX (v0.4.9)
run: |
# 下载压缩包
curl -L https://GitHub.com/upyun/upx/releases/download/v0.4.9/upx_0.4.9_linux_amd64.tar.gz -o upx.tar.gz
# 解压
tar -xzf upx.tar.gz
# 文件夹里通常包含 upx 可执行文件,将其移动到系统路径
# 注意:解压后文件名可能是 upx,直接赋权并移动
chmod +x upx
sudo mv upx /usr/local/bin/
# 验证版本
upx -v
- name: Deploy to Upyun
env:
UP_BUCKET: ${{ secrets.UPYUN_BUCKET }}
UP_USER: ${{ secrets.UPYUN_OPERATOR }}
UP_PW: ${{ secrets.UPYUN_PASSWORD }}
run: |
upx login $UP_BUCKET $UP_USER $UP_PW
# --delete: 删除桶中存在但本地(runner)没有的文件
upx sync ./public/ / --delete
|
提交之后就可以坐等其成了。

至于费用么,因为没有人看,所以又拍云这边每天也花不了一分两分钱,人多的时候能花个一毛两毛的。GHA那边免费用户私有仓库的配额很受限,但是完成这个任务还是足够的。
以后每次写文章就提交到仓库就行了,方便快捷。好了,看过就等于会了,感谢朋友们观看,下次再见🥰