项目背景
这是一个基于Hugo的个人技术博客系统,采用完全自动化的CI/CD流程,实现了从本地编写文章到生产环境发布的全流程自动化。整个系统具有以下特点:
- ✅ 零成本运营:使用GitHub Actions免费额度
- ✅ 高度自动化:Git推送即部署,2-3分钟自动完成
- ✅ 模块化设计:支持多专题独立管理
- ✅ 自主可控:自建访客统计系统
- ✅ 性能优异:静态网站,首页加载<2秒
核心工作流:
写作(2分钟) → Git推送(即时) → Actions构建(1.5分钟) → rsync部署(30秒) → 网站生效(即时)
技术架构
技术栈
| 层级 | 技术选型 | 说明 |
|---|---|---|
| 静态网站生成器 | Hugo v0.150.1 extended | 构建速度快,支持SCSS |
| 主题 | PaperMod | 简洁美观,功能丰富 |
| CI/CD平台 | GitHub Actions | 免费,与GitHub深度集成 |
| 版本控制 | Git + GitHub | 代码托管和协作 |
| Web服务器 | Nginx 1.20.1 | 高性能静态文件服务 |
| SSL证书 | Let’s Encrypt (acme.sh) | 免费,自动续期 |
| 访客统计 | Python Flask + SQLite | 自建,数据可控 |
| 服务器 | 阿里云ECS | CentOS/Alibaba Cloud Linux |
系统架构图
┌─────────────────────────────────────────────────────────────┐
│ 本地开发环境 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 写作编辑 │→│ 本地预览 │→│ Git提交 │ │
│ │ Markdown │ │hugo server│ │git push │ │
│ └──────────┘ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ GitHub平台 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ GitHub Actions (CI/CD) │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │检出 │→│安装 │→│构建 │→│SSH │→│部署 │ │ │
│ │ │代码 │ │Hugo │ │网站 │ │连接 │ │文件 │ │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 生产服务器 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Nginx Web服务器 │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │
│ │ │ 静态文件 │ │ SSL证书 │ │ 访客统计 │ │ │
│ │ │ /blog/ │ │ HTTPS加密 │ │ Flask API │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 用户访问 │
│ https://ruyueshuke.com/blog/ │
└─────────────────────────────────────────────────────────────┘
GitHub Actions CI/CD配置
配置文件结构
文件位置:.github/workflows/deploy.yml
触发条件:
- 自动触发:推送到main分支时自动执行
- 手动触发:支持workflow_dispatch手动触发
完整配置详解
name: Deploy Hugo Blog
on:
push:
branches:
- main # main分支有push时触发
workflow_dispatch: # 允许手动触发
jobs:
deploy:
runs-on: ubuntu-latest # 使用Ubuntu虚拟机
steps:
# 步骤1:检出代码
- name: 📥 Checkout repository
uses: actions/checkout@v4
with:
submodules: true # 拉取主题子模块
fetch-depth: 0 # 获取完整历史(Hugo需要)
关键点:
submodules: true:自动拉取PaperMod主题(Git子模块)fetch-depth: 0:获取完整Git历史,用于显示文章最后修改时间
# 步骤2:安装Hugo
- name: 🔧 Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: 'latest' # 使用最新版本
extended: true # 安装extended版本(支持SCSS)
为什么需要extended版本:
- 支持SCSS/SASS编译
- 支持WebP图片处理
- 支持PostCSS
# 步骤3:构建网站
- name: 🏗️ Build website
run: hugo --minify
构建过程:
- 读取
config.toml配置 - 处理
content/目录下的Markdown文件 - 应用
layouts/自定义模板 - 复制
static/静态资源 - 生成静态HTML到
public/目录 --minify参数压缩HTML/CSS/JS
# 步骤4:显示构建信息
- name: 📊 Show build info
run: |
echo "构建完成!"
echo "生成文件列表:"
ls -lah public/
echo "---"
echo "文件总大小:"
du -sh public/
输出示例:
构建完成!
生成文件列表:
total 1.2M
drwxr-xr-x 8 runner docker 256 Jan 29 03:35 .
drwxr-xr-x 12 runner docker 384 Jan 29 03:35 ..
-rw-r--r-- 1 runner docker 15K Jan 29 03:35 index.html
drwxr-xr-x 5 runner docker 160 Jan 29 03:35 posts
drwxr-xr-x 3 runner docker 96 Jan 29 03:35 images
---
文件总大小:
1.2M public/
# 步骤5:部署Hugo博客到blog子目录
- name: 🚀 Deploy Hugo blog to server
uses: easingthemes/ssh-deploy@main
with:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
REMOTE_HOST: ${{ secrets.SERVER_HOST }}
REMOTE_USER: ${{ secrets.SERVER_USER }}
SOURCE: "public/"
TARGET: "/usr/share/testpage/blog/"
ARGS: "-avzr --delete --exclude='.well-known'"
rsync参数详解:
-a:归档模式,保留文件权限、时间戳、符号链接-v:详细输出,显示同步过程-z:压缩传输,节省带宽-r:递归同步子目录--delete:删除目标目录中源目录没有的文件(保持同步)--exclude='.well-known':排除SSL证书验证目录
为什么排除.well-known:
- Let’s Encrypt使用
.well-known/acme-challenge/进行域名验证 - 如果删除此目录,证书续期会失败
- 必须在rsync时排除,避免被误删
GitHub Secrets配置
在GitHub仓库设置中配置以下Secrets:
| Secret名称 | 说明 | 示例值 |
|---|---|---|
SSH_PRIVATE_KEY | SSH私钥(ed25519格式) | -----BEGIN OPENSSH PRIVATE KEY-----... |
SERVER_HOST | 服务器IP或域名 | 47.93.8.184 |
SERVER_USER | SSH登录用户 | root |
生成SSH密钥对:
# 1. 生成ed25519密钥对(更安全)
ssh-keygen -t ed25519 -C "github-actions" -f ~/.ssh/github_actions
# 2. 将公钥添加到服务器
ssh-copy-id -i ~/.ssh/github_actions.pub root@47.93.8.184
# 3. 测试连接
ssh -i ~/.ssh/github_actions root@47.93.8.184
# 4. 将私钥内容复制到GitHub Secrets
cat ~/.ssh/github_actions
部署时间分析
| 步骤 | 耗时 | 说明 |
|---|---|---|
| 检出代码 | 10秒 | 拉取代码和子模块 |
| 安装Hugo | 20秒 | 下载并安装Hugo |
| 构建网站 | 30秒 | 生成静态文件 |
| SSH连接 | 10秒 | 建立SSH连接 |
| rsync同步 | 30秒 | 传输文件到服务器 |
| 总计 | ~2分钟 | 完全自动化 |
服务器部署配置
目录结构
/usr/share/testpage/
├── blog/ # Hugo博客(子目录部署)
│ ├── index.html # 博客首页
│ ├── posts/ # 文章目录
│ │ ├── index.html
│ │ └── [文章页面...]
│ ├── devops/ # DevOps专题
│ ├── business/ # 业务专题
│ ├── images/ # 图片资源
│ ├── css/ # 样式文件
│ ├── js/ # JavaScript文件
│ └── [其他静态文件...]
├── index.html # 根目录首页(导航页)
└── .well-known/ # SSL证书验证目录
└── acme-challenge/ # Let's Encrypt验证
为什么使用子目录部署:
- 灵活性:根目录可以放置其他内容(如导航页)
- 扩展性:未来可以添加其他子应用(如API、管理后台)
- 隔离性:博客更新不影响根目录内容
- SEO友好:URL结构清晰(
/blog/posts/article-name/)
Nginx配置
配置文件位置:/etc/nginx/conf.d/ruyueshuke.conf
完整配置示例:
# HTTP自动跳转HTTPS
server {
listen 80;
server_name ruyueshuke.com www.ruyueshuke.com;
return 301 https://$server_name$request_uri;
}
# HTTPS服务器
server {
listen 443 ssl http2;
server_name ruyueshuke.com www.ruyueshuke.com;
root /usr/share/testpage;
index index.html;
# SSL证书配置
ssl_certificate /etc/nginx/ssl/ruyueshuke.com.cer;
ssl_certificate_key /etc/nginx/ssl/ruyueshuke.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 静态资源缓存策略
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
location ~* \.(css|js)$ {
expires 7d;
add_header Cache-Control "public";
}
# Gzip压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 访客统计API反向代理
location /api/ {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
配置要点:
- HTTP到HTTPS重定向:所有HTTP请求自动跳转到HTTPS
- HTTP/2支持:提升页面加载速度
- 静态资源缓存:图片缓存30天,CSS/JS缓存7天
- Gzip压缩:压缩文本类文件,减少传输大小
- 安全头:防止XSS、点击劫持等攻击
- API反向代理:访客统计API通过Nginx代理
完整部署流程
日常发布流程
# 第一步:本地开发
hugo new posts/$(date +%Y-%m-%d)-article-title.md
vim content/posts/$(date +%Y-%m-%d)-article-title.md
hugo server -D # 本地预览
# 第二步:Git提交
git add content/posts/$(date +%Y-%m-%d)-article-title.md
git commit -m "Add: 文章标题
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"
git push origin main
# 第三步:等待自动部署(2-3分钟)
# 访问 https://github.com/用户名/仓库名/actions 查看部署进度
# 第四步:验证发布
# 浏览器访问 https://ruyueshuke.com/blog/
部署流程详解
┌─────────────────────────────────────────────────────────────┐
│ 阶段1:本地开发(2-10分钟) │
├─────────────────────────────────────────────────────────────┤
│ 1. 创建Markdown文件 │
│ 2. 编写文章内容 │
│ 3. 本地预览验证 │
│ 4. 调整样式和格式 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 阶段2:Git提交(10秒) │
├─────────────────────────────────────────────────────────────┤
│ 1. git add 添加文件 │
│ 2. git commit 提交更改 │
│ 3. git push 推送到GitHub │
│ 4. GitHub接收推送,触发webhook │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 阶段3:GitHub Actions构建(1.5分钟) │
├─────────────────────────────────────────────────────────────┤
│ 1. 启动Ubuntu虚拟机(5秒) │
│ 2. 检出代码和子模块(10秒) │
│ 3. 安装Hugo extended(20秒) │
│ 4. 执行hugo --minify构建(30秒) │
│ 5. 显示构建信息(5秒) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 阶段4:SSH部署(30秒) │
├─────────────────────────────────────────────────────────────┤
│ 1. 建立SSH连接(10秒) │
│ 2. rsync同步文件(20秒) │
│ - 传输新增/修改的文件 │
│ - 删除服务器多余文件 │
│ - 保留.well-known目录 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 阶段5:Nginx服务(即时) │
├─────────────────────────────────────────────────────────────┤
│ 1. Nginx检测到文件更新 │
│ 2. 自动提供最新静态文件 │
│ 3. 用户访问立即看到新内容 │
└─────────────────────────────────────────────────────────────┘
部署验证
1. 查看GitHub Actions状态
访问:https://github.com/用户名/仓库名/actions
状态说明:
- 🟡 黄色圆圈:正在执行
- ✅ 绿色对勾:部署成功
- ❌ 红色叉号:部署失败
2. 查看部署日志
点击具体的workflow run,可以看到每个步骤的详细日志:
- 检出代码的输出
- Hugo构建的输出
- rsync同步的文件列表
- 部署完成的通知
3. 验证网站更新
# 方法1:浏览器访问
https://ruyueshuke.com/blog/
# 方法2:curl检查(查看最后修改时间)
curl -I https://ruyueshuke.com/blog/
# 方法3:SSH登录服务器查看
ssh root@服务器IP "ls -lth /usr/share/testpage/blog/ | head"
访客统计系统
系统架构
技术栈:
- 后端:Python 3.6 + Flask 2.0
- 数据库:SQLite
- 部署:Gunicorn + Systemd
- 反向代理:Nginx
核心功能:
- PV统计:总访问量(Page Views)
- UV统计:独立访客数(基于IP哈希)
- 今日统计:今日PV和UV
- 防刷机制:同一IP 60秒内只计数一次
- 隐私保护:IP经SHA256哈希,不存储原始IP
API端点
GET /api/stats - 获取统计数据
POST /api/stats/visit - 记录访问
GET /api/health - 健康检查
响应示例:
{
"success": true,
"data": {
"total_pv": 1234,
"total_uv": 567,
"today_pv": 89,
"today_uv": 45
}
}
前端集成
位置:layouts/partials/extend_footer.html
显示效果:
👀 本站总访问量 1,234 次 | 👤 访客数 567 人 | 📅 今日访问 89 次
工作原理:
- 页面加载时调用
POST /api/stats/visit记录访问 - 同时调用
GET /api/stats获取统计数据 - JavaScript格式化数字(千分位逗号)
- 失败时显示"-",不影响页面使用
服务管理
# 查看服务状态
systemctl status visitor-stats
# 查看实时日志
journalctl -u visitor-stats -f
# 重启服务
systemctl restart visitor-stats
# 查看数据库
sqlite3 /var/lib/visitor-stats/stats.db "SELECT COUNT(*) FROM visits"
最佳实践
1. 文章编写规范
Front Matter模板:
---
title: "文章标题"
date: 2026-01-29T10:00:00+08:00
draft: false
tags: ["标签1", "标签2"]
categories: ["技术"]
description: "文章简介"
---
注意事项:
- ⚠️ 时间不能是未来:Hugo默认不发布未来时间的文章
- ✅ 使用当前或过去时间:确保文章能正常显示
- ✅ 标签规范:使用统一的标签体系
- ✅ 描述精炼:控制在100字以内
2. 图片管理
存放位置:static/images/
命名规范:
# 按日期组织
static/images/2026-01-29/screenshot.png
# 或按文章组织
static/images/article-name/diagram.png
引用方式:

优化建议:
- 图片压缩:使用TinyPNG等工具
- 格式选择:PNG用于截图,JPG用于照片,SVG用于图标
- 大小控制:小图标<50KB,配图<300KB,大图<800KB
3. 性能优化
Hugo构建优化:
# 使用--minify压缩输出
hugo --minify
# 使用--gc清理缓存
hugo --gc
# 使用--cleanDestinationDir清理目标目录
hugo --cleanDestinationDir
Nginx优化:
- 启用Gzip压缩
- 配置静态资源缓存
- 启用HTTP/2
- 配置CDN(可选)
4. 安全加固
SSH安全:
# 使用ed25519密钥(更安全)
ssh-keygen -t ed25519
# 禁用密码登录(仅密钥登录)
# /etc/ssh/sshd_config
PasswordAuthentication no
# 修改SSH端口(可选)
Port 2222
Nginx安全:
- 配置安全头(X-Frame-Options、X-XSS-Protection)
- 隐藏Nginx版本号
- 配置防火墙规则
- 定期更新SSL证书
5. 监控告警
GitHub Actions通知:
- 配置邮件通知
- 配置Slack/钉钉通知
- 监控部署失败
服务器监控:
# 磁盘空间监控
df -h /usr/share/testpage
# Nginx访问日志
tail -f /var/log/nginx/access.log
# 访客统计服务日志
journalctl -u visitor-stats -f
6. 备份策略
Git备份:
- 所有内容都在Git中,天然备份
- 推送到GitHub,云端存储
- 可以随时回滚到任意版本
服务器备份(可选):
# 备份网站文件
tar -czf blog-backup-$(date +%Y%m%d).tar.gz /usr/share/testpage/blog/
# 备份访客统计数据库
cp /var/lib/visitor-stats/stats.db /backup/stats-$(date +%Y%m%d).db
成本分析
初始成本:¥0
| 项目 | 费用 | 说明 |
|---|---|---|
| Hugo | 免费 | 开源软件 |
| GitHub仓库 | 免费 | 私有仓库免费 |
| GitHub Actions | 免费 | 2000分钟/月 |
| 服务器 | 已有 | 复用现有服务器 |
| 域名 | 已有 | 复用现有域名 |
| SSL证书 | 免费 | Let’s Encrypt |
运营成本:¥0/月
| 项目 | 费用 | 说明 |
|---|---|---|
| GitHub Actions | ¥0 | 每月构建<100次 |
| 服务器带宽 | ¥0 | 静态网站流量小 |
| 图片存储 | ¥0 | 存储在Git(<1GB) |
| SSL证书续期 | ¥0 | 自动续期 |
时间成本
| 任务 | 耗时 | 频率 |
|---|---|---|
| 初次搭建 | 2-3小时 | 一次性 |
| 写一篇文章 | 30-60分钟 | 按需 |
| 发布文章 | 1分钟 | 每篇 |
| 等待部署 | 2-3分钟 | 自动 |
| 系统维护 | 5分钟 | 每月 |
故障排查
常见问题
1. 部署失败:SSH连接超时
# 检查服务器SSH服务
ssh root@服务器IP
# 检查防火墙规则
firewall-cmd --list-all
# 检查GitHub Actions Secrets配置
# 确保SSH_PRIVATE_KEY、SERVER_HOST、SERVER_USER正确
2. 文章不显示:时间是未来
# 检查文章Front Matter的date字段
# 确保时间不是未来时间
# 修改为当前或过去时间
date: 2026-01-29T10:00:00+08:00 # ✅ 正确
date: 2026-12-31T10:00:00+08:00 # ❌ 错误(未来时间)
3. 图片显示404
# 检查图片路径
# 正确:/images/2026-01-29/screenshot.png
# 错误:/static/images/2026-01-29/screenshot.png
# 检查图片是否已提交到Git
git status
git add static/images/
git commit -m "Add: 添加图片"
git push
4. 访客统计不显示
# 检查API服务状态
systemctl status visitor-stats
# 检查API是否响应
curl https://ruyueshuke.com/api/health
# 查看服务日志
journalctl -u visitor-stats -n 50
# 重启服务
systemctl restart visitor-stats
总结
这是一个完全自动化、零成本运营的Hugo博客CI/CD系统,具有以下特点:
核心优势
高度自动化
- Git推送即部署
- 2-3分钟自动完成
- 无需人工干预
零成本运营
- 使用GitHub Actions免费额度
- 复用现有服务器和域名
- Let’s Encrypt免费SSL证书
模块化设计
- 支持多专题独立管理
- 清晰的目录结构
- 易于扩展和维护
自主可控
- 自建访客统计系统
- 数据完全掌控
- 隐私保护
性能优异
- 静态网站,首页加载<2秒
- Gzip压缩,减少传输大小
- 静态资源缓存,提升访问速度
技术亮点
- ✅ Git子模块管理主题:方便主题更新
- ✅ rsync增量同步:只传输变更文件
- ✅ Nginx反向代理:统一API访问
- ✅ Systemd服务管理:自动启动和重启
- ✅ acme.sh自动续期:SSL证书永不过期
适用场景
这套方案适合:
- 个人技术博客
- 团队文档站点
- 项目展示页面
- 静态网站托管
核心工作流:
写作(2分钟) → Git推送(即时) → Actions构建(1.5分钟) → rsync部署(30秒) → 网站生效(即时)
所有配置文件、脚本、文档都已完整保存在项目中,可以作为DevOps实践的完整案例参考。