Dorkytiger 的技术文档站(Hugo + PaperMod)
  • HTML 52.3%
  • CSS 27.5%
  • JavaScript 13%
  • Dockerfile 7.2%
Find a file
2026-09-18 18:04:58 +08:00
archetypes 初始化 Hugo 文档站:文档版式、首页与内容规范 2026-09-18 11:35:13 +08:00
assets 补上缺失的图标文件,并给文章开头的元信息补换行 2026-09-18 16:33:54 +08:00
content feat: 追加一加刷机教程 2026-09-18 18:04:58 +08:00
deploy 追加docker部署 2026-09-18 14:37:55 +08:00
layouts 修复文章内容被渲染两遍(页面重复 + 拉到底部跳回顶部) 2026-09-18 16:23:02 +08:00
static 补上缺失的图标文件,并给文章开头的元信息补换行 2026-09-18 16:33:54 +08:00
themes 初始化 Hugo 文档站:文档版式、首页与内容规范 2026-09-18 11:35:13 +08:00
.dockerignore 追加docker部署 2026-09-18 14:37:55 +08:00
.env.example 追加docker部署 2026-09-18 14:37:55 +08:00
.gitignore 追加docker部署 2026-09-18 14:37:55 +08:00
.gitmodules 初始化 Hugo 文档站:文档版式、首页与内容规范 2026-09-18 11:35:13 +08:00
docker-compose.yml 追加docker部署 2026-09-18 14:37:55 +08:00
Dockerfile 追加docker部署 2026-09-18 14:37:55 +08:00
hugo.toml 补上缺失的图标文件,并给文章开头的元信息补换行 2026-09-18 16:33:54 +08:00
README.md 文档:更新部署说明(容器内端口 8080、文件权限注意事项) 2026-09-18 14:56:53 +08:00

Dorkytiger 的小屋

个人技术文档站,用 Hugo + PaperMod 搭建。 文档版式(面包屑 + 左侧文档树 + 本页目录)是本仓库自己的模板,不依赖主题改动。

hugo server -D                     # 本地预览 http://localhost:1313
hugo                               # 构建到 public/
docker compose up -d --build       # 构建镜像并启动(推荐部署方式,见第八节)

⚠️ hugo server 会写 public/。 它的 baseURL 是 http://localhost:1313, 所以预览过一次之后,public/ 里的页面就带上 localhost 链接了 —— 如果你随后 把 public/ 传上服务器,线上就会出现「点 logo 跳到 localhost:1313」。

预览请用 hugo server -D --renderToMemory(只写内存,不碰 public/), 或者干脆用 Docker 部署,让构建只发生在镜像里。


---

## 一、内容结构

四级模型,目录名决定 URL:

content/ ├── _index.md 首页(hero + 专题卡片) ├── kotlin/ ① 顶层分类(= 页头导航项) │ ├── _index.md ⚠️ 必须带 cascade,见第三节 │ └── kotlin-benchmark/ ② 专题(一本书) │ ├── _index.md 专题首页(导言 + 自动章节卡片) │ ├── 00-introduction/ ③ 章 │ │ ├── _index.md 章首页(导言 + 自动小节卡片) │ │ └── 01-three-kinds-of-problems.md ④ 节 │ └── 01-metrics-and-slo/ └── c-plus-plus/ ├── _index.md └── c-plus-plus-concurrent-programming/ └── _index.md 单篇长文:专题本身即文章


**不要用 `README.md` 当章首页。** Hugo 只认 `_index.md`;`README.md` 会生成一个多余的
`/章目录/readme/` 页面。本仓库早期的 9 个 `README.md` 已全部改名。

**`_index.md` 就是索引页**,标题自动渲染、子页面自动列成卡片,不需要手写目录。

---

## 二、Front matter 约定

### 节 / 文章(普通 `.md`)

