Featured image of post 我的第一篇 Stack 博客文章

我的第一篇 Stack 博客文章

记录使用 Hugo、Stack 和 Nginx 搭建博客的过程

Hugo + Stack + Nginx 网站配置教程

适用环境:Ubuntu amd64 服务器。
配置版本:Hugo Extended 0.169.0、Stack v4.0.3。
维护用户:bloguser。
示例域名:www.novalshared.work。
示例公网 IP:8.137.156.232。
整理日期:2026-11-07。

本文包含安装、主题配置、文章管理、静态发布、Nginx、HTTPS,以及可选的 IP 访问配置。所有域名、IP、用户资料均应替换为实际值。

现有下载站继续使用原有的 download.conf、Flask 和 /srv/downloads/;博客使用独立目录和 Nginx 配置。

目录

  1. 目录规划
  2. 准备用户与基础环境
  3. 安装 Hugo Extended
  4. 创建项目并安装 Stack
  5. 配置 hugo.toml
  6. 创建文章与图片
  7. 创建归档、搜索与关于页面
  8. 配置头像与自定义样式
  9. 通过 SSH 预览
  10. 配置正式发布
  11. 配置 Nginx HTTP 站点
  12. 配置域名与 HTTPS
  13. 配置证书自动续期
  14. 更新网站内容
  15. 可选:配置公网 IP 访问
  16. 可选:移除 IP 访问配置
  17. 版本管理与备份
  18. 最终目录结构

1. 目录规划

用途路径
博客源项目/home/bloguser/sites/personal-blog-stack/
Hugo 配置文件/home/bloguser/sites/personal-blog-stack/hugo.toml
文章目录/home/bloguser/sites/personal-blog-stack/content/post/
独立页面目录/home/bloguser/sites/personal-blog-stack/content/page/
Stack 主题目录/home/bloguser/sites/personal-blog-stack/themes/hugo-theme-stack/
正式静态网页/var/www/personal-blog/
证书验证目录/var/www/certbot/
博客 Nginx 配置/etc/nginx/conf.d/blog.conf
原下载站 Nginx 配置/etc/nginx/conf.d/download.conf

源文件由普通用户维护,Nginx 只读取正式发布目录中的静态网页。

2. 准备用户与基础环境

2.1 创建维护用户

如果尚未创建 bloguser,使用 root 或管理员账号执行:

1
sudo adduser bloguser

根据提示设置密码和用户信息。

如果该用户需要负责软件安装、Nginx 和证书管理,管理员执行:

1
sudo usermod -aG sudo bloguser

使用 root 直接操作时,省略命令开头的 sudo。组权限调整后,重新登录 bloguser。

如果不授予该用户管理权限,本文带 sudo 的步骤由管理员执行,其余步骤由 bloguser 执行。

2.2 登录并确认环境

从自己的电脑登录服务器:

1
ssh bloguser@8.137.156.232

确认账号、家目录和架构:

1
2
3
whoami
echo "$HOME"
dpkg --print-architecture

对应结果应为 bloguser、/home/bloguser 和 amd64。

2.3 安装基础工具

1
2
sudo apt update
sudo apt install -y ca-certificates curl git rsync nano

如果服务器尚未安装 Nginx:

1
2
sudo apt install -y nginx
sudo systemctl enable --now nginx

检查 Nginx 配置:

1
sudo nginx -t

3. 安装 Hugo Extended

本文使用官方提供的 Linux amd64 Extended deb 包。

3.1 下载软件包

以 bloguser 执行:

1
2
3
4
5
6
mkdir -p /home/bloguser/packages
cd /home/bloguser/packages

curl -fL \
  https://github.com/gohugoio/hugo/releases/download/v0.169.0/hugo_extended_0.169.0_linux-amd64.deb \
  -o hugo_extended_0.169.0_linux-amd64.deb

3.2 校验安装包

1
2
echo "a20f7da84e0981bebbecc032cc87f0dda2049a844727720aab14e61ce416e5e9  hugo_extended_0.169.0_linux-amd64.deb" \
  | sha256sum -c -

校验结果应为 OK。

3.3 安装

1
2
3
4
sudo cp hugo_extended_0.169.0_linux-amd64.deb /tmp/
sudo chmod 644 /tmp/hugo_extended_0.169.0_linux-amd64.deb
sudo apt install -y /tmp/hugo_extended_0.169.0_linux-amd64.deb
hash -r

