技术栈概览

本博客基于以下技术搭建:

组件 版本 / 说明
Hugo v0.146.0(通过 Docker 运行)
主题 PaperMod
构建工具 Docker(hugomods/hugo)
Web 服务器 Nginx(nginx:alpine)
HTTPS 自签名证书 / Let’s Encrypt

整体思路:Hugo 生成静态文件 → Nginx 提供访问服务,两者都跑在 Docker 容器里,无需在宿主机安装任何额外依赖。


一、环境准备

安装 Docker

# Ubuntu / Debian
curl -fsSL https://get.docker.com | sh

# 将当前用户加入 docker 组(避免每次 sudo)
sudo usermod -aG docker $USER
newgrp docker

# 验证安装
docker --version

克隆项目(或新建)

# 新建博客目录
mkdir -p /srv/blog && cd /srv/blog

# 初始化 git(可选)
git init

二、Hugo 项目初始化

由于使用 Docker 运行 Hugo,不需要在本机安装 Hugo 二进制。

# 使用 Docker 创建新站点
docker run --rm \
  -u "$(id -u):$(id -g)" \
  -v "$(pwd):/site" \
  hugomods/hugo:0.146.0 \
  hugo new site /site --force

项目结构如下:

b l o g / a c l s t n s p h r o a t h g c u u c n y a e i r b g h t o t m n i l o e e b g k p p u i e x p i . t n l a b a r t c s t c t y t r / g o s s o p g d e j m e / e s e l s n / c / / t s / # # # # # # # # # # # # # # N g i n & x M A f a b a r o v k u i d t c g o o i w n t n

三、安装 PaperMod 主题

# 使用 git submodule 方式安装(推荐,便于后续更新)
git submodule add --depth=1 \
  https://github.com/adityatelange/hugo-PaperMod.git \
  themes/PaperMod

# 如果已克隆仓库,需要初始化子模块
git submodule update --init --recursive

四、配置 hugo.toml

以下是本博客的核心配置,可按需调整:

baseURL = "https://your-server-ip/"
languageCode = "zh-cn"
title = "你的博客名"
theme = "PaperMod"
enableRobotsTXT = true
enableEmoji = true

# 分页
[pagination]
  pagerSize = 10

# 输出格式(搜索功能需要 JSON)
[outputs]
  home = ["HTML", "RSS", "JSON"]

[params]
  defaultTheme = "auto"          # auto / light / dark
  ShowReadingTime = true
  ShowWordCount = true
  ShowCodeCopyButtons = true
  ShowPostNavLinks = true
  ShowBreadCrumbs = true
  ShowToc = true
  TocOpen = false
  DateFormat = "2006-01-02"
  ShowLastMod = true
  author = "你的名字"
  description = "博客描述"

  # 搜索配置(Fuse.js)
  [params.fuseOpts]
    isCaseSensitive = false
    shouldSort = true
    threshold = 0.4
    keys = ["title", "permalink", "summary", "content"]

# 首页 Profile 模式
[params.profileMode]
  enabled = true
  title = "你的博客名"
  subtitle = "一句话简介"
  imageUrl = "/favicon.svg"
  imageWidth = 150
  imageHeight = 150

  [[params.profileMode.buttons]]
    name = "📝 博客"
    url = "/blog"

# 导航菜单
[[menu.main]]
  name = "📝 博客"
  url = "/blog/"
  weight = 10
[[menu.main]]
  name = "🔍 搜索"
  url = "/search/"
  weight = 5

五、创建内容页面

启用搜索页

新建 content/search.md

---
title: "搜索"
layout: "search"
summary: "search"
placeholder: "搜索文章..."
---

启用归档页

新建 content/archives.md

---
title: "归档"
layout: "archives"
url: "/archives/"
summary: archives
---

写第一篇文章

# 在 content/blog/ 下新建文章
cat > content/blog/hello.md << 'EOF'
---
title: "Hello World"
date: 2026-03-03
draft: false
tags: ["博客"]
categories: ["日志"]
summary: "第一篇博客文章。"
---

欢迎来到我的博客!
EOF

六、构建静态站点

构建脚本 scripts/build.sh

#!/bin/bash
set -e

PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_ROOT"

# 清理旧的构建锁
rm -f .hugo_build.lock

# 使用 Docker 构建
docker run --rm \
  -u "$(id -u):$(id -g)" \
  -v "$PROJECT_ROOT:/site" \
  hugomods/hugo:0.146.0 \
  hugo -s /site

echo "✅ 构建完成!静态文件位于 public/ 目录"

执行构建:

chmod +x scripts/build.sh
bash scripts/build.sh

构建产物输出到 public/ 目录,这就是最终要提供访问的静态文件。


七、Nginx 配置与部署

7.1 生成自签名 SSL 证书

mkdir -p nginx/ssl

openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout nginx/ssl/key.pem \
  -out nginx/ssl/cert.pem \
  -subj "/C=CN/ST=Beijing/L=Beijing/O=Personal/OU=Blog/CN=your-server-ip"

如果有正式域名,建议使用 Let’s Encrypt + certbot 获取免费证书。

7.2 Nginx 配置文件 nginx/default.conf

# HTTP → HTTPS 重定向
server {
  listen 80;
  server_name _;
  return 301 https://$host$request_uri;
}

# HTTPS 服务
server {
  listen 443 ssl http2;
  server_name _;

  ssl_certificate     /etc/nginx/ssl/cert.pem;
  ssl_certificate_key /etc/nginx/ssl/key.pem;
  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;
  ssl_session_timeout 10m;

  root /usr/share/nginx/html;
  index index.html;

  location / {
    try_files $uri $uri/ =404;
  }
}

7.3 启动 Nginx 容器

# 停止旧容器(如果存在)
docker stop blog-nginx 2>/dev/null || true
docker rm blog-nginx 2>/dev/null || true

# 启动新容器
docker run -d \
  --name blog-nginx \
  --restart unless-stopped \
  -p 80:80 \
  -p 443:443 \
  -v "$(pwd)/public:/usr/share/nginx/html:ro" \
  -v "$(pwd)/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro" \
  -v "$(pwd)/nginx/ssl:/etc/nginx/ssl:ro" \
  nginx:alpine

echo "✅ 博客已上线:https://your-server-ip"

八、日常写作工作流

每次写完新文章后,只需两步:

# 第一步:构建
bash scripts/build.sh

# 第二步:Nginx 自动读取新文件(无需重启容器)
# public/ 目录通过挂载卷共享,构建完成即生效

如果修改了 Nginx 配置,需要重载:

docker exec blog-nginx nginx -s reload

九、常见问题

文章不显示?

检查 front matter 中 draft 是否为 false

---
draft: false   # 必须为 false 才会发布
---

搜索功能不工作?

确认 hugo.tomloutputs 包含 JSON,且 content/search.md 存在且 layout: "search"

构建时文件权限问题?

Docker 构建时添加 -u "$(id -u):$(id -g)" 参数,确保生成的文件属于当前用户。

浏览器显示"不安全"?

使用了自签名证书,点击"高级 → 继续访问"即可。如需消除警告,请配置正式域名并申请 Let’s Encrypt 证书。


总结

本博客的整个技术链路非常轻量:

( M a r k d o w n ) H u g o ( D o c k e r ) ( p u b l i c / ) N g i n x ( D o c k e r )

无数据库、无后端、无复杂运维,适合个人在云服务器上低成本部署。如有问题欢迎留言交流!