```yaml
---
title: "指标分四层,缺一层就无法定位"
weight: 2
---
字段 必填 说明
title 是 侧栏、面包屑、卡片都用它
weight 建议 排序。必须 ≥ 1:Hugo 把 weight: 0 当作"未设置"排在最后

章 / 专题首页(_index.md)

---
title: "指标与目标"                        # 侧栏和面包屑里的短标签
description: "一句话说明这个专题讲什么"     # 只有专题首页需要,显示在首页卡片上
weight: 2
---

命名与排序的关系

模板按文件名/目录名的数字前缀理解顺序,所以推荐:

00-introduction/     → weight 1
01-metrics-and-slo/  → weight 2
02-...

编号 NN 对应 weight: NN+1。如果你沿用数字前缀命名,其实可以不写 weight, 但显式写上更清楚。

⚠️ 不要出现 weight: 0,它会被排到最后。


三、新增内容怎么做

加一节(最常见)

在对应章目录下新建 NN-标题.md,照第二节写好 front matter。侧栏、面包屑、上下页 链接会自动出现,不需要动任何模板。

加一章

mkdir content/kotlin/kotlin-benchmark/10-new-chapter

在该目录建 _index.md(title + weight)和若干 NN-*.md。 章列表、首页卡片自动更新。

加一个专题

mkdir content/kotlin/new-book

建 content/kotlin/new-book/_index.md:

---
title: "新专题名"
description: "首页卡片上显示的一句话简介"
weight: 20
---

加一个顶层分类(C++ / Kotlin 这一层)

这一步有个必做的动作,否则新分类不会套用文档版式:

---
# content/rust/_index.md
title: "Rust"
cascade:
  type: docs        # ⚠️ 必需:让整棵树继承文档模板
---

cascade 写在分类根节点上而不是 hugo.toml 全局,是为了让首页保持博客版式。 页头导航会自动多出这一项(sectionPagesMenu)。


四、版式与自动化

需求 实现位置
面包屑(首页 / 分类 / 专题 / 章 / 文章) layouts/_partials/doc/breadcrumbs.html
左侧文档树(章节手风琴,只展开当前章) layouts/_partials/doc/tree.html
本页目录(h2/h3,滚动高亮) layouts/_partials/doc/toc.html + assets/js/docs.js
当前位置推导(书 / 章 / 文章) layouts/_partials/doc/path.html
导航短标签(去掉 1.2、第 3 章 · 前缀) layouts/_partials/doc/label.html
文章页 / 章节页版式 layouts/docs/single.html、layouts/docs/list.html
站内互链解析 layouts/_markup/render-link.html
样式(含首页) assets/css/extended/docs.css(PaperMod 自动合并此目录)

互链可以直接写相对路径,构建时会解析成真实 URL:

[1.2 百分位不可平均](02-percentiles-and-aggregation.md)
[第 4 章](../04-toolchain/README.md)          ← 旧的 README.md 写法仍兼容

解析不到的站内 .md 链接会渲染成灰色文字而不是死链。指向 ../../code/ 的配套代码 链接保留原始相对路径(见第七节)。

主题不要直接改。 themes/PaperMod 是 git submodule,所有定制都在项目根目录的 layouts/、assets/、static/ 里,通过 Hugo 的覆盖查找顺序生效。


五、首页

首页内容全部由页面树生成,加专题/章节后无需修改 layouts/index.html:

  • Hero:站点标题 + hugo.toml 的 [params] description + content/_index.md 正文
  • 左栏「全部文档」:顶层分类 → 专题,带页面数
  • 「文档专题」卡片:每个专题一张,显示层级、标题、description、章节 chips、页数

想让卡片更好看,就给专题 _index.md 补一句 description。


六、数学公式

已配置好,直接用 $...$ 和 $$...$$:

行内:平均并发数 $L = \lambda W$。

块级:
$$
W_q = \frac{\rho}{1-\rho} \cdot \frac{1}{\mu}
$$
  • KaTeX 资源已本地化在 static/vendor/katex/(608 KB,v0.16.11),不依赖 CDN
  • 只在内容里真的有公式的页面加载,其他页面零开销
  • hugo.toml 里的 goldmark.extensions.passthrough 负责保护 $x_1$、$\alpha$ 不被 markdown 解析器破坏

已知取舍:单 $ 是公式分隔符,所以正文里写价格要转义 —— \$5。 代码块内的 $ 不受影响。

想整体关掉公式:hugo.toml 里设 [params] math = false。


七、维护备忘

目录名和文件名一旦发布就不要改,它直接决定 URL。改名请用 aliases:

aliases: ["/kotlin/kotlin-benchmark/旧路径/"]

规模控制(超过这些数量就该考虑分层):

层级 建议上限
顶层分类 ~5
每类下专题 ~7
每专题章数 12–15
每章节数 ~15

配套代码链接:正文里约 180 处指向 ../../code/<章>/<文件>.md,那棵代码树不在本仓库。 如果要让这些链接可用,需在部署时把 code/ 目录一并放到站点根下,或后续把这些文档 并入 content/ 一起管理。

构建产物 public/ 已加入 .gitignore,不要提交。


八、部署(Docker)

站点在镜像里构建,宿主机上的 public/ 完全不参与部署。这是刻意的: 本机 hugo server 再也无法污染线上产物。

Dockerfile           两阶段:Hugo 构建 → nginx 托管(运行镜像里没有 Hugo/源码/主题)
docker-compose.yml   单服务,只读根文件系统,健康检查,日志轮转
deploy/nginx.conf    gzip、指纹资源长缓存、404 页、安全响应头
.dockerignore        排除 public/ .git/ 等
.env.example         宿主机绑定地址与端口

部署

cp .env.example .env        # 按需改 BIND_ADDR / BIND_PORT
docker compose up -d --build
docker compose logs -f

默认映射到宿主机的 127.0.0.1:8080(.env 里 BIND_PORT 可改),由宿主机的 反向代理(Nginx Proxy Manager / Caddy / Traefik)再转发到 dorkytiger.top。 若要让它在局域网直接可达,把 .env 里 BIND_ADDR 改成 0.0.0.0。

容器内部监听 8080 而非 80:容器以非 root 用户(uid 101)运行,绑定 1024 以下的端口需要额外 capability。反代指向宿主端口即可,无需关心容器内端口。

TLS 由宿主机或上游代理终止。如果你想让这个容器自己管证书,deploy/nginx.conf 末尾有一段注释好的 443 server 块,打开并挂载证书即可。

更新内容

git pull
docker compose up -d --build

改完内容必须 --build,否则跑的还是旧镜像。

验证镜像里的产物

# 应为 0
docker compose run --rm --entrypoint sh web \
  -c "grep -rl 'localhost:1313' /usr/share/nginx/html | wc -l"

注意事项

  • 克隆后要先拉主题:themes/PaperMod 是 git submodule,没拉的话镜像会构建失败 (Dockerfile 里有检查,会明确报错而不是产出一个没主题的站):
    git clone --recurse-submodules <repo>
    # 或已克隆过:
    git submodule update --init --recursive
    
  • baseURL 在构建期固化:hugo.toml 里的 baseURL 决定页面里的绝对链接 (canonical、logo、菜单)。换域名要改配置并重新 --build。
  • hugo server 不要用来产出部署文件,它写的 public/ 带 localhost 地址。 预览请加 --renderToMemory。
  • 文件权限:Dockerfile 会显式 chmod 644 配置类文件并 chmod -R a+rX 站点 目录。原因是 COPY 会保留构建上下文里的文件模式,而容器以 uid 101 运行 —— 若源文件是 600,nginx 会因读不到自己的配置而启动失败(Permission denied)。 另外站点的静态文件(content/、static/ 等)保持 644/755 更稳妥。