3.4 确认版本

1
2
command -v hugo
hugo version

版本信息应包含 v0.169.0、extended 和 linux/amd64。后续使用普通用户运行 Hugo。

4. 创建项目并安装 Stack

以下命令以 bloguser 执行。

4.1 创建项目

1
2
3
4
5
6
7
mkdir -p /home/bloguser/sites
cd /home/bloguser/sites

hugo new project personal-blog-stack
cd personal-blog-stack

mkdir -p content/post content/page

4.2 安装主题并固定版本

1
2
3
4
5
6
7
git init

git submodule add \
  https://github.com/CaiJimmy/hugo-theme-stack.git \
  themes/hugo-theme-stack

git -C themes/hugo-theme-stack checkout v4.0.3

确认主题版本:

1
git -C themes/hugo-theme-stack describe --tags --exact-match

输出应为 v4.0.3。

本教程使用 Git 子模块方式安装主题,无需配置 Hugo Modules 或额外安装 Go。

5. 配置 hugo.toml

编辑:

1
nano /home/bloguser/sites/personal-blog-stack/hugo.toml

将文件内容整体替换为:

  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
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# 网站基本信息
baseURL = "https://www.novalshared.work/"
title = "我的个人技术博客"
theme = "hugo-theme-stack"

locale = "zh"
defaultContentLanguage = "zh"
hasCJKLanguage = true
timeZone = "Asia/Shanghai"

enableRobotsTXT = true

# 分页
[pagination]
pagerSize = 10

# 分类与标签
[taxonomies]
category = "categories"
tag = "tags"

# 页面地址
[permalinks]
post = "/p/:slug/"
page = "/:slug/"

# 代码高亮与目录
[markup.highlight]
noClasses = false
codeFences = true
guessSyntax = false
lineNos = true
lineNumbersInTable = true
tabWidth = 4

[markup.tableOfContents]
startLevel = 2
endLevel = 4
ordered = false

# 首页导航
[[menus.main]]
name = "首页"
url = "/"
weight = 10

[menus.main.params]
icon = "home"

# Stack 参数
[params]
mainSections = ["post"]
rssFullContent = true

[params.footer]
since = 2026
customText = ""

[params.dateFormat]
published = "2006-01-02"
lastUpdated = "2006-01-02"

[params.sidebar]
compact = false
subtitle = "记录 Linux 运维、编程学习与个人实践"
avatar = ""

[params.article]
headingAnchor = true
math = false
toc = true
readingTime = true

[params.article.list]
showTags = true

[params.article.license]
enabled = false

[params.comments]
enabled = false

[params.colorScheme]
toggle = true
default = "auto"

[params.imageProcessing.content]
enabled = true

[params.imageProcessing.thumbnail]
enabled = true

# 首页右侧组件
[[params.widgets.homepage]]
type = "search"

[[params.widgets.homepage]]
type = "archives"

[params.widgets.homepage.params]
limit = 5

[[params.widgets.homepage]]
type = "categories"

[params.widgets.homepage.params]
limit = 10

[[params.widgets.homepage]]
type = "tag-cloud"

[params.widgets.homepage.params]
limit = 20

# 文章右侧目录
[[params.widgets.page]]
type = "toc"

配置约定:

  • baseURL 使用正式域名,保留末尾 /。
  • Stack v4 简体中文语言标识使用 zh。
  • 文章统一存放在 content/post/,与 mainSections = ["post"] 对应。
  • 头像尚未上传时,保留 avatar = ""。
  • 所有字符串使用英文半角引号,配置文件使用 UTF-8 编码。

检查配置:

1
2
cd /home/bloguser/sites/personal-blog-stack
hugo config >/dev/null && echo "配置解析成功"

6. 创建文章与图片

每篇文章使用独立文件夹,将正文与相关图片放在一起。

6.1 创建第一篇文章

1
2
3
cd /home/bloguser/sites/personal-blog-stack
hugo new content post/hello-stack/index.md
nano content/post/hello-stack/index.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
+++
title = "我的第一篇 Stack 博客文章"
description = "记录使用 Hugo、Stack 和 Nginx 搭建博客的过程"
date = 2026-11-07T10:00:00+08:00
slug = "hello-stack"
draft = false
categories = ["技术笔记"]
tags = ["Hugo", "Nginx", "Linux"]
toc = true
+++

