这是一份面向小白的博客维护手册。你不需要理解 Hugo 的全部原理,只要按顺序操作,就可以发布文章、添加图片、修改首页诗句,并在出错时安全地停下来检查。

先记住最重要的三件事

这个博客没有 WordPress 后台,也不需要数据库。它由三部分组成:

  • Markdown:保存文章内容,文件名通常以 .md 结尾;
  • Hugo:读取文章、配置和模板,生成静态网页;
  • Nginx:把 Hugo 生成的 public 目录发布到 https://yuning.wang。

日常维护只有一条主线:

修改 Markdown 或配置文件
          ↓
在预览站检查效果
          ↓
运行 Hugo 正式构建
          ↓
打开 yuning.wang 验收

不要直接修改 public 里的 HTML。public 是 Hugo 自动生成的结果,下次构建时会被覆盖。

一、登录服务器并进入博客目录

打开 macOS 的“终端”,输入:

ssh ubuntu@yuning.wang

第一次连接时,如果终端询问是否信任主机,输入 yes 并按回车。

登录后进入博客目录:

cd /home/ubuntu/blog

确认位置:

pwd

正确输出应当是:

/home/ubuntu/blog

后文中的 Hugo 命令,除非特别说明,都应在这个目录运行。

二、最快发布一篇新文章

如果你只想尽快发布文章,完成这一章即可。其他章节可以等需要时再看。

2.1 决定文章地址

先为文章取一个简短的英文目录名。例如文章标题是“我的第一篇旅行记录”,可以使用:

my-first-trip

建议:

  • 只使用小写英文字母、数字和连字符 -;
  • 不使用空格、中文或下划线;
  • 尽量简短,并能表达文章内容;
  • 发布后尽量不要改目录名,否则文章地址也会改变。

最终地址会是:

https://yuning.wang/posts/my-first-trip/

2.2 让 Hugo 创建文章

运行:

hugo new posts/my-first-trip/index.md

Hugo 会创建:

content/posts/my-first-trip/
└── index.md

index.md 是文章正文。以后文章使用的图片也放在这个目录中。

2.3 编辑文章

使用 nano:

nano content/posts/my-first-trip/index.md

新文件大致如下:

---
title: "My First Trip"
date: 2026-07-19T18:00:00+08:00
categories:
  - 技术笔记
draft: true
---

在这里写文章摘要。

<!--more-->

在这里开始写正文。

两条 --- 之间叫 Front Matter,保存文章标题、日期、分类和草稿状态。

修改为自己的内容,例如:

---
title: "我的第一篇旅行记录"
date: 2026-07-19T18:00:00+08:00
categories:
  - 生活随想
draft: true
---

这是显示在首页文章列表里的简短摘要。

<!--more-->

## 出发之前

这里开始写完整正文。

重要字段:

字段作用
title网页上显示的文章标题
date发布时间,通常保持 Hugo 自动生成的值
categories文章分类,例如“技术笔记”或“生活随想”
drafttrue 是草稿,false 才会进入正式网站

<!--more--> 之前是首页摘要,之后是完整正文。摘要应当简短,不要把整篇文章都放在它前面。

2.4 保存文件

在 nano 中:

  1. 按 Control + O 保存;
  2. 按回车确认文件名;
  3. 按 Control + X 退出。

注意是 Control,不是 Command。

2.5 预览草稿

服务器上的预览服务会读取草稿,并将结果写入独立的 .preview-public,不会污染正式网站。

修改内容后可以重启预览服务:

systemctl --user restart hugo-preview.service

在自己电脑上另开一个终端窗口,建立安全通道:

ssh -N -L 8888:127.0.0.1:8888 ubuntu@yuning.wang

保持这个终端窗口不要关闭,然后用浏览器访问:

http://localhost:8888/posts/my-first-trip/

如果文章地址不存在,先确认目录名是否正确,并检查预览服务:

systemctl --user status hugo-preview.service

2.6 正式发布

确认预览无误后,再次编辑文章:

nano content/posts/my-first-trip/index.md

把:

draft: true

改为:

draft: false

保存退出,然后执行正式构建:

hugo --gc --minify --cleanDestinationDir --baseURL https://yuning.wang/

看到构建完成且没有 ERROR 后,打开:

https://yuning.wang/posts/my-first-trip/

也可以检查 HTTP 状态:

curl -I https://yuning.wang/posts/my-first-trip/

看到 HTTP/2 200 表示网页存在。

正常发布时不要先执行 rm -rf public。Nginx 通过 Docker 挂载这个目录,删除并重新创建目录可能让它暂时仍指向旧目录。上面的 Hugo 命令会安全地清理旧产物。

三、Markdown 常用写法

3.1 标题

文章主标题已经写在 Front Matter 的 title 中,正文一般从二级标题开始:

