背景
这次用 Docker 方式部署 Hugo 博客,避免在本地安装 Hugo 环境,同时支持热重载方便写作。本文记录从零开始到生产部署的完整过程。
环境信息
- 系统:macOS
- 博客目录:
/Users/xhsui/Library/CloudStorage/SynologyDrive-content/Hugo - 容器镜像:
hugomods/hugo:exts(支持 Sass/SCSS) - 主题:PaperMod
- 域名:<ADDRESS_INFO_REPLACED>
完整部署步骤
1. 设置环境变量
export HUGO_PATH="/Users/xhsui/Library/CloudStorage/SynologyDrive-content/Hugo"
2. 初始化 Hugo 站点
docker run --rm \
-v "${HUGO_PATH}:/src" \
hugomods/hugo:exts \
new site . --force
3. 安装主题(PaperMod)
cd "${HUGO_PATH}"
git clone https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod
4. 创建配置文件
创建 hugo.toml(注意:Hugo 0.110+ 推荐使用 .toml 格式):
baseURL = 'https://blog.xhsui.com/'
title = 'xhsui blog'
theme = 'PaperMod'
defaultContentLanguage = 'zh-cn'
enableInlineShortcodes = true
[params]
locale = 'zh-cn'
mainSections = ["tech", "health"]
showSummary = true
showReadingTime = true
ShowShareButtons = false
ShowPostNavLinks = true
ShowCodeCopyButtons = true
[params.homeInfoParams]
Title = "欢迎来到我的博客"
Content = "这里记录了我的技术学习和健康生活点滴。"
# 菜单配置
[menu]
[[menu.main]]
identifier = "tech"
name = "技术"
url = "/tech/"
weight = 10
[[menu.main]]
identifier = "health"
name = "健康"
url = "/health/"
weight = 20
[[menu.main]]
identifier = "tags"
name = "标签"
url = "/tags/"
weight = 30
[pagination]
pagerSize = 10
⚠️ 关键配置说明:
| 配置项 | 说明 |
|---|---|
defaultContentLanguage = 'zh-cn' |
语言代码必须全小写,否则 Hugo 会报错 |
mainSections = ["tech", "health"] |
告诉 PaperMod 在首页显示哪些 section |
baseURL |
生产环境用真实域名,本地开发用 http://localhost:1313/ |
5. 创建第一篇文章
docker run --rm \
-v "${HUGO_PATH}:/src" \
hugomods/hugo:exts \
new content/posts/hello-world.md
6. 修改文章状态(draft 改为 false)
sed -i '' 's/draft = true/draft = false/g' "${HUGO_PATH}/content/posts/"*.md
7. 启动容器(支持热重载)
# 删除旧容器(如果存在)
docker stop hugo 2>/dev/null
docker rm hugo 2>/dev/null
# 启动新容器
docker run -d \
--name hugo \
--restart unless-stopped \
-p 1313:1313 \
-v "${HUGO_PATH}:/src" \
hugomods/hugo:exts \
server --bind "0.0.0.0" --poll 1s --disableFastRender
8. 验证运行状态
docker logs hugo --tail 20
访问 http://localhost:1313 即可看到博客。
常用管理命令
| 操作 | 命令 |
|---|---|
| 查看日志 | docker logs hugo |
| 停止容器 | docker stop hugo |
| 启动容器 | docker start hugo |
| 重启容器 | docker restart hugo |
| 手动触发编译 | docker exec hugo hugo --quiet |
| 查看容器状态 | docker ps | grep hugo |
清理缓存
如果需要完全清理缓存重新生成:
# 停止并删除容器
docker stop hugo
docker rm hugo
# 清理缓存文件
rm -rf "${HUGO_PATH}/resources/_gen"
rm -rf "${HUGO_PATH}/.hugo_build.lock"
rm -rf "${HUGO_PATH}/public"
# 重新启动容器
docker run -d \
--name hugo \
--restart unless-stopped \
-p 1313:1313 \
-v "${HUGO_PATH}:/src" \
hugomods/hugo:exts \
server --bind "0.0.0.0" --poll 1s --disableFastRender
关键参数说明
| 参数 | 作用 |
|---|---|
-d |
后台运行 |
--name hugo |
容器命名为 hugo |
--restart unless-stopped |
自动重启(手动停止除外) |
-p 1313:1313 |
端口映射 |
-v |
目录挂载 |
--bind "0.0.0.0" |
允许外部访问 |
--poll 1s |
每秒轮询文件变化(适合云存储目录) |
--disableFastRender |
每次修改完整重新渲染 |
热重载说明
由于博客目录在云存储(SynologyDrive)上,文件变化通知可能不灵敏,使用 --poll 1s 参数让 Hugo 每秒主动扫描一次文件变化。
工作流程:
- 编辑
.md文章文件并保存 - 等待 1 秒
- 刷新浏览器即可看到变化
遇到的问题及解决
问题 1:找不到配置文件
报错: Unable to locate config file or config directory
解决: 需要先执行 new site . --force 初始化站点。
问题 2:文章不显示
原因: 新创建的文章默认 draft = true
解决: 将 draft 改为 false,或启动时加 -D 参数。
问题 3:删除 public 目录后页面 404
解决: 手动触发编译
docker exec hugo hugo --quiet
问题 4:容器名称冲突
报错: Conflict. The container name "/hugo" is already in use
解决: 先删除旧容器
docker stop hugo && docker rm hugo
问题 5:语言代码大小写错误
报错: language name "zh-CN" is invalid: must be all lower case
解决: 改为小写 zh-cn,并使用 defaultContentLanguage 代替 languageCode(新版本 Hugo)
defaultContentLanguage = 'zh-cn'
问题 6:首页不显示文章列表
原因: PaperMod 主题不知道要显示哪个 section 的文章
解决: 在 hugo.toml 中添加:
[params]
mainSections = ["tech", "health"]
问题 7:.bak 备份文件被 Hugo 当成内容处理
现象: public/ 目录中出现 xxx.md.bak/ 文件夹
解决: 删除所有 .bak 文件
find "${HUGO_PATH}/content" -name "*.bak" -type f -delete
问题 8:URL 中带有端口号(生产环境)
现象: 访问 https://blog.xhsui.com/tech/ 时,页面链接指向 https://blog.xhsui.com:1313/...
原因: hugo server 默认会在 URL 后附加端口号
解决方案 A(推荐):使用静态文件 + Nginx
# 构建静态文件
cd "${HUGO_PATH}"
hugo --minify
# 把 public/ 目录部署到服务器
# Nginx 直接托管静态文件
Nginx 配置示例:
server {
listen 443 ssl http2;
server_name blog.xhsui.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
root /path/to/hugo/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
解决方案 B:继续使用 hugo server + Nginx 反代
启动 Hugo 时添加 --appendPort=false 参数:
docker run -d \
--name hugo \
--restart unless-stopped \
-p 1313:1313 \
-v "${HUGO_PATH}:/src" \
hugomods/hugo:exts \
server --appendPort=false --baseURL https://blog.xhsui.com/ --bind "0.0.0.0" --poll 1s --disableFastRender
Nginx 反代配置:
location / {
proxy_pass http://127.0.0.1:1313;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
内容分类方案
方案选择:Section 分目录(推荐)
content/
├── tech/ ← 技术文章
│ ├── _index.md
│ └── *.md
└── health/ ← 健康记录
├── _index.md
└── *.md
优势:
- URL 结构自然:
/tech/、/health/ - Hugo 自动生成 section 页面
- 便于管理和扩展
实施步骤:
- 创建 section 目录:
mkdir -p "${HUGO_PATH}/content/tech"
mkdir -p "${HUGO_PATH}/content/health"
- 移动文章:
mv "${HUGO_PATH}/content/posts/"* "${HUGO_PATH}/content/tech/"
- 创建 section 首页:
---
date = '2026-06-07T00:00:00+08:00'
draft = false
title = '技术'
description = '技术学习笔记和教程'
---
- 更新
hugo.toml:
[params]
mainSections = ["tech", "health"]
- 给文章添加分类标签:
for f in "${HUGO_PATH}/content/tech/"*.md; do
sed -i '' '/draft = false/a\
categories = ["技术"]' "$f"
done
定时任务:自动生成健康日报
使用 WorkBuddy 的自动化任务,每天凌晨 3:00 自动生成健康日报并保存到 Hugo 目录:
任务配置:
- 名称:
diet-health-md-export - 执行时间: 每天 03:00
- 目标文件:
/Users/xhsui/Library/CloudStorage/SynologyDrive-content/Hugo/content/health/YYYY-MM-DD.md
生成的 Markdown 格式:
+++
date = "2026-06-07T03:00:00+08:00"
draft = false
title = "健康日报 - 2026-06-07"
categories = ["健康"]
+++
## 📊 今日总览
| 项目 | 实际值 | 目标值 | 完成度 |
|------|--------|--------|--------|
| 🔥 总摄入热量 | 1730 kcal | 1750 kcal | 99% ✅ |
...
好处:
- Hugo 自动渲染,访问
/health/即可看到所有健康记录 - 版本管理:所有健康数据都在 Git 中
- 隐私可控:可配合 Nginx 设置密码保护
总结
使用 Docker 部署 Hugo 博客的好处:
- ✅ 无需在本地安装 Hugo
- ✅ 环境一致性
- ✅ 支持热重载,写作体验流畅
- ✅ 自动重启,稳定可靠
- ✅ 配合 Nginx 反代,轻松实现生产部署
推荐的生产部署流程:
- 本地用
hugo server写作和预览 - 写完用
hugo --minify构建静态文件 - 把
public/目录同步到服务器 - Nginx 直接托管静态文件(性能最优)
以后写博客只需要:
- 编辑 Markdown 文件
- 保存
- 刷新浏览器
- 满意后运行
hugo --minify && rsync -avz public/ server:/path/to/blog/