欢迎来到我的个人博客。

## 关于本站

本站使用 Hugo 生成静态网页,通过 Nginx 对外提供访问。

## 记录内容

- Linux 运维实践
- Java 学习笔记
- 网站部署经验
- 个人项目开发

## 接下来的计划

持续更新文章,记录学习与实践过程。

文章日期按实际发布时间填写。draft = false 表示正式文章,draft = true 表示草稿。

6.2 添加封面

将封面图片放在:

1
content/post/hello-stack/cover.jpg

在文章开头的 +++ 区域中添加:

1
image = "cover.jpg"

6.3 添加正文图片

将图片放在同一文章目录:

1
content/post/hello-stack/screenshot.png

在正文中引用:

1
![网站运行截图](screenshot.png)

对应结构:

1
2
3
4
content/post/hello-stack/
├── index.md
├── cover.jpg
└── screenshot.png

图片引用使用资源路径,文件名大小写与实际文件保持一致。

6.4 从 Windows 上传图片

在自己电脑的 PowerShell 中执行,替换本地图片路径:

1
scp "C:\Users\你的用户名\Pictures\cover.jpg" bloguser@8.137.156.232:/home/bloguser/sites/personal-blog-stack/content/post/hello-stack/

7. 创建归档、搜索与关于页面

7.1 创建目录

1
2
3
4
5
cd /home/bloguser/sites/personal-blog-stack

mkdir -p content/page/archives
mkdir -p content/page/search
mkdir -p content/page/about

7.2 归档页面

编辑:

1
nano content/page/archives/index.md

写入:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
+++
title = "归档"
slug = "archives"
layout = "archives"

[menu.main]
weight = 20

[menu.main.params]
icon = "archives"
+++

7.3 搜索页面

编辑:

1
nano content/page/search/index.md

写入:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
+++
title = "搜索"
slug = "search"
layout = "search"
outputs = ["HTML", "JSON"]

[menu.main]
weight = 30

[menu.main.params]
icon = "search"
+++

7.4 关于页面

编辑:

1
nano content/page/about/index.md

写入:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
+++
title = "关于"
slug = "about"
description = "关于这个博客"
toc = false

[menu.main]
weight = 40

[menu.main.params]
icon = "user"
+++

## 关于我

这里记录我的技术学习与实践。

## 关于博客

使用 Hugo、Stack 和 Nginx 搭建。

主要分享 Linux 运维、编程学习和个人项目经验。

7.5 构建检查

1
2
3
4
5
6
7
8
hugo --minify

ls -l public/index.html
ls -l public/p/hello-stack/index.html
ls -l public/archives/index.html
ls -l public/search/index.html
ls -l public/search/index.json
ls -l public/about/index.html

8. 配置头像与自定义样式

8.1 头像

创建资源目录:

1
mkdir -p /home/bloguser/sites/personal-blog-stack/assets/img

将头像上传为:

1
assets/img/avatar.jpg

修改 hugo.toml 中现有的 [params.sidebar]:

1
2
3
4
[params.sidebar]
compact = false
subtitle = "记录 Linux 运维、编程学习与个人实践"
avatar = "img/avatar.jpg"

8.2 自定义样式

1
2
mkdir -p /home/bloguser/sites/personal-blog-stack/assets/scss
nano /home/bloguser/sites/personal-blog-stack/assets/scss/custom.scss

例如设置正文行高:

1
2
3
.article-content {
    line-height: 1.9;
}

自定义样式放在项目的 assets/scss/custom.scss 中。

9. 通过 SSH 预览

9.1 在 Windows 建立 SSH 隧道

在自己电脑的 PowerShell 中执行:

1
ssh -L 1313:127.0.0.1:1313 bloguser@8.137.156.232

9.2 在该 SSH 会话启动 Hugo

1
2
3
4
5
6
7
8
cd /home/bloguser/sites/personal-blog-stack

hugo server \
  -D \
  --bind 127.0.0.1 \
  --port 1313 \
  --baseURL http://localhost:1313/ \
  --appendPort=false

在自己电脑浏览器打开:

1
http://localhost:1313/

预览期间保持 SSH 会话和 Hugo 运行,结束时按 Ctrl + C。此方式不需要在云安全组开放 1313 端口。

-D 包含草稿;正式发布时不使用该参数。

10. 配置正式发布

10.1 创建发布目录

管理员执行:

1
2
3
sudo mkdir -p /var/www/personal-blog
sudo chown bloguser:bloguser /var/www/personal-blog
sudo chmod 755 /var/www/personal-blog

该目录专用于博客。后面的同步操作会使其内容与构建结果一致,包括移除已下线的页面。

10.2 创建发布脚本

以 bloguser 编辑:

1
nano /home/bloguser/sites/personal-blog-stack/publish.sh

写入:

 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
#!/usr/bin/env bash
set -euo pipefail

site_dir="/home/bloguser/sites/personal-blog-stack"
publish_dir="/var/www/personal-blog"

cd "$site_dir"

# 使用全新目录生成本次发布文件
build_dir="$(mktemp -d "$site_dir/.build.XXXXXXXX")"

cleanup() {
    case "$build_dir" in
        "$site_dir"/.build.*)
            if [ -d "$build_dir" ] && [ ! -L "$build_dir" ]; then
                rm -r -- "$build_dir"
            fi
            ;;
    esac
}

trap cleanup EXIT

echo "正在构建网站……"

hugo \
  --environment production \
  --minify \
  --destination "$build_dir"

test -s "$build_dir/index.html"
test -s "$build_dir/search/index.json"

if [ ! -d "$publish_dir" ] || [ ! -w "$publish_dir" ]; then
    echo "发布目录不存在或当前用户无写入权限:$publish_dir"
    exit 1
fi

echo "正在同步网站……"

rsync -av --delete \
  "$build_dir/" \
  "$publish_dir/"

chmod -R a+rX "$publish_dir"

echo "发布完成:https://www.novalshared.work/"

授予执行权限:

1
chmod +x /home/bloguser/sites/personal-blog-stack/publish.sh

10.3 发布网站

1
2
cd /home/bloguser/sites/personal-blog-stack
./publish.sh

只更新文章或静态资源时,无需重新加载 Nginx。

11. 配置 Nginx HTTP 站点

11.1 创建证书验证目录

1
2
sudo mkdir -p /var/www/certbot/.well-known/acme-challenge
sudo chmod -R a+rX /var/www/certbot

11.2 创建独立博客配置

1
sudo nano /etc/nginx/conf.d/blog.conf

写入:

 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
server {
    listen 80;
    listen [::]:80;

    server_name www.novalshared.work;

    root /var/www/personal-blog;
    index index.html;
    charset utf-8;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
        default_type text/plain;
        auth_basic off;
        allow all;
        try_files $uri =404;
    }

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

    location ~ /\. {
        deny all;
    }

    error_page 404 /404.html;

    access_log /var/log/nginx/blog_access.log;
    error_log /var/log/nginx/blog_error.log;
}

检查并加载:

1
sudo nginx -t && sudo systemctl reload nginx

11.3 测试虚拟主机

1
2
3
curl -I \
  -H "Host: www.novalshared.work" \
  http://127.0.0.1/

预期返回 HTTP/1.1 200 OK。

12. 配置域名与 HTTPS

12.1 配置 DNS 与公网端口

在域名 DNS 控制台添加:

类型主机记录记录值
Awww8.137.156.232,替换为实际公网 IPv4

保留原有下载站记录。只有在服务器已配置可用 IPv6 时,才添加对应的 AAAA 记录。

在云安全组和系统防火墙中允许博客所需的 TCP 80、443 端口,并保留现有 SSH 管理规则。

确认解析:

1
getent ahostsv4 www.novalshared.work

公网开放按服务器接入商的要求办理;HTTP 证书验证需要公网能够访问该站点。

12.2 测试证书验证路径

创建测试文件:

1
2
echo "acme-test" | sudo tee \
  /var/www/certbot/.well-known/acme-challenge/test.txt

在服务器测试:

1
2
3
curl -i \
  -H "Host: www.novalshared.work" \
  http://127.0.0.1/.well-known/acme-challenge/test.txt

在自己的 Windows 电脑测试:

