项目背景

这是一个基于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自建,数据可控
服务器阿里云ECSCentOS/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

触发条件

  1. 自动触发:推送到main分支时自动执行
  2. 手动触发:支持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

构建过程

  1. 读取config.toml配置
  2. 处理content/目录下的Markdown文件
  3. 应用layouts/自定义模板
  4. 复制static/静态资源
  5. 生成静态HTML到public/目录
  6. --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_KEYSSH私钥(ed25519格式)-----BEGIN OPENSSH PRIVATE KEY-----...
SERVER_HOST服务器IP或域名47.93.8.184
SERVER_USERSSH登录用户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秒拉取代码和子模块
安装Hugo20秒下载并安装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验证

为什么使用子目录部署

  1. 灵活性:根目录可以放置其他内容(如导航页)
  2. 扩展性:未来可以添加其他子应用(如API、管理后台)
  3. 隔离性:博客更新不影响根目录内容
  4. 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;
    }
}

配置要点

  1. HTTP到HTTPS重定向:所有HTTP请求自动跳转到HTTPS
  2. HTTP/2支持:提升页面加载速度
  3. 静态资源缓存:图片缓存30天,CSS/JS缓存7天
  4. Gzip压缩:压缩文本类文件,减少传输大小
  5. 安全头:防止XSS、点击劫持等攻击
  6. 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

核心功能

  1. PV统计:总访问量(Page Views)
  2. UV统计:独立访客数(基于IP哈希)
  3. 今日统计:今日PV和UV
  4. 防刷机制:同一IP 60秒内只计数一次
  5. 隐私保护: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 次

工作原理

  1. 页面加载时调用POST /api/stats/visit记录访问
  2. 同时调用GET /api/stats获取统计数据
  3. JavaScript格式化数字(千分位逗号)
  4. 失败时显示"-",不影响页面使用

服务管理

# 查看服务状态
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

引用方式

![描述](/images/2026-01-29/screenshot.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系统,具有以下特点:

核心优势

  1. 高度自动化

    • Git推送即部署
    • 2-3分钟自动完成
    • 无需人工干预
  2. 零成本运营

    • 使用GitHub Actions免费额度
    • 复用现有服务器和域名
    • Let’s Encrypt免费SSL证书
  3. 模块化设计

    • 支持多专题独立管理
    • 清晰的目录结构
    • 易于扩展和维护
  4. 自主可控

    • 自建访客统计系统
    • 数据完全掌控
    • 隐私保护
  5. 性能优异

    • 静态网站,首页加载<2秒
    • Gzip压缩,减少传输大小
    • 静态资源缓存,提升访问速度

技术亮点

  • Git子模块管理主题:方便主题更新
  • rsync增量同步:只传输变更文件
  • Nginx反向代理:统一API访问
  • Systemd服务管理:自动启动和重启
  • acme.sh自动续期:SSL证书永不过期

适用场景

这套方案适合:

  • 个人技术博客
  • 团队文档站点
  • 项目展示页面
  • 静态网站托管

核心工作流

写作(2分钟) → Git推送(即时) → Actions构建(1.5分钟) → rsync部署(30秒) → 网站生效(即时)

所有配置文件、脚本、文档都已完整保存在项目中,可以作为DevOps实践的完整案例参考。


参考资料