Hugo主题hugo-theme-stack部署记录
起因
冲浪过程中搜索Linux命令行使用mihomo内核的方法,结果发现一个宝藏博主:亂筆,观看多篇博文发现是一个技术与想法并存的有趣的人,收藏关注点赞三连之后发现博客主题不错,遂在页脚寻找主题信息,发现是使用Hugo的stack主题,没听过,去查了一下,这是它们各自官方的介绍:
Hugo is a static site generator written in Go, optimized for speed and designed for flexibility.
Hugo Theme Stack: Card-style Hugo theme designed for bloggers.
明白了,Go语言写的博客主题,看着不错,凭借去年折腾Halo主题的经验,想整一个这种纯静态的博客试试。先说一下对于一个已经有多个博客的人想折腾hugo主题的动机。
动机
- 我还没玩过静态blog
- 现在有很多SAAS公司提供静态网站托管,简言之就是可以白嫖
- 体验一下运维式的blog撰写过程
- 亂筆的高质量内容搭配这个主题让我很心动
开始
找到了这个主题的作者CaiJimmy,使用其推荐的Quick Start项目hugo-theme-stack-starter,但是部署完之后发现可能应该使用主主仓库的,这是后话,有时间再折腾主仓库的事。
- 点击右上方的
Use this template按钮,下拉列表中使用Create a new repository

- 创建一个新仓库页面,输入
Repository name,描述可写可不写,因为这个starter项目要把博文直接保存在仓库中,Choose visbility我选择了Private

- 创建
codespace。在仓库中找到我们刚才已经fork的项目,右上方位置,绿色的Code按钮,下拉菜单中选择创建codespace,稍作等待,会在新标签页中出来在线版本的vscode IDE

- 在线版本的
vs code长这样,和桌面版本也不差多少了。

- 在中间下方的TERMINAL中输入
hugo server进入预览界面,跑通之后点击Open in browser会在新标签页打开blog

Cloudflare部署
- 进入
cloudflare→Workers & Pages→Create application→Pages→Import an existing Git repository→Get started

- 绑定github账号,如果没有就根据提示绑定刚才
folk仓库的账号,然后选择对应仓库,如果没有发现仓库,请那就是没有允许cloudflare完全访问github账号,比如我,点击正文的连接进入github设置中将对应仓库的访问权限给cloudflare

- 下一步,
Set up builds and deployments中,有几个注意点,Framework preset选None,也可以选Hugo,没影响,Build command留空,Build output directory只输入.,点开Environment variables (advanced)加入两个参数,GO_VERSION和HUGO_VERSION,对应参数值分别为1.11和0.93.2,完工,Save and Deploy

- 等待
Deploy site完成,出现Success表示部署成功。