1
curl.exe -i http://www.novalshared.work/.well-known/acme-challenge/test.txt

确认返回 200 OK,正文为 acme-test 后申请证书。

12.3 安装 Certbot

1
sudo apt install -y certbot python3-certbot-nginx

12.4 申请证书

1
2
3
4
sudo certbot certonly \
  --webroot \
  -w /var/www/certbot \
  -d www.novalshared.work

按提示填写邮箱并接受服务条款。

查看证书路径:

1
sudo certbot certificates

下一步使用该命令返回的实际证书路径。以下配置以常见默认路径为例。

12.5 配置完整 HTTPS 站点

编辑:

1
sudo nano /etc/nginx/conf.d/blog.conf

将内容整体替换为:

 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
60
61
62
63
64
65
66
# HTTP:保留证书验证,其余请求跳转到 HTTPS
server {
    listen 80;
    listen [::]:80;

    server_name www.novalshared.work;

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/certbot;
        default_type text/plain;
        auth_basic off;
        allow all;
        try_files $uri =404;
    }

    location / {
        return 301 https://www.novalshared.work$request_uri;
    }

    access_log /var/log/nginx/blog_access.log;
    error_log /var/log/nginx/blog_error.log;
}

# HTTPS:提供静态博客
server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name www.novalshared.work;

    ssl_certificate
        /etc/letsencrypt/live/www.novalshared.work/fullchain.pem;

    ssl_certificate_key
        /etc/letsencrypt/live/www.novalshared.work/privkey.pem;

    ssl_protocols TLSv1.2 TLSv1.3;

    root /var/www/personal-blog;
    index index.html;
    charset utf-8;

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

    location ~ /\. {
        deny all;
    }

    error_page 404 /404.html;

    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types
        text/plain
        text/css
        application/javascript
        application/json
        application/xml
        image/svg+xml;

    access_log /var/log/nginx/blog_access.log;
    error_log /var/log/nginx/blog_error.log;
}

检查并加载:

1
sudo nginx -t && sudo systemctl reload nginx

测试访问:

1
2
curl -I http://www.novalshared.work/
curl -I https://www.novalshared.work/

HTTP 应跳转 HTTPS,HTTPS 首页应返回 200。

13. 配置证书自动续期

13.1 创建续期后的部署钩子

1
2
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

写入:

1
2
3
4
5
#!/bin/sh
set -eu

/usr/sbin/nginx -t
/bin/systemctl reload nginx

授予执行权限:

1
2
sudo chmod 755 \
  /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

13.2 启用并测试续期

使用 Ubuntu apt 安装 Certbot 时,启用定时器:

1
2
3
sudo systemctl enable --now certbot.timer
systemctl list-timers --all | grep -i certbot
sudo certbot renew --dry-run

保留 HTTP 80 端口及独立的证书验证目录,供后续自动验证使用。

14. 更新网站内容

14.1 新增文章

1
2
3
cd /home/bloguser/sites/personal-blog-stack
hugo new content post/my-new-post/index.md
nano content/post/my-new-post/index.md

填写正文,并设置:

1
2
draft = false
slug = "my-new-post"

对应文章地址:

1
https://www.novalshared.work/p/my-new-post/

14.2 发布文章、图片和样式

预览确认后执行:

1
2
cd /home/bloguser/sites/personal-blog-stack
./publish.sh

14.3 修改与下线

修改文章时编辑对应 index.md,完成后执行发布脚本。

下线文章时,将 Front Matter 改为:

1
draft = true

再执行 ./publish.sh。发布脚本每次使用新目录构建,正式目录会同步移除已下线页面。

15. 可选:配置公网 IP 访问

此部分配置独立的静态站点,通过 http://服务器公网IP/ 查看网页,无需持续运行 Hugo 开发服务器。公网可用性以实际网络及接入商规则为准。

15.1 按 IP 地址构建

1
2
3
4
5
cd /home/bloguser/sites/personal-blog-stack

hugo --minify \
  --baseURL "http://8.137.156.232/" \
  --destination public-ip

--baseURL 仅覆盖本次构建,不修改 hugo.toml 中的正式域名。

15.2 发布到独立目录

1
2
3
4
5
6
7
sudo mkdir -p /var/www/personal-blog-ip

sudo rsync -av --delete \
  public-ip/ \
  /var/www/personal-blog-ip/

