1 技术选型
由于博客网站主要用来记录博主的文章和日常,这里选择使用静态框架 Hugo 进行搭建, 访问速度更快, 维护成本更低。
- 静态框架:Hugo
- 框架主题:Clean White
- 部署方式:Docker + Nginx + GitHub Actions
2 使用 Hugo 静态框架
Hugo 是最受欢迎的开源静态网站生成器之一。凭借其惊人的速度和灵活性,Hugo 让搭建网站重新变得有趣。
- Hugo 官网:
https://gohugo.io - Hugo 主题仓库:
https://themes.gohugo.io- Clean White 主题:
https://themes.gohugo.io/themes/hugo-theme-cleanwhite
- Clean White 主题:
- Hugo 配置文档:
https://gohugo.io/documentation
2.1 本地化开发
2.1.1 Window 11 环境
- 环境依赖:
- 访问 GitHub 可能需要梯子:参考 《梯子使用手册》
- Git:参考 《Git 使用手册》
1# 1 安装 Hugo
2
3# 查询本地是否已经安装
4winget list | findstr Hugo
5# Hugo Hugo.Hugo 0.153.0 0.159.0 winget
6
7# 搜索远程仓库 Hugo 最新版本
8winget search Hugo
9# Name Id Version Match Source
10# -------------------------------------------------------------------
11# Hugo Hugo.Hugo 0.159.0 winget
12# Hugo (Deploy) Hugo.Hugo.Deploy 0.150.0 Command: hugo winget
13# Hugo (Extended) Hugo.Hugo.Extended 0.159.0 winget
14# 希沃集控 Seewo.SeewoHugo 1.4.5.57 winget
15# 掌上看班 Seewo.SeewoHugoKanban 1.4.5.68 winget
16
17# 安装/更新指定版本 Hugo
18winget install --id Hugo.Hugo --version 0.159.0
19
20# 查询认证一下
21winget list | findstr Hugo
22# Hugo Hugo.Hugo 0.159.0 winget
23hugo version
24# hugo v0.159.0-2ed7d193cfdfcf11808fb2a921a9429423b0ebe9 windows/amd64 BuildDate=2026-03-23T18:16:59Z VendorInfo=gohugoio
25
26
27
28# 2 使用 Hugo 创建站点
29
30# 创建站点
31hugo new project D:\dev\workspace\blog && cd /d D:\dev\workspace\blog
32
33# 下载主题 hugo-theme-cleanwhite
34git clone --depth 1 https://github.com/zhaohuabing/hugo-theme-cleanwhite.git themes/hugo-theme-cleanwhite
35# 删除主题 git 相关信息
36cd themes\hugo-theme-cleanwhite && rd /s /q .git & del /f /q .gitignore
37# 修改站点主题为 hugo-theme-cleanwhite
38cd ..\.. && echo theme = 'hugo-theme-cleanwhite' >> hugo.toml
39
40
41
42# 3 启动站点的服务器测试模式
43# --bind 0.0.0.0 是为了监听 IPv4 所有网络地址,让 手机 等设备可以通过 局域网 (同一 WiFi 下) 访问 电脑 的站点,进行移动端测试
44hugo server --bind 0.0.0.0
2.1.2 macOS 环境
2.2 目录结构
- archetypes:存放新内容的模板(优先级高于主题的模版)
- default.md:命令新建 新内容 的默认模板(
hugo new test.md) - post.md:命令新建 文章 的模板(
hugo new post/20260115-building-blog-site.md)
- default.md:命令新建 新内容 的默认模板(
- assets:存放需要 Hugo 处理压缩的文件,需要通过代码管道调用
- content:存放构成网站内容的文章、页面等文件(可 手动 或 命令 创建)
- post:存放文章文件
- 其他目录:存放页面文件
- data:存放数据文件
- i18n:存放多语言网站的翻译表
- layouts:存放新内容的各种布局模板(优先级高于主题的模版,主题二次开发的文件一般放这里)
- baseof.html:所有内容基础结构模板
- _partials
- head.html:元数据、脚本等信息模版
- nav.html:头部导航模板
- footer.html:尾部信息模板
- _partials
- home.html:首页模板
- _partials:
- portfolio.html:首页内容容器模板
- posts.html:文章列表容器模板
- post_list.html:文章列表模板
- pagination.html:文章分页模板
- sidebar.html:右侧信息模板
- posts.html:文章列表容器模板
- portfolio.html:首页内容容器模板
- _partials:
- post.html:文章内容模板
- _partials:
- reward.html:赞赏模板
- comments.html:评论模板
- _partials:
- taxonomy:
- category.html:分类页面模板
- tag.html:标签页面模板
- _partials:
- category.html:分类,标签列表模板
- posts.html:文章列表容器模板
- post_list.html:文章列表模板
- pagination.html:文章分页模板
- sidebar.html:右侧信息模板
- archive.html:归档模板
- _partials:
- sidebar.html:右侧信息模板
- _partials:
- about.html:关于我模板
- _partials:
- comments.html:评论模板
- sidebar.html:右侧信息模板
- _partials:
- search/list.html:搜索结果模板
- _partials:
- search-algolia.html:Algolia 搜索结果模板
- search-pagefind.html:Pagefind 搜索结果模板
- sidebar.html:右侧信息模板
- _partials:
- baseof.html:所有内容基础结构模板
- public:存放项目构建结果文件
- static:存放项目构建时将被复制到 public 目录的静态文件
- img:存放图片资源
- theme:存放主题文件
- hugo-theme-cleanwhite
- exampleSite:主题作者提供的参考站点,可以参考配置
- hugo-theme-cleanwhite
- hugo.toml:项目配置文件
2.3 项目配置
2.3.1 配置文件
- 作者配置
./hugo.toml:
1# 生产构建时,生成所有正式链接的唯一基础地址
2# sitemap.xml(网站地图)、robots.txt(爬虫协议)、页面 canonical 标签 等 SEO 核心文件必依赖它
3baseURL = 'https://templechann.com'
4# locale = 'en-us'
5locale = 'zh-cn'
6title = 'Temple Blog'
7theme = 'hugo-theme-cleanwhite'
8
9buildFuture = true # 构建包含未来日期的文章
10hasCJKLanguage = true # 自动处理中日韩文字,解决默认配置下的排版、摘要、字数统计 BUG
11enableRobotsTXT = true # 自动在你的网站根目录生成 robots.txt 文件
12cleanDestinationDir = true # 构建时清空历史文件
13
14[markup]
15 [markup.highlight]
16 style = "nord" # 代码块高亮,https://xyproto.github.io/splash/docs/all.html
17 lineNos = true # 显示行号
18 lineNumbersInTable = false
19 [markup.goldmark]
20 [markup.goldmark.renderer]
21 unsafe = true # markdown 中使用 html
22 [markup.goldmark.extensions]
23 [markup.goldmark.extensions.passthrough]
24 enable = true
25 [markup.goldmark.extensions.passthrough.delimiters]
26 block = [['\[', '\]'], ['$$', '$$']]
27 inline = [['\(', '\)']]
28
29[pagination]
30 pagerSize = 10 # frontpage pagination
31
32[mediaTypes]
33 [mediaTypes.'font/woff']
34 suffixes = ['woff']
35 [mediaTypes.'font/woff2']
36 suffixes = ['woff2']
37
38[outputs]
39# home = ["HTML", "RSS", "Algolia"]
40home = ["HTML", "RSS"]
41
42[services]
43 # Enable comments by entering your Disqus shortname
44 [services.disqus]
45 shortname = ""
46 [services.googleAnalytics]
47 id = ""
48
49[outputFormats.Algolia]
50# baseName = "algolia"
51# isPlainText = true
52# mediaType = "application/json"
53# notAlternative = true
54
55[params]
56 header_image = "img/home-bg.png"
57 slogan = "山高自有客行路,水深自有渡船人"
58 SEOTitle = "谌中钱的博客 | Temple Blog"
59 description = "谌中钱(言戈,Temple Chan),男,29岁,179cm,65kg,摩羯座,ESTJ,汉族,中共团员,1996年1月14日出生于湖北省武汉市黄陂区,祖籍河南洛阳一带,始祖春秋时期郑国大夫裨谌。理学学士学位,主修计算机科学,中国内地不知名程序员,腾讯、Coupang、阿里云 前搬砖人,爬界科技 创始人、首席执行官。"
60 keyword = "谌中钱, 言戈, 在下言戈, Temple Chan, Temple, templechan, templechann, templechannn, 谌中钱的博客, 博客网站, 博客, 编程技术"
61
62 image_404 = "img/post-bg-404.png"
63 title_404 = "你页面不存在"
64 omit_categories = false # 隐藏分类菜单
65 upstreamAttribution = false # 显示主题作者信息
66 dark_mode_toggle = false # 是否开启暗黑模式
67 isSearch = false # 是否显示搜索图标
68
69 # 备案信息
70 isBeian = true # 是否显示备案信息
71 icp = "鄂ICP备2025165689号-1"
72 gongan = "鄂公网安备42018502008405号"
73 gongan_num = "42018502008405"
74
75 # Sidebar settings
76 sidebar_avatar = "img/templechan.jpg" # use absolute URL, seeing it's used in both `/` and `/about/`
77 sidebar_about_description = "谌中钱(言戈,Temple Chan),男,29岁,179cm,65kg,摩羯座,ESTJ,汉族,中共团员,1996年1月14日出生于湖北省武汉市黄陂区,祖籍河南洛阳一带,始祖春秋时期郑国大夫裨谌。理学学士学位,主修计算机科学,中国内地不知名程序员,腾讯、Coupang、阿里云 前搬砖人,爬界科技 创始人、首席执行官。"
78 about_me = true
79 bookmarks = true
80 featured_tags = true
81 featured_condition_size = 0
82 friends = true
83
84 # Last posts
85 last_posts = true
86 #last_posts_title = "LAST POSTS"
87 #last_posts_count = 5
88
89 #Enable wechat pay & alipay to allow readers send reward money if they like the articles
90 reward = false
91 reward_guide = "您的咖啡能让我写出少 Bug 的代码 ☕️ ~"
92
93 # Twikoo comments
94 # Follow https://twikoo.js.org/ to set up your own env_id
95 twikoo_env_id = ""
96
97 # Artalk comments
98 # Follow https://artalk.js.org/ to set up your own server
99 artalk_enable = false
100 artalk_server = "https://xxx.xxx.com"
101 artalk_site = "xxx blog"
102
103 # We need a proxy to access Disqus api in China
104 # Follow https://github.com/zhaohuabing/disqus-php-api to set up your own disqus proxy
105 disqus_proxy = ""
106 disqus_site = ""
107
108 # algolia site search
109 algolia_search = false
110 algolia_appId = ""
111 algolia_indexName = ""
112 algolia_apiKey = ""
113
114 # leancloud storage for page view counter
115 page_view_counter = false
116 leancloud_app_id = ""
117 leancloud_app_key = ""
118
119 # Baidu Analytics
120 ba_track_id = ""
121
122 # Include any custom CSS and/or JS files, url or relative to /static folder
123 #custom_css = ["css/lightbox.css", "https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css", "css/main.css"]
124 #custom_js = ["js/lightbox.js", "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js", "js/main.js"]
125
126 [params.algolia]
127 vars = ["title", "summary", "date", "publishdate", "expirydate", "permalink"]
128 params = ["categories", "tags"]
129
130 [params.social]
131 rss = true
132
133 email = "templechan@126.com"
134 github = "https://github.com/templechan"
135# linkedin = "https://www.linkedin.com/in/templechan"
136 wechat = "img/social/social-wechat.png"
137 qq = "img/social/social-qq.png"
138 whatsapp = "img/social/social-whatsapp.jpg"
139 messenger = "img/social/social-messenger.jpg"
140 telegram = "img/social/social-telegram.jpg"
141 line = "img/social/social-line.jpg"
142 kakaotalk = "img/social/social-kakaotalk.png"
143 zalo = "img/social/social-zalo.jpg"
144
145 tiktok = "https://www.douyin.com/user/MS4wLjABAAAA84o70K2c9LEZXJ9fHp0deVyvxMudni7rQgAahjtoWIX34SCg61Gbf6H4HYKneZsW"
146 wechatChannels = "img/social/social-wechat-channels.jpg"
147 bilibili = "https://space.bilibili.com/3546602247555636"
148 rednote = "https://www.xiaohongshu.com/user/profile/658fc18d0000000022017e5a"
149 wechatPublicPlatform = "img/social/social-wechat-public-platform.jpg"
150 csdn = "https://blog.csdn.net/2301_82344373"
151 juejin = "https://juejin.cn/user/3617844579024624"
152 zhihu = "https://www.zhihu.com/people/templechan"
153 weibo = "https://weibo.com/templechan1024"
154 facebook = "https://www.facebook.com/templechann"
155 instagram = "https://www.instagram.com/templechann"
156 tiktokInternational = "https://www.tiktok.com/@templechan"
157 x = "https://x.com/templechann"
158 snapchat = "https://www.snapchat.com/@templechann"
159 vk = "https://vk.com/templechan"
160 youtube = "https://www.youtube.com/@templechann"
161 threads = "https://www.threads.com/@templechann"
162
163 [[params.bookmark_link]]
164 title = "爬界科技"
165 href = "https://climbtw.com"
166
167 [[params.friend_link]]
168 title = "赵华冰的博客"
169 href = "https://www.zhaohuabing.com"
170 [[params.friend_link]]
171 title = "Beyond the Void"
172 href = "https://byvoid.com/zhs"
173
174 [[params.additional_menus]]
175 title = "ARCHIVE"
176 href = "/archive"
177 [[params.additional_menus]]
178 title = "ABOUT"
179 href = "/about"
2.3.2 内容元数据配置
配置于 Markdown 文件头部。
作者配置:
1---
2layout: post
3title: 构建博客网站
4subtitle:
5description: 涉及 Hugo 静态框架,自动化部署,评论服务,SEO 等。
6author: 谌中钱
7date: 2026-01-15
8lastMod:
9image: img/post-bg-default.png
10categories:
11- programming
12tags:
13- 解决方案
14slug: building-blog-site
15metadata:
16- text: Hugo
17 link: https://gohugo.io
18weight: 2
19showtoc: true
20draft: false
21---
2.3.3 命令新建文章模板
命令:
hugo new post/20260115-building-blog-site.md作者文章模版
./archetypes/post.md:1--- 2layout: post 3title: 4subtitle: 5description: 涉及 等。 6author: 谌中钱 7date: 2026-01-15 8lastMod: 9image: img/post-bg-default.png 10categories: 11- 12tags: 13- 14slug: 15metadata: 16- text: 17 link: 18weight: 2 19showtoc: true 20draft: false 21--- 22 23<br /> 24 25<!-- @import "[TOC]" {cmd="toc" depthFrom=1 depthTo=6} -->
2.4 自动化部署
实现推送代码到 Github 上的 main 分支时,会自动部署到 云服务器。
- 环境依赖:
- 云服务器:参考 《云服务器购买和使用手册》
- Docker:参考 《Docker 使用手册》
- Nginx:参考 《Nginx 使用手册》
2.4.1 云服务器 SSH 配置
让 Github 可以用 云服务器的私钥 去连接 云服务器。
1# 云服务器上生成 公钥(id_ed25519.pub) 和 私钥(id_ed25519)
2ssh-keygen -t ed25519 -C "templechan@126.com"
3# 将 公钥(id_ed25519.pub) 添加到云服务器的 ~/.ssh/authorized_keys 文件中
4cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
5
6# 查看 私钥
7cat ~/.ssh/id_ed25519
8# 登录 GitHub -> 站点仓库下的 Settings -> Secrets and variables -> Actions -> New repository secret 中添加 3 个常量:
9
10# Name: BLOG_SSH_PRIVATE_KEY
11# Value: 你的私钥内容(注意不要添加换行符,可以直接从文件复制)
12
13# Name: BLOG_SERVER_IP
14# Value: 部署服务器的 IP
15
16# Name: BLOG_USER
17# Value: 部署服务器的 user
2.4.2 编写脚本
./.github/workflows/blog_deploy.yml:工作流文件,用来连接云服务器,执行云服务器的部署脚本./deploy.sh:云服务器的部署脚本./Dockfile:镜像构建文件./docker-compose.yml:容器构建文件
2.4.2.1 工作流文件
.github/workflows/blog_deploy.yml:
1name: Deploy to Server
2
3on:
4 push:
5 branches:
6 - main
7
8jobs:
9 deploy:
10 runs-on: ubuntu-latest
11 steps:
12 - name: Checkout code
13 uses: actions/checkout@v2
14
15 - name: Install SSH key
16 uses: webfactory/ssh-agent@v0.5.3
17 with:
18 ssh-private-key: ${{ secrets.BLOG_SSH_PRIVATE_KEY }}
19
20 - name: Adding Known Hosts
21 run: ssh-keyscan ${{ secrets.BLOG_SERVER_IP }} >> ~/.ssh/known_hosts
22
23 - name: Deploy to Server
24 run: ssh ${{ secrets.BLOG_USER }}@${{ secrets.BLOG_SERVER_IP }} 'bash -s' < ./deploy.sh
2.4.2.2 部署脚本
./deploy.sh:
1cd /usr/local/src
2rm -rf /usr/local/src/blog
3
4if ! command -v git &> /dev/null; then
5 dnf install -y git
6 git config --global user.email "templechan@126.com"
7 git config --global user.name "templechan"
8fi
9
10# 设置 GitHub 国内镜像源
11git config --global url."https://bgithub.xyz/".insteadOf https://github.com/
12# 如果失效,则删除旧的,设置的新的,记得先测试下是否有效
13# git config --global --unset url."https://bgithub.xyz/".insteadOf https://github.com/
14# git config --global url."https://kkgithub.com/".insteadOf https://github.com/
15git clone -b main https://github.com/templechan/blog.git
16
17if [ -d /usr/local/src/blog ] && [ -n "$(ls -A /usr/local/src/blog)" ]; then
18 cd /usr/local/src/blog
19 if ! command -v mogrify &> /dev/null; then
20 # 安装图片压缩包 ImageMagick
21 dnf install -y ImageMagick bc parallel
22 # 配置ImageMagick策略文件
23 sed -i '/<policy domain="coder" rights=".*" pattern="PNG,JPG,JPEG,WEBP"/d;/<policymap>/a \ <policy domain="coder" rights="read|write" pattern="PNG,JPG,JPEG,WEBP" />;s/<policy domain="resource" name="memory" value="[^"]*"/<policy domain="resource" name="memory" value="256MiB"/;s/<policy domain="resource" name="disk" value="[^"]*"/<policy domain="resource" name="disk" value="1GiB"/;s/<policy domain="resource" name="width" value="[^"]*"/<policy domain="resource" name="width" value="8KP"/;s/<policy domain="resource" name="height" value="[^"]*"/<policy domain="resource" name="height" value="8KP"/;s/<policy domain="resource" name="thread" value="[^"]*"/<policy domain="resource" name="thread" value="2"/;s/<policy domain="resource" name="throttle" value="[^"]*"/<policy domain="resource" name="throttle" value="1"/;s/<policy domain="resource" name="map" value="[^"]*"/<policy domain="resource" name="map" value="256MiB"/' /etc/ImageMagick-7/policy.xml
24 fi
25
26 # 手动压缩图片资源(会覆盖源文件,注意保留源文件)
27 # 1 图片大小判断 >100KB 才压缩
28 # 2 动态质量计算算法 75 - 20*l(...)
29 # 3 质量限制 15~60
30 # 4 PNG / JPG / WebP 压缩参数
31 # 5 统计节省空间算法
32 # 6 并行数 -j 2
33
34 # 进度交互版
35 # start=$SECONDS; find ./static/img/ \( -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" -o -name "*.webp" \) -type f -print0 | parallel -0 -j 2 --bar 'f="{}";old_size=$(stat -c %s "$f");if [ $old_size -gt 102400 ]; then q=$(echo "scale=0;80-40*l($old_size/102400)/l(10)" | bc -l | awk "{print int(\$1+0.5)}");q=$((q<15?15:q>60?60:q));ext="${f##*.}";case "$ext" in png) mogrify -strip -quality $q -define png:compression-level=9 -colors 128 "$f" 2>/dev/null ;; jpg|jpeg) mogrify -strip -quality $q -sampling-factor 4:2:0 -density 72x72 "$f" 2>/dev/null ;; webp) mogrify -strip -quality $((q-5)) -define webp:method=6 "$f" 2>/dev/null ;; esac;new_size=$(stat -c %s "$f");save=$((old_size-new_size));echo "$save" >> /tmp/img_save.txt;fi'; total_save=$(awk '{sum+=$1}END{print sum}' /tmp/img_save.txt 2>/dev/null||0); count=$(wc -l </tmp/img_save.txt 2>/dev/null||0); rm -f /tmp/img_save.txt; cost=$((SECONDS - start)); min=$((cost / 60)); sec=$((cost % 60)); echo -e "\n\033[1;32m=== 压缩完成 ===\033[0m"; echo "✅ 压缩数量:$count 张"; echo "✅ 节省空间:$((total_save/1024)) KB ($((total_save/1024/1024)) MB)"; echo -e "✅ 耗时:${min}分${sec}秒"; echo -e "\033[1;32m================\033[0m"
36 # GitHub Actions 不支持交互专用
37 start=$SECONDS; find ./static/img/ \( -name "*.png" -o -name "*.jpg" -o -name "*.jpeg" -o -name "*.webp" \) -type f -print0 | parallel -0 -j 2 'f="{}";old_size=$(stat -c %s "$f");if [ $old_size -gt 102400 ]; then q=$(echo "scale=0;80-40*l($old_size/102400)/l(10)" | bc -l | awk "{print int(\$1+0.5)}");q=$((q<15?15:q>60?60:q));ext="${f##*.}";case "$ext" in png) mogrify -strip -quality $q -define png:compression-level=9 -colors 128 "$f" 2>/dev/null ;; jpg|jpeg) mogrify -strip -quality $q -sampling-factor 4:2:0 -density 72x72 "$f" 2>/dev/null ;; webp) mogrify -strip -quality $((q-5)) -define webp:method=6 "$f" 2>/dev/null ;; esac;new_size=$(stat -c %s "$f");save=$((old_size-new_size));echo "$save" >> /tmp/img_save.txt;fi' 2>/dev/null; total_save=$(awk '{sum+=$1}END{print sum}' /tmp/img_save.txt 2>/dev/null||0); count=$(wc -l </tmp/img_save.txt 2>/dev/null||0); rm -f /tmp/img_save.txt; cost=$((SECONDS-start)); min=$((cost/60)); sec=$((cost%60)); echo -e "\n=== 图片压缩完成 ==="; echo "压缩数量:$count 张"; echo "节省空间:$((total_save/1024)) KB ($((total_save/1024/1024)) MB)"; echo "耗时:${min}分${sec}秒"; echo "===================="
38
39 if ! command -v docker &> /dev/null; then
40 # 卸载旧版 Docker
41 dnf remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
42 # 自动启用仓库
43 sed -i 's/enabled=0/enabled=1/g' /etc/yum.repos.d/OpenCloudOS.repo
44 # 保存后,清除重建缓存
45 dnf clean all && dnf makecache
46
47 # 设置 Docker 国内软件源
48 dnf install -y dnf-plugins-core
49 # dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
50 dnf config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
51
52 # 安装 Docker
53 dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
54
55 # 启动 Docker
56 systemctl start docker
57 # 设置 Docker 自启
58 systemctl enable docker
59 fi
60 # 设置 Docker 国内镜像代理
61 tee /etc/docker/daemon.json <<EOF
62 {
63 "registry-mirrors": [
64 "https://docker.1ms.run",
65 "https://dockerproxy.net",
66 "https://proxy.vvvv.ee",
67 "https://dockerproxy.link"
68 ]
69 }
70EOF
71 systemctl daemon-reload
72
73 docker rm -f blog >/dev/null 2>&1
74 docker rmi -f blog >/dev/null 2>&1
75
76 docker compose up -d --build
77fi
2.4.2.3 镜像构建文件
./Dockfile:
1# 阶段1:Hugo 构建环境(临时镜像,用完丢弃)
2FROM hugomods/hugo:std-base-0.159.0 AS builder
3WORKDIR /src
4COPY . .
5RUN hugo --minify
6
7# 阶段2:生产运行环境(仅保留静态文件 + Nginx,超小体积)
8FROM nginx:alpine
9COPY --from=builder /src/public/ /usr/share/nginx/html/
10EXPOSE 80
2.4.2.4 容器构建启动文件
./docker-compose.yml:
1version: '3.8'
2
3services:
4 blog:
5 # 等价于 docker build -t blog . (自动构建当前目录的Dockerfile)
6 build: .
7 # 容器名称
8 container_name: blog
9 # 端口映射 主机81 → 容器80
10 ports:
11 - "81:80"
12 # 开机/崩溃自动重启
13 restart: always
2.5 部署云服务器 Nginx 服务
部署一个 Nginx 服务监听 云服务器 的 80 端口,然后通过端口转发到各种服务,参考 《Nginx 使用手册》
2.6 Twikoo 评论服务
Twikoo 是一个简洁、安全、免费的静态网站评论系统。
- Twikoo 官网:
https://twikoo.js.org - GitHub:
https://github.com/twikoojs/twikoo/releases- 前端引用 twikoo.js 版本需要与 云函数版本 保持一致
2.6.1 云函数部署
2.6.1.1 Docker 方式
1# 1 创建文件夹,用来存放 数据文件
2mkdir -p /usr/local/src/twikoo/data && cd /usr/local/src/twikoo
3
4# 2 创建启动容器
5docker compose up -d
6
7# 3 修改云服务器 nginx.conf 配置,让 二级域名 xxx.templechann.com 反向代理到 twikoo 容器映射的 宿主机端口 82,重启 nginx 容器
2.6.1.1.1 容器构建文件
./docker-compose.yml:
1version: '3'
2
3services:
4 twikoo:
5 image: imaegoo/twikoo:1.6.42
6 container_name: twikoo
7 restart: always
8 ports:
9 - "82:8080"
10 environment:
11 - TWIKOO_THROTTLE=1000
12 volumes:
13 - ./data:/app/data
2.6.2 站点修改
2.6.1 修改站点配置
./hugo.toml:
1# Twikoo comments
2# Follow https://twikoo.js.org/ to set up your own env_id
3twikoo_env_id = "https://xxx.templechann.com/" # 云函数部署的地址
2.6.2 修改主题代码
- 修改 前端引用的 twikoo.js,与 云函数版本 保持一致,这里用的 1.6.42:
./layouts/_partials/comments.html:
1<!-- <script src="https://cdn.jsdelivr.net/npm/twikoo@1.4.14/dist/twikoo.all.min.js"></script> -->
2<script src="https://registry.npmmirror.com/twikoo/1.6.42/files/dist/twikoo.all.min.js"></script>
- 主题 的 bootstrap.min.css 对 上传图像 样式有覆盖
- 主题 hugo-theme-cleanwhite 的样式对 头像 div 有覆盖
- 需要修改:
./layouts/_partials/comments.html:
1<style>
2.twikoo .tk-input-image {
3 display: none;
4}
5.twikoo img {
6 margin: 0;
7}
8</style>
9<div id="twikoo-tcomment"></div>
2.6.3 Twikoo 设置
在 站点文章 下方会有 Twikoo 评论组件,组件右下侧有 设置 按钮,第一次打开 设置 需要 配置密码。
2.6.3.1 头像配置
Weavatar,多端多元化的统一头像服务。
- Weavatar 官网:
https://weavatar.com - 配置方法:
- 去 Weavatar 官网 用 邮箱 注册 和 上传 自定义头像。
- 在 Twikoo 设置 -> 配置管理 -> 通用,按如下配置:
GRAVATAR_CDN: weavatar.com
2.6.3.2 Server酱 (ServerChan) 评论推送
Server酱,英文名 ServerChan,是一款 手机 和 服务器、智能设备 之间的通信软件。
- Server酱 官网:
https://sct.ftqq.com - 配置方法:
- 去 Server酱 官网 注册,获取 SendKey,然后在 通道配置 里面设置 通知方式,我使用的 方糖的微信服务号。
- 在 Twikoo 设置 -> 配置管理 -> 即时通知,按如下配置:
PUSHOO_CHANNEL: serverchan
PUSHOO_TOKEN: 填写获取的 SendKey
- 注意:
- ServerChan 目前由于用户量比较大,免费的通知额度只有 5 条。
- 自己发布的评论 (按邮箱判断),不会通知。