写博客
很好,现在可以开始写博客了。
让我们回到在线vscode这边,在文件目录中创建一个文件命名为:archetypes→post.md,在其中加入如下内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| ---
title: "{{ replace .Name "-" " " | title }}"
description: ""
date: {{ .Date }}
draft: false
categories:
- "xxxx"
tags:
- "tag1"
- "tag2"
toc: true
cover:
image: ""
alt: ""
caption: ""
author:
name: ""
---
|
这一步的目的是为了定制每次使用代码生成.md文档的front-matter也就是对应博文的属性。
现在就可以正式开始写博客了。
在TERMINAL中输入hugo new post/xxx/index.md创建新文件,可以看到已经自动生成了我们设置好的front-matter,在front-matter之后撰写博文。
写完之后的流程如下:
1
2
3
| git add .
git commit -m "xxxxx"
git push
|
因为作者已经在安排了自动化操作,我们不需要再执行其他操作,Github Action会自动编排将内容编排成静态网页,并且cloudflare也会自动部署新的一笔提交。
整合Artalk评论服务
我看一个博主说评论是一个博客的重要组成部分,我也认为评论是一个博客的活力来源的一部分。所以应该有评论服务。CaiJimmy这个项目默认使用Disqus这个东西,我也试着去注册了一下,但是直接看到用户协议里说了可以使用和出售用户信息,免费计划还有广告,我就吐了。想着换一个,正好亂筆目标博客使用的是Artalk,那我也效仿一下了。
首先,artalk是一个服务,查了一下是要部署在服务器的,而且因为要持久化评论内容还有数据库,那么,cloudflare应该是不能白嫖了,还有其他方法吗?有的,查了一下还有一个SAAS商家他们家可以在免费额度内白嫖,但是需要绑定信用卡防止滥用,它就是fly.io,付款方式我的选择的Google Play,经过测试bybit的虚拟信用卡是不可以的。
- 安装官方的CLI工具,我是windows还挺方便的
1
2
| # 使用Powershell终端执行就好了
pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"
|
- 登录
按照提示登录
3. 创建项目目录并发起launch
1
2
3
4
5
| # 创建并进入项目文件夹
mkdir my-artalk-server
cd my-artalk-server
# 启动程序,只生成配置文件但是不部署
fly launch --no-deploy
|
launch这一步会问要不要修改配置Do you want to tweak these settings before proceeding?,当然了,我们选y,之后会打开网页,让我们完成配置,非常的nice,选择最小号的x1型号的cpu和256m内存就行,毕竟是用免费的额度。完成配置之后文件夹中出现.toml格式的文件。
- 创建持久化存储卷,我选择的是
nrt也就是Japanese Tokyo
1
| fly volumes create artalk_data --size 1 --region <你选择的区域> --app <你刚才起的名字>
|
- 修改配置文件并部署
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| #根据自动生成的FLY.TOML文件修改
app = "artalk"
primary_region = "nrt"
[build]
image = "artalk/artalk-go"
[http_service]
internal_port = 23366
force_https = true
auto_stop_machines = true
auto_start_machines = true
min_machines_running = 0
processes = ["app"]
[[mounts]]
source = "artalk_data"
destination = "/data"
|
- 创建管理员账号与添加
Trusted Domain
在fly项目文件夹中,也就是和toml文件一个目录下使用终端执行
1
2
3
4
5
6
7
| # 进入容器内
flyctl ssh console
# 创建管理员账号
./artalk admin
# 按照提示创建管理员账号
# 重启服务
flctl apps restart
|
通过fly.io网页进入artalk后台,域名通常是https://app-name.fly.dev,使用上一步创建的管理员账号登录。添加站点,其中Site Name要记住,Site URLs就是cloudflare中访问hugo的网址。
并在设置中添加vs code的预览地址和实际访问地址到信任域名中:

- 整合进stack主题
创建
layouts→_default→single.html并写入
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
| {{ define "body-class" }}
article-page
{{/*
Enable the right sidebar if
- Widget different from 'TOC' is enabled
- TOC is enabled and not empty
*/}}
{{- $HasWidgetNotTOC := false -}}
{{- $TOCWidgetEnabled := false -}}
{{- range .Site.Params.widgets.page -}}
{{- if ne .type "toc" -}}
{{ $HasWidgetNotTOC = true -}}
{{- else -}}
{{ $TOCWidgetEnabled = true -}}
{{- end -}}
{{- end -}}
{{- $TOCManuallyDisabled := eq .Params.toc false -}}
{{- $TOCEnabled := and (not $TOCManuallyDisabled) $TOCWidgetEnabled -}}
{{- $hasTOC := ge (len .TableOfContents) 100 -}}
{{- .Scratch.Set "TOCEnabled" (and $TOCEnabled $hasTOC) -}}
{{- .Scratch.Set "hasWidget" (or $HasWidgetNotTOC (and $TOCEnabled $hasTOC)) -}}
{{ end }}
{{ define "main" }}
{{ partial "article/article.html" . }}
{{ if .Params.links }}
{{ partial "article/components/links" . }}
{{ end }}
{{ partial "article/components/related-content" . }}
{{ if not (eq .Params.comments false) }}
{{ partial "comments/include" . }}
{{ end }}
{{ partialCached "footer/footer" . }}
{{ partialCached "article/components/photoswipe" . }}
{{ end }}
{{ define "right-sidebar" }}
{{ if .Scratch.Get "hasWidget" }}{{ partial "sidebar/right.html" (dict "Context" . "Scope" "page") }}{{ end}}
{{ end }}
|
创建layouts→partials→comments→provider→artalk.html并写入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| <link href="{{ $.Site.Params.comments.artalk.server }}/dist/Artalk.css" rel="stylesheet">
<script src="{{ $.Site.Params.comments.artalk.server }}/dist/Artalk.js"></script>
<div id="Comments"></div>
<script>
const artalk = Artalk.init({
el: '#Comments',
pageKey: '{{ .Permalink }}',
pageTitle: '{{ .Title }}',
server: '{{ $.Site.Params.comments.artalk.server }}',
site: '{{ $.Site.Title }}',
locale: "auto"
})
window.addEventListener('onColorSchemeChange', (e) => {
if (e.detail === 'dark') {
artalk.setDarkMode(true)
} else {
artalk.setDarkMode(false)
}
})
</script>
|
修改config→_default→params.toml文件
1
2
3
4
5
6
7
8
9
| ## Comments
[comments]
enabled = true
provider = "artalk"
[comments.artalk]
server = "your-server-domains/ip"
site = "your-site-name" #要与第6步中的Site Name对应
nest = true
|
如果评论部分出现错误:Artalk Error应该是没把对应的域名加入Trusted Domain中。
实际效果展示