## 二级标题

### 三级标题

#### 四级标题

Hugo 会根据这些标题自动生成文章目录和锚点。修改标题后重新构建,目录也会自动更新。

本站默认显示目录。文章可单独设置:

ShowToc: true
TocOpen: false
  • ShowToc: true:显示目录;
  • ShowToc: false:隐藏目录;
  • TocOpen: true:默认展开;
  • TocOpen: false:默认折叠。

3.2 段落与换行

普通段落之间留一个空行:

这是第一段。

这是第二段。

不要依赖连续空格排版,也不要为了首行缩进手动输入许多空格。

3.3 粗体、斜体和删除线

这是 **粗体**。

这是 *斜体*。

这是 ~~删除线~~。

实际效果:这是 粗体,这是 斜体,这是 删除线。

3.4 链接

[访问 Hugo 官网](https://gohugo.io/)

实际效果:访问 Hugo 官网。

3.5 列表

无序列表:

- 第一项
- 第二项
  - 子项目

有序列表:

1. 第一步
2. 第二步
3. 第三步

任务列表:

- [x] 已完成
- [ ] 待完成

3.6 引用

> 小舟从此逝,江海寄余生。

实际效果:

小舟从此逝,江海寄余生。

3.7 分隔线

单独写三个短横线:

---

3.8 表格

| 项目 | 状态 |
|---|---|
| 写文章 | 完成 |
| 上传图片 | 进行中 |

实际效果:

项目状态
写文章完成
上传图片进行中

3.9 行内代码与代码块

行内代码用一对反引号:

运行 `hugo version` 查看版本。

多行代码使用三个反引号,并标注语言:

```python
message = "Hello, Hugo"
print(message)
```

实际效果:

message = "Hello, Hugo"
print(message)

代码很长时会出现横向滚动条,不会撑破页面。

四、给文章添加图片

4.1 图片放在哪里

一篇文章和它的图片放在同一目录:

content/posts/my-first-trip/
├── index.md
├── street.jpg
└── ticket.png

这样移动或备份文章时,不容易遗漏图片。

4.2 从自己的电脑上传图片

这条命令在自己的 Mac 终端运行,而不是在服务器 SSH 窗口运行:

scp ~/Desktop/street.jpg ubuntu@yuning.wang:/home/ubuntu/blog/content/posts/my-first-trip/

如果文件名包含空格,建议先改成简短英文名。

上传后,在服务器确认:

ls -lh /home/ubuntu/blog/content/posts/my-first-trip/

4.3 在文章中显示图片

![街道夜景](street.jpg)

方括号内是图片说明,圆括号内是文件名。文件名大小写必须与服务器文件完全一致。

本站标识图的真实示例:

![云兮努力学习的网站标识图](site-logo.png)

实际效果:

云兮努力学习的网站标识图

图片同时作为链接:

[![网站标识图](site-logo.png)](site-logo.png)

实际效果:

网站标识图

4.4 图片不显示时

依次检查:

  1. 图片是否真的位于文章目录;
  2. Markdown 文件名与真实文件名是否一致;
  3. 是否误用了自己电脑上的绝对路径;
  4. 是否重新运行了 Hugo 构建。

正式发布后可检查:

curl -I https://yuning.wang/posts/my-first-trip/street.jpg

五、维护首页随机诗句

首页标题下方的诗句来自:

data/quotes.yaml

它是一个本地配置文件,不请求第三方诗词 API。配置至少两句后,每次打开或刷新首页时,浏览器会随机选一句;如果只有一句,就固定显示这一句。页面停留期间不会轮播。

5.1 打开配置文件

在服务器博客目录运行:

nano data/quotes.yaml

当前结构如下:

- text: "小舟从此逝,江海寄余生。"
  author: "苏轼"
  source: "临江仙·夜归临皋"

- text: "凤箫声动,玉壶光转,一夜鱼龙舞。"
  author: "辛弃疾"
  source: "青玉案·元夕"

- text: "夜来幽梦忽还乡,小轩窗,正梳妆。"
  author: "苏轼"
  source: "江城子·乙卯正月二十日夜记梦"

字段含义:

字段作用
text首页显示的正文
author作者
source作品名,网页会自动加书名号

第一条诗句同时承担两个职责:

  • 正常情况下参与随机;
  • 如果浏览器禁用了 JavaScript,作为默认诗句显示。

5.2 增加一句诗

在文件末尾增加一个完整区块:

- text: "小舟从此逝,江海寄余生。"
  author: "苏轼"
  source: "临江仙·夜归临皋"

- text: "醉后不知天在水,满船清梦压星河。"
  author: "唐珙"
  source: "题龙阳县青草湖"

注意:

  • 每句从 - text: 开始;
  • author 和 source 前面有两个空格;
  • 三个值都建议使用英文双引号包裹;
  • 区块之间可以留一个空行;
  • 不要使用 Tab 缩进;
  • 作品名只写名称,不要自己加 《》,网页会自动添加。

保存后先重启预览服务:

systemctl --user restart hugo-preview.service

刷新 http://localhost:8888/ 数次,应当能看到不同诗句。

确认无误后正式构建:

hugo --gc --minify --cleanDestinationDir --baseURL https://yuning.wang/

再刷新 https://yuning.wang/ 验收。

5.3 修改或删除诗句

修改:直接编辑对应区块的文字。

删除:删除该诗句从 - text: 开始的整个区块,不要只删其中一行。

如果只保留一句,首页会固定显示这一句,不会报错;以后增加第二句后,随机功能会自动生效。

5.4 配置错误怎么办

先运行:

hugo --gc --minify --cleanDestinationDir --baseURL https://yuning.wang/

如果 YAML 缩进或引号有问题,Hugo 会停止构建并显示错误位置。此时:

  • 不要继续删除 public;
  • 不要重启 Nginx;
  • 回到 data/quotes.yaml 检查最近添加的区块;
  • 可以先删掉刚添加的区块,再重新构建。

Hugo 构建失败不会自动替换现有线上网页,因此先修配置即可。

六、修改已发布文章

找到对应源文件:

nano content/posts/my-first-trip/index.md

修改并保存后,先预览,再运行:

hugo --gc --minify --cleanDestinationDir --baseURL https://yuning.wang/

只修改 Markdown 而不重新构建,公网页面不会更新。

如果想暂时隐藏文章,把 draft 改回 true,然后重新构建。

如果希望页面显示最后修改时间,可在 Front Matter 中增加或更新:

lastmod: 2026-07-19T18:30:00+08:00

七、常见问题排查

7.1 构建成功,但首页没有新文章

检查文章是否仍是草稿,或者日期是否误写到了未来:

hugo list drafts
hugo list future

7.2 文章页面返回 404

确认目录名和访问地址一致:

find content/posts -maxdepth 2 -name index.md

然后重新构建。不要手动修改 public 中的 HTML。

7.3 Hugo 报 YAML 错误

常见原因:

  • 缩进不一致;
  • 漏掉双引号;
  • 使用了 Tab;
  • Front Matter 缺少开头或结尾的 ---;
  • 首页诗句没有从 - text: 开始。

优先检查最后一次修改的几行。

7.4 预览页没有更新

重启预览服务:

systemctl --user restart hugo-preview.service

检查状态:

systemctl --user status hugo-preview.service

确认本机 SSH 安全通道仍在运行,再强制刷新浏览器。

7.5 正式页面没有更新

确认运行的是正式构建命令:

hugo --gc --minify --cleanDestinationDir --baseURL https://yuning.wang/

macOS Chrome 可使用 Command + Shift + R 强制刷新。

7.6 首页或文章突然变成 403/404

不要反复删除文件。先确认 /home/ubuntu/blog/public/index.html 存在。

如果你曾手动删除整个 public 后重新创建,Docker 可能仍挂载旧目录。此时才需要:

cd /home/ubuntu/nginx
docker compose up -d --no-deps --force-recreate nginx
docker exec my-nginx nginx -t

正常的文章发布不需要执行这一步。

7.7 发布失败时怎么办

不要立刻重启所有容器,也不要删除整个博客目录。保留终端中的完整错误信息,检查刚修改的 Markdown 或 YAML。

Hugo 构建失败时,线上旧页面通常仍能继续访问。

八、发布前检查清单

新文章

  • 英文目录名简短,没有空格和中文;
  • title 是最终标题;
  • categories 分类正确;
  • 首页摘要位于 <!--more--> 之前;
  • 正文标题一般从 ## 开始;
  • 图片已上传,文件名完全一致;
  • 代码块标注了语言;
  • 预览页排版正常;
  • draft 已改为 false;
  • Hugo 正式构建没有 ERROR;
  • 正式文章地址返回 HTTP 200。

首页诗句

  • 每句都从 - text: 开始;
  • author 和 source 使用两个空格缩进;
  • 没有手动添加书名号;
  • 预览首页刷新多次没有异常;
  • 正式构建成功;
  • 正式首页能显示诗句和出处。

九、日常维护速查

创建文章:

cd /home/ubuntu/blog
hugo new posts/my-first-trip/index.md
nano content/posts/my-first-trip/index.md

维护首页诗句:

cd /home/ubuntu/blog
nano data/quotes.yaml

重启预览:

systemctl --user restart hugo-preview.service

正式发布:

hugo --gc --minify --cleanDestinationDir --baseURL https://yuning.wang/

最终可以把整个博客维护过程记成一句话:

修改源文件,预览确认,Hugo 构建,浏览器验收。