sudo chmod -R a+rX /var/www/personal-blog-ip

15.3 新建 IP 访问配置

1
sudo nano /etc/nginx/conf.d/blog-ip.conf

写入:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
server {
    listen 80;

    server_name 8.137.156.232;

    root /var/www/personal-blog-ip;
    index index.html;
    charset utf-8;

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

    location ~ /\. {
        deny all;
    }

    access_log /var/log/nginx/blog_ip_access.log;
    error_log /var/log/nginx/blog_ip_error.log;
}

检查并加载:

1
sudo nginx -t && sudo systemctl reload nginx

15.4 测试访问

1
2
3
curl -I \
  -H "Host: 8.137.156.232" \
  http://127.0.0.1/

在浏览器打开:

1
http://8.137.156.232/

IP 访问使用 HTTP;域名的 HTTPS 证书不用于该 IP 站点。

15.5 更新 IP 站点

每次修改后,重复执行本节的构建与同步命令。IP 站点和正式域名站点使用各自的构建结果及发布目录。

16. 可选:移除 IP 访问配置

16.1 确认正式域名站点已发布

确认 hugo.toml 保留:

1
baseURL = "https://www.novalshared.work/"

发布并检查:

1
2
3
cd /home/bloguser/sites/personal-blog-stack
./publish.sh
curl -I https://www.novalshared.work/

16.2 停用 IP 站点

1
2
3
4
5
sudo mv \
  /etc/nginx/conf.d/blog-ip.conf \
  /etc/nginx/conf.d/blog-ip.conf.disabled

sudo nginx -t && sudo systemctl reload nginx

16.3 清理 IP 专用网页

确认两个目录只包含本教程生成的 IP 静态网站后,删除:

1
2
sudo rm -r -- /var/www/personal-blog-ip
rm -r -- /home/bloguser/sites/personal-blog-stack/public-ip

以上仅清理可重新生成的 IP 网页。保留正式源项目、/var/www/personal-blog/、blog.conf、证书及验证目录。

停用 IP 专用站点后,直接访问 IP 的请求会按 Nginx 的默认站点规则处理;此步骤不额外改变默认站点。

17. 版本管理与备份

17.1 配置忽略文件

1
2
cd /home/bloguser/sites/personal-blog-stack
nano .gitignore

写入:

/public/
/public-ip/
/resources/
/.hugo_build.lock
/.build.*/

17.2 配置项目 Git 身份

替换为自己的姓名和邮箱:

1
2
git config user.name "你的名字"
git config user.email "你的真实邮箱"

17.3 保存项目版本

1
2
git add .
git commit -m "初始化 Hugo Stack 博客"

以后更新内容后:

1
2
3
git status
git add .
git commit -m "更新博客内容"

将仓库同步到自己的私有远程仓库,或定期复制到其他设备。恢复子模块时执行:

1
git submodule update --init --recursive

17.4 备份范围

重点备份:

1
2
3
/home/bloguser/sites/personal-blog-stack/
/etc/nginx/conf.d/blog.conf
/etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh

如果需要完整迁移现有证书,另行以管理员权限安全备份 /etc/letsencrypt/,其中包含私钥。

主题升级时选择明确的目标版本,先在源项目预览和构建,再运行发布脚本;主题版本变更后将子模块引用一并提交。

18. 最终目录结构

 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
/home/bloguser/sites/personal-blog-stack/
├── hugo.toml
├── publish.sh
├── .gitignore
├── .gitmodules
├── assets/
│   ├── img/
│   │   └── avatar.jpg
│   └── scss/
│       └── custom.scss
├── content/
│   ├── post/
│   │   └── hello-stack/
│   │       ├── index.md
│   │       ├── cover.jpg
│   │       └── screenshot.png
│   └── page/
│       ├── archives/index.md
│       ├── search/index.md
│       └── about/index.md
└── themes/
    └── hugo-theme-stack/

/var/www/
├── personal-blog/
└── certbot/
    └── .well-known/acme-challenge/

/etc/nginx/conf.d/
├── blog.conf
└── download.conf

/etc/letsencrypt/renewal-hooks/deploy/
└── reload-nginx.sh

官方参考

使用 Hugo 构建
主题 Stack 由 Jimmy 设计