2025.11.13更新
之前设置的front-matter有点小问题,在我设置封面图的时候发现不管用,遂去翻了一下stack官方文档和hugo官方文档,重新贴一下更新后的模板。位置还是照旧:archetypes→post.md
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
| ---
# 文章标题 — 必填,Hugo 会用 .Title 方法访问
title: "{{ replace .Name "-" " " | title }}"
# 创建/发布日期 — 建议自动使用 .Date 模板变量
date: {{ .Date }}
# 最后修改日期 — 如果文章更新时手动修改,否则可与 date 相同或留空
lastmod: {{ .Date }}
# 真正发布时间(如果与 date 不同) — Hugo 的 PublishDate 方法访问。:contentReference[oaicite:3]{index=3}
publishDate: {{ .Date }}
# 到期/取消发布日期 — 如果文章在某日期后不再发布,可填;默认为空
expiryDate: ""
# 自定义链接尾部 slug — 覆盖默认 URL 的最后一段(Hugo 的 slug 方法使用):contentReference[oaicite:4]{index=4}
slug: ""
# 分类(categories) — 文章所属分类,使用数组格式
categories: []
# 标签(tags) — 文章标签,用于文章归类、检索
tags: []
# 描述/摘要 — 通常用于 meta 标签 description。:contentReference[oaicite:5]{index=5}
description: ""
# 预览或封面图片 — 主题特有字段(Stack 主题),也可用于 OpenGraph、Twitter 等
image: ""
# 是否开启评论 — 主题特有字段(Stack 主题)
comments: true
# 授权信息 — 主题特有字段
license: ""
# 是否启用数学公式(KaTeX) — 主题特有字段
math: false
# 是否显示目录(Table of Contents) — 主题特有字段
toc: true
# 是否显示阅读时间 — 主题特有字段
readingTime: true
# SEO 关键词 — Hugo 自身支持 keywords 字段。:contentReference[oaicite:6]{index=6}
keywords: []
# (可选)样式字段 — 主题特有,用于如 badge 背景色等
style: ""
# (推荐)是否草稿状态 — Hugo 的 draft 字段。若为 true 则不会发布,除非使用 --buildDrafts。:contentReference[oaicite:7]{index=7}
draft: true
# (推荐)文章是否置顶/特色 — 主题可能支持 featured 字段,可按需添加:
# featured: false
---
|
无注释版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| ---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
lastmod: {{ .Date }}
publishDate: {{ .Date }}
slug: ""
categories: []
tags: []
description: ""
image: ""
comments: true
license: ""
math: false
toc: true
readingTime: true
keywords: []
---
|