Pelican 静态博客网站详细部署指南
本文档提供从零开始在云服务器上部署 Pelican 静态博客的完整步骤,涵盖本地blog编写和预览环境、Gitee 仓库配置、服务器部署和自动化发布。
1. 环境概述
1.1 目标环境
| 项目 | 配置 |
|---|---|
| 服务器 | CentOS 9 Stream |
| Web 服务器 | Nginx 1.20.1 |
| Python 版本 | Python 3.11 |
| 虚拟环境管理 | uv |
| Git 版本 | 2.43 |
| 域名 | chenlip.top |
1.2 服务器目录结构
/home/app/my_blog/ # 博客根目录(blog + webhook 统一管理)
├── .venv/ # uv 虚拟环境(Python 3.11)
│ ├── ...
├── content/ # 内容目录(从 Gitee 拉取)
│ ├── articles/ # - 文章
│ ├── pages/ # - 页面
│ ├── images/ # - 图片
│ ├── downloads/ # - 下载附件(.zip/.rar/.7z)
│ └── media/ # - 音视频(<10MB)
├── output/ # Pelican 生成的文件
├── pelicanconf.py # 开发配置
├── publishconf.py # 生产配置
├── webhook_server.py # Webhook 服务(fastapi)
├── rebuild.sh # 构建脚本
├── requirements.txt # Python 依赖
└── .env # 环境变量
1.3 本地blog编写和预览环境(Windows 10或linux)
以下的本地日志编写和管理环境, 如果是linux环境, 请自行使用对应的命令即可
对于window环境, 个人习惯是使用 CMD 终端,所以下面的命令基本都是基于。
你的本地环境用于编写和预览博客内容,服务器负责构建和发布。
| 项目 | 你的环境(请先准备好以下工具) | 说明 |
|---|---|---|
| 操作系统 | Windows 10 | 本地开发机 |
| Python | Python 3.11 | 已安装 ✅ |
| 包管理器 | uv 0.11 | 已安装 ✅ |
| Git | 已安装 | 代码版本控制 ✅ |
| 本地项目目录 | D:\pythonapp\my_blog |
博客源码存放位置 |
2. 本地日志编写和管理环境搭建
⚠️ 以下的本地日志编写和管理环境, 如果是linux环境, 请自行使用对应的命令即可
⚠️ 对于window环境, 个人习惯是使用 CMD 终端,所以下面的命令基本都是基于。
2.1 创建本地项目目录
:: 在 D:\pythonapp(可以是你想要的任何目录) 目录下创建博客项目
cd D:\pythonapp
git clone https://gitee.com/hoeking/my_blog.git
2.2 使用 uv 创建虚拟环境
:: 进入项目目录
cd D:\pythonapp\my_blog
:: 使用 uv 创建 Python 3.11 虚拟环境
uv venv .venv --python 3.11.14
:: 激活虚拟环境 (CMD)
.venv\Scripts\activate
:: 验证
where python
python --version
2.3 安装 Pelican 及依赖
:: 激活虚拟环境后执行
uv pip install "pelican[markdown]"
:: 安装 Invoke(Windows 上替代 Makefile 的官方推荐工具)
uv pip install invoke
:: 安装 livereload(开发时浏览器自动刷新,强烈推荐)
uv pip install livereload
:: 安装完成后验证
pelican --version
invoke --version
为什么需要 invoke 和 livereload?
- Windows 没有
make命令,无法使用Makefile,Invoke 是官方推荐的 Windows 替代方案invoke livereload可以实现修改文件后浏览器自动刷新,是最高效的本地开发方式- 如果暂时不想安装,也可以用纯
pelican命令开发(见 2.7 节方法一、二)
2.4 初始化 Pelican 项目(如果是直接git clone, 则无需初始化)
:: 在 my_blog 目录下执行
pelican-quickstart
# 回答交互式问题:
# > Where do you want to create your new website? [.]
# > What will be the title of this web site? Chen's Blog
# > Who will be the author of this web site? Chen Li
# > What will be the default language of this website? [zh]
# > What is the URL of your website? https://chenlip.top
# > Do you want to specify a URL prefix? [Y/n] n
# > Do you want to enable article pagination? [Y/n] n
# > Do you want to generate a tasks.txt file? [y/N] n
# > Do you want to upload website to GitHub? [y/N] n
2.5 本地目录结构
初始化后,D:\pythonapp\my_blog 目录结构如下:
D:\pythonapp\my_blog\
├── .venv/ # uv 虚拟环境
│ └── Scripts/ # - Windows 激活脚本
├── content/ # 博客文章目录 ⭐ 你在这里写文章
│ ├── articles/ # - 文章 (md 文件)
│ ├── pages/ # - 页面
│ ├── images/ # - 图片
│ ├── downloads/ # - 下载附件
│ └── media/ # - 音视频 (<10MB)
├── output/ # 生成的静态文件
├── pelicanconf.py # 开发配置
├── publishconf.py # 生产配置
├── tasks.py # Invoke 构建任务(Windows 开发环境推荐使用)
├── Makefile # 构建脚本(仅 Linux/macOS 可用,Windows 无法使用 ❌)
└── develop_server.sh # 开发服务器脚本(仅 Linux/macOS 可用,Windows 无法使用 ❌)
⚠️ Windows 重要说明:
Makefile和develop_server.sh是Linux下的pelican-quickstart自动生成的,但它们仅适用于 Linux/macOS(POSIX 系统)- Windows 环境下应使用 Invoke(
tasks.py)或直接使用 pelican 命令来替代make- 这两个文件可以保留在项目中(供服务器端使用),但本地开发时不要尝试用
make命令
2.6 创建示例文章(如果是克隆的项目, 里面已经有示例了)
# 创建
2.7 使用 dev_win.bat启动(推荐)
⚠️ 重要:Windows 本地开发必须使用
.bat启动,否则会遇到编码问题!
2.7.1 创建 dev_win.bat
在 D:\pythonapp\my_blog 目录下创建 dev_win.bat 文件:
@echo off
chcp 65001 >nul
set PYTHONUTF8=1
cd /d %~dp0
call .venv\Scripts\activate.bat
echo Starting Pelican livereload server...
start http://localhost:11326
invoke livereload
pause
2.7.2 使用方法
:: 进入博客目录
cd D:\pythonapp\my_blog
:: 双击 dev_win.bat或在 CMD 中运行
dev_win.bat
2.7.3 常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
运行后报错 UnicodeDecodeError |
未使用 dev_win.bat启动 | 双击 dev_win.bat运行 |
| 提示 "不是内部或外部命令" | 虚拟环境未激活 | 确保 .venv\Scripts\activate.bat 可执行 |
Invoke 常用开发命令速查:
命令 作用 invoke build生成静态文件 invoke regenerate自动检测变化并重新生成 invoke serve启动本地预览服务器 invoke livereload自动重生成 + 浏览器自动刷新 ⭐推荐
2.8 本地开发常用命令
:: ============ 激活虚拟环境 ============
.venv\Scripts\activate
:: ============ 生成静态文件 ============
pelican content/ -s pelicanconf.py
:: ============ 启动预览服务器 ============
pelican --listen --port 8000
:: ============ 自动监听修改并重新生成(单独运行) ============
pelican --autoreload content/ -s pelicanconf.py
:: ============ Windows 上的开发工作流 ============
:: 终端1:启动自动重载(监听文件变化)
pelican -r content/ -s pelicanconf.py
:: 终端2:启动预览服务器(另开一个 CMD 窗口)
pelican --listen --port 8000
:: ============ 使用 Invoke(推荐) ============
invoke build :: 生成静态文件
invoke regenerate :: 自动检测变化并重新生成
invoke serve :: 启动预览服务器
invoke livereload :: 自动重生成 + 浏览器自动刷新 ⭐
:: ============ 清理生成的文件 ============
pelican --clean content/ -s pelicanconf.py
⚠️ Windows 重要提醒:
pelican -r -l(即--autoreload --listen组合)在 Windows 上不能同时使用,必须分两个终端窗口分别运行。这是 Pelican 官方文档明确指出的限制。
3. Gitee 仓库配置
3.1 为什么需要 Gitee 仓库?
┌─────────────────┐ git push ┌─────────────────┐
│ 本地 D:\pythonapp │ ────────────────→ │ Gitee 仓库 │
│ \my_blog │ │ hoeking/my_note │
└─────────────────┘ └────────┬────────┘
│
webhook 触发
│
▼
┌─────────────────┐
│ 云服务器 │
│ /home/app/my_blog │
│ (自动构建发布) │
└────────┬────────┘
│
▼
┌─────────────────┐
│ https:// │
│ chenlip.top │
└─────────────────┘
流程说明:
- 你在本地
D:\pythonapp\my_blog编写博客 - 使用
git push推送到 Gitee - Gitee 发送 Webhook 通知到服务器
- 服务器自动拉取代码、构建、发布
3.2 创建 Gitee 仓库
- 登录 Gitee
- 点击右上角 "+" → "新建仓库"
- 填写信息:
| 配置项 | 值 |
|---|---|
| 仓库名称 | my_note 或 my_blog |
| 路径 | hoeking/my_note |
| 仓库公开性 | 公开(Webhook 需要) |
| 勾选 | ✅ 使用 README 初始化仓库(可选) |
- 点击 "创建"
3.3 初始化本地 Git 并推送到 Gitee
# 进入本地项目目录
cd D:\pythonapp\my_blog
# 初始化 Git(如果还没有初始化)
git init
# 添加远程仓库
git remote add origin https://gitee.com/hoeking/my_note.git
# 添加所有文件
git add .
# 提交
git commit -m "初始化 Pelican 博客项目"
# 推送到 Gitee(首次推送)
git push -u origin master
3.4 验证推送成功
在 Gitee 仓库页面刷新,确认文件已上传。
4. 服务器环境准备
2.1 配置防火墙
# 开放 HTTP(80)和 HTTPS(443)端口
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
# 重载防火墙
firewall-cmd --reload
# 查看已开放的端口
firewall-cmd --list-all
2.2 配置 SELinux(我的服务器上这个是禁用状态的, 所以这步可以跳过)
# 检查 SELinux 状态
getenforce
# 如果是 Enforcing 模式,需要配置
setsebool -P httpd_can_network_connect on
setsebool -P httpd_read_user_content on
5. 创建博客目录并初始化虚拟环境
3.1 创建目录
# 创建博客目录
mkdir -p /home/app/my_blog
3.2 使用 uv 创建 Python 3.11 虚拟环境
cd /home/app/my_blog
# 使用 uv 创建 Python 3.11 虚拟环境
uv venv .venv --python 3.11.14
# 激活虚拟环境
source .venv/bin/activate
# 验证
python --version # 应显示 Python 3.11.x
3.3 在虚拟环境中安装依赖
# 激活虚拟环境(后续操作都需要先激活)
source /home/app/my_blog/.venv/bin/activate
# 安装 Pelican 和 Markdown 支持
pip install "pelican[markdown]"
# 安装 Webhook 服务依赖
pip install fastapi uvicorn python-dotenv httpx
# 验证安装
pelican --version
6. 初始化博客配置
4.1 在本地初始化项目
在本地 Windows 机器上操作:
:: 创建博客项目
cd D:\pythonapp
mkdir my_blog
cd my_blog
:: 初始化 Pelican(交互式)
pelican-quickstart
:: 回答问题:
:: > Where do you want to create your new website? [.]
:: > What will be the title of this web site? Chen's Blog
:: > Who will be the author of this web site? Chen Li
:: > What will be the default language of this website? [zh]
:: > What is the URL of your website? https://chenlip.top
:: > Do you want to specify a URL prefix? e.g., https://example.com [Y/n] n
:: > Do you want to enable article pagination? [Y/n] n
:: > Do you want to generate a tasks.txt Accumulo file? [y/N] n
:: > Do you want to upload website to GitHub? [y/N] n
4.2 配置文件说明
pelicanconf.py(开发配置):
#!/usr/bin/env python
# -*- coding: utf-8 -*- #
from __future__ import annotations
# ===========================================
# 基础配置
# ===========================================
SITENAME = "Chen's Blog"
SITEURL = "http://localhost:8000"
AUTHOR = "Chen Li"
SITESUBTITLE = "技术分享与生活记录"
DESCRIPTION = "分享技术心得与生活感悟"
# 路径配置
PATH = "content"
OUTPUT_PATH = "output"
THEME = "themes/notmyidea"
# 文章配置
ARTICLE_PATHS = ["articles"]
PAGE_PATHS = ["pages"]
STATIC_PATHS = ["images", "downloads", "media", "extra"]
# URL 配置
ARTICLE_URL = "articles/{slug}.html"
ARTICLE_SAVE_AS = "articles/{slug}.html"
PAGE_URL = "pages/{slug}.html"
PAGE_SAVE_AS = "pages/{slug}.html"
# ===========================================
# 分类和标签
# ===========================================
USE_FOLDER_AS_CATEGORY = True
DEFAULT_CATEGORY = "杂项"
DISPLAY_CATEGORIES_ON_MENU = True
DISPLAY_TAGS_ON_MENU = True
# 标签云
TAG_CLOUD_MAX_ITEMS = 50
TAG_CLOUD_STEPS = 4
# ===========================================
# 时间配置
# ===========================================
WITH_FUTURE_DATES = True
DEFAULT_DATE_FORMAT = "%Y-%m-%d"
# ===========================================
# 开发选项(本地预览配置)
# ===========================================
# 本地预览时显示所有文章(包括草稿、隐藏等)
DEBUG = True
# 显示草稿文章(draft 状态)
INCLUDE_DRAFTS = True
# 显示隐藏文章(hidden 状态)
HIDDEN_INCLUDE = True
# 保留历史文件,不删除输出目录
DELETE_OUTPUT_DIRECTORY = False
# 使用缓存加速构建
LOAD_CONTENT_CACHE = True
# 静态文件
STATIC_CREATE_LINKS = True
STATIC_EXCLUDE_SOURCES = False
# ===========================================
# 忽略文件配置
# ===========================================
# Pelican 构建时会忽略以下匹配模式的文件
# 这对 webhook 自动构建也有效:即使 git pull 了这些文件,构建时也会被跳过
IGNORE_FILES = [
'.*', # 所有隐藏文件 (.gitignore, .DS_Store 等)
'_*', # 以下划线开头的文件和目录
'*.bak', # 备份文件
'*.tmp', # 临时文件
'*.swp', # Vim 交换文件
'*~', # Emacs 备份文件
'draft-*', # 以 draft- 开头的文件
'private-*', # 以 private- 开头的文件
]
# 排除特定目录下的内容(仅处理 articles 和 pages 目录)
ARTICLE_EXCLUDES = ['temp', 'archive', '_drafts', '_private', 'drafts', 'private']
PAGE_EXCLUDES = ['temp', 'archive', '_drafts', '_private']
# 不纳入版本控制的临时目录
EXCLUDES = ['.git', '.venv', '__pycache__', 'node_modules', 'temp']
# ===========================================
# Markdown 支持
# ===========================================
MARKDOWN = {
"extensions": [
"meta",
"extra",
"codehilite",
"toc",
"tables",
"fenced_code",
],
"extension_configs": {
"markdown.extensions.toc": {"title": "目录"},
},
}
# 分页(禁用)
DEFAULT_PAGINATION = False
# ===========================================
# 站点地图 (Sitemap)
# ===========================================
SITEMAP = {
"format": "xml",
"priorities": {
"articles": 0.7,
"pages": 0.5,
"indexes": 0.5,
},
"changefreqs": {
"articles": "monthly",
"pages": "weekly",
"indexes": "daily",
},
}
# ===========================================
# 评论系统 (Valine - 基于 LeanCloud)
# ===========================================
# 使用 Valine 无需后端,直接集成 LeanCloud
# 配置方法见文档后续章节
# Valine 国内访问速度快,适合国内用户
# ===========================================
# 搜索功能 (Tipue Search)
# ===========================================
# 使用 Tipue Search 实现静态站点搜索,无需后端
SEARCH_MODE = "static"
SEARCH_EXTERNAL = ""
DIRECT_TEMPLATES = ["index", "tags", "categories", "archives", "sitemap", "search"]
TEMPLATE_PAGES = {"search": "search.html"}
# ===========================================
# 社交链接
# ===========================================
SOCIAL = (
("GitHub", "https://github.com/yourusername"),
("Email", "mailto:your@email.com"),
)
# ===========================================
# 版权信息
# ===========================================
COPYRIGHT_YEAR = 2024
3.1.3 附件与音视频目录配置
Pelican 的 STATIC_PATHS 配置用于指定哪些目录作为静态资源目录,这些目录下的文件会被复制到输出目录:
# 静态文件路径配置
STATIC_PATHS = [
"images", # 图片目录
"downloads", # 下载附件(.zip/.rar/.7z)
"media", # 音视频目录(<10MB)
"extra", # 额外静态文件
]
目录结构说明:
content/
├── images/ # 图片文件
├── downloads/ # 下载附件
│ ├── source-code/ # - 源码包
│ ├── templates/ # - 模板文件
│ └── documents/ # - PDF文档
├── media/ # 音视频文件
│ ├── videos/ # - 视频 (<10MB)
│ └── audios/ # - 音频 (<10MB)
└── extra/ # 额外静态文件
⚠️ 重要:本地开发配置和服务器配置必须保持
STATIC_PATHS一致!
publishconf.py(生产配置):
publishconf.py(生产配置):
#!/usr/bin/env python
# -*- coding: utf-8 -*- #
from __future__ import annotations
# 从 pelicanconf.py 导入基础配置
from pelicanconf import *
# ===========================================
# 生产环境配置
# ===========================================
SITEURL = "https://chenlip.top"
RELATIVE_URLS = False
# ⚠️ 重要:生产环境必须关闭草稿预览,确保草稿不会被发布
INCLUDE_DRAFTS = False
HIDDEN_INCLUDE = False
# 忽略文件配置(继承自 pelicanconf.py,保持不变)
# 注意:即使 git pull 拉取了这些文件,构建时也会被过滤,不会发布
# 生产环境需要删除输出目录以确保干净
DELETE_OUTPUT_DIRECTORY = False # 保持增量更新
# 启用缓存以加快构建速度
LOAD_CONTENT_CACHE = True
# ===========================================
# RSS/Atom 订阅
# ===========================================
FEED_ALL_ATOM = "feeds/all.atom.xml"
CATEGORY_FEED_ATOM = "feeds/{slug}.atom.xml"
TAG_FEED_ATOM = "feeds/{slug}.atom.xml"
FEED_RSS = "feeds/all.rss.xml"
# ===========================================
# Google Analytics(可选)
# ===========================================
# GOOGLE_ANALYTICS = "G-XXXXXXXXXX"
# ===========================================
# 结束时启用
# ===========================================
import sys
if len(sys.argv) > 1 and sys.argv[1] == "publish":
pass
4.3 创建内容目录结构
:: 创建内容目录
mkdir content\articles\tech
mkdir content\articles\life
mkdir content\pages
mkdir content\images
mkdir content\downloads\source-code
mkdir content\downloads\templates
mkdir content\media\videos
mkdir content\media\audios
mkdir content\drafts
创建示例文章 content\articles\hello-world.md(用编辑器创建,内容如下):
Title: 欢迎来到我的博客
Date: 2024-01-01 10:00
Category: 杂项
Tags: 欢迎, 博客
Slug: welcome
这是我的第一篇博客文章!
## 关于我
我是一名软件开发者,喜欢分享技术文章。
提示:Windows CMD 不支持
cat > file << 'EOF'和mkdir -p,请直接用编辑器创建文件,目录需逐级创建。
7. 高级功能配置
5.1 安装插件(站点地图、搜索等)
# 激活虚拟环境
source /home/app/my_blog/.venv/bin/activate
# 安装 pelican 插件(如果主题需要)
pip install pelican-plugin-render-math pelican-tiptap
5.2 配置站点地图 (Sitemap)
Pelican 内置 sitemap 插件,无需额外安装。
启用方式:在 pelicanconf.py 中已配置 SITEMAP 字典。
生成的文件:
sitemap.xml- 站点地图
验证:构建后在 output/ 目录检查 sitemap.xml 文件。
5.3 配置标签 (Tags)
Pelican 原生支持标签功能。
使用方法:在文章 metadata 中添加 Tags:
Title: 我的第一篇文章
Date: 2024-01-01 10:00
Category: 技术
Tags: Python, Pelican, 博客
Slug: my-first-post
文章内容...
标签云页面:访问 /tags/ 查看所有标签。
配置标签云样式(在 THEME/templates 目录的 CSS 中):
.tag-cloud {
font-family: Arial, sans-serif;
}
.tag-1 { font-size: 0.8em; }
.tag-2 { font-size: 1.0em; }
.tag-3 { font-size: 1.2em; }
.tag-4 { font-size: 1.5em; }
5.4 配置评论系统 (Valine)
Valine 是一款基于 LeanCloud 的轻量级评论系统,无需后端,直接通过 LeanCloud API 存储评论数据。国内访问速度快,配置简单。
5.4.1 注册 LeanCloud 并创建应用
- 访问 LeanCloud 官网,注册账号并登录
- 进入控制台,点击 "创建应用"
- 输入应用名称(如
my-blog-comments),选择 "开发版" - 创建完成后,进入 "应用设置 → 应用Key"
- 记录以下两个关键信息:
- AppID
- AppKey
5.4.2 配置安全域名
⚠️ 重要:必须配置安全域名,否则评论功能无法正常使用。
在 LeanCloud 控制台中:
- 进入 "应用设置 → 安全中心"
- 在 "安全域名" 中添加你的博客域名,例如:
https://chenlip.tophttps://www.chenlip.top- 保存设置
5.4.3 安装 Valine
方式一:CDN 引入(推荐)
在博客主题的 HTML 模板 <head> 中添加:
<!-- Valine 依赖的 LeanCloud SDK -->
<script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
<!-- Valine 核心脚本 -->
<script src='//unpkg.com/valine/dist/Valine.min.js'></script>
方式二:NPM 安装(适合前端开发者)
npm install valine --save
import Valine from 'valine';
5.4.4 在模板中添加评论框
编辑博客主题的 article.html 模板文件,在文章底部添加评论区域:
<!-- Valine 评论系统 -->
{% if article and article.status != 'draft' %}
<div id="vcomments" class="comments-area"></div>
<script>
new Valine({
el: '#vcomments',
appId: '你的LeanCloud AppID',
appKey: '你的LeanCloud AppKey',
placeholder: '欢迎留言交流!',
avatar: 'mm',
meta: ['nick', 'mail', 'link'],
requiredFields: ['nick', 'mail'],
pageSize: 10,
lang: 'zh-CN',
visitor: true,
highlight: true,
recordIP: false,
enableQQ: false
});
</script>
{% endif %}
5.4.5 基础配置参数说明
| 参数 | 说明 | 默认值 |
|---|---|---|
el |
评论框容器元素选择器 | #vcomments |
appId |
LeanCloud AppID | 必填 |
appKey |
LeanCloud AppKey | 必填 |
placeholder |
评论框占位文字 | '说点什么吧...' |
avatar |
头像样式:mm/identicon/monsterid/wavatar/retro |
'mm' |
meta |
评论者信息字段 | ['nick', 'mail', 'link'] |
requiredFields |
必填字段 | ['nick'] |
pageSize |
每页评论数 | 10 |
lang |
语言设置 | 'zh-CN' |
visitor |
开启文章访问量统计 | false |
highlight |
代码高亮 | true |
5.4.6 进阶配置
邮件通知功能:
Valine 支持评论通知,但需要额外配置(可选)。
评论样式自定义:
在主题的 CSS 文件中添加自定义样式:
/* Valine 评论框样式 */
#vcomments {
padding: 20px 0;
}
.v[data-class=v] .vcard {
padding: 10px 0;
}
.v[data-class=v] .vcontent {
font-size: 15px;
line-height: 1.8;
}
/* 评论输入框 */
.veditor {
min-height: 120px;
resize: vertical;
}
/* 提交按钮 */
.vsubmit {
background: #3498db;
color: #fff;
border: none;
padding: 8px 20px;
border-radius: 4px;
cursor: pointer;
}
5.4.7 评论数据管理
在 LeanCloud 控制台中:
- 选择你的应用
- 进入 "存储 → Comment" 类
- 可以查看、编辑、删除所有评论数据
5.4.8 常见问题排查
| 问题 | 解决方案 |
|---|---|
| 评论框不显示 | 检查 AppID/AppKey 是否正确,确认安全域名已配置 |
| 评论提交失败 | 检查浏览器控制台错误信息,确认网络连接正常 |
| 加载缓慢 | 尝试使用 NPM 方式本地加载,或更换 CDN 源 |
| 头像不显示 | Valine 使用 Gravatar 头像,确保评论者邮箱已注册 Gravatar |
5.4.9 Valine vs Giscus 对比
| 特性 | Valine | Giscus |
|---|---|---|
| 数据存储 | LeanCloud | GitHub Discussions |
| 国内访问 | ✅ 快速 | ❌ 可能不稳定 |
| 无需数据库 | ✅ | ✅ |
| 配置复杂度 | 低 | 低 |
| 依赖外部服务 | LeanCloud | GitHub |
| 适合场景 | 国内用户为主 | 面向全球/技术社区 |
5.5 配置访问统计功能
静态博客无法在后端直接记录访问量,需要借助第三方服务。以下介绍两种方案。
5.5.1 方案一:不蒜子(Busuanzi)- 最简单
不蒜子是一个轻量级的网站统计服务,只需一行代码即可集成,国内访问速度快。
1. 在模板中添加统计脚本
编辑博客主题的 base.html 或 footer.html,在 </body> 前添加:
<!-- 不蒜子统计 -->
<script async src="//busuanzi.icodeq.com/busuanzi/2.3/busuanzi.pure.mini.js"></script>
2. 显示页面阅读量
在文章页面 article.html 中添加阅读量显示位置:
<!-- 文章阅读量 -->
<span id="busuanzi_value_page_pv" class="page-view-count">0</span> 次阅读
3. 显示全站访客量(可选)
在页脚 footer.html 或侧边栏添加:
<!-- 全站访客统计 -->
<span id="busuanzi_value_site_pv">0</span> 次访问
<span id="busuanzi_value_site_uv">0</span> 位访客
4. CSS 样式自定义
/* 阅读量样式 */
.page-view-count {
color: #666;
font-size: 14px;
margin-left: 5px;
}
/* 悬停提示 */
.page-view-count:hover {
color: #3498db;
}
5. 不蒜子常用标签说明
| 标签 ID | 说明 | 示例 |
|---|---|---|
busuanzi_value_site_pv |
全站总访问量 | 1000 次访问 |
busuanzi_value_site_uv |
全站总访客数 | 500 位访客 |
busuanzi_value_page_pv |
当前页面访问量 | 100 次阅读 |
5.5.2 方案二:Valine Visitor(与评论系统共用)
如果你已集成 Valine 评论系统,可以直接开启 visitor 功能来统计文章阅读量,无需额外注册其他服务。
1. 修改 Valine 初始化配置
编辑 article.html 中的 Valine 配置,确保开启 visitor 选项:
<script>
new Valine({
el: '#vcomments',
appId: '你的LeanCloud AppID',
appKey: '你的LeanCloud AppKey',
placeholder: '欢迎留言交流!',
avatar: 'mm',
visitor: true, <!-- 开启文章阅读量统计 -->
// ...其他配置
});
</script>
2. 显示阅读量
Valine 会自动在评论区域上方显示阅读量。如需自定义显示位置,可在文章模板中添加:
<!-- Valine 阅读量(可选自定义显示) -->
<span class="article-visitor" id="<文章ID>-visitors">
阅读: <span class="leancloud-visitors-count">0</span>
</span>
其中 <文章ID> 需要与 Valine 生成的 ID 一致,通常格式为 url_key-文章slug。
3. 在文章元信息中显示阅读量
编辑 article.html 模板,在文章标题下方添加阅读量:
<article class="post">
<header class="post-header">
<h1 class="post-title">{{ article.title }}</h1>
<div class="post-meta">
<span class="post-date">{{ article.date.strftime('%Y-%m-%d') }}</span>
<span class="post-category">{{ article.category }}</span>
<!-- 阅读量显示 -->
<span class="post-views">
<i class="icon-view"></i>
<span class="leancloud-visitors-count" id="{{ article.url }}-visitors">0</span> 阅读
</span>
</div>
</header>
<!-- 文章内容 ... -->
</article>
4. CSS 样式
/* 阅读量样式 */
.post-views {
color: #888;
font-size: 14px;
margin-left: 15px;
}
.post-views .leancloud-visitors-count {
color: #e74c3c;
font-weight: bold;
}
5.5.3 两种方案对比
| 特性 | 不蒜子 | Valine Visitor |
|---|---|---|
| 集成复杂度 | ⭐ 最简单(一行代码) | ⭐⭐ 需开启配置 |
| 数据存储 | 第三方服务器 | LeanCloud |
| 国内访问 | ✅ 快速 | ✅ 快速 |
| 是否需要注册 | ❌ 无需注册 | ✅ 需 LeanCloud |
| 功能 | 简单统计 | 评论 + 统计一体化 |
| 可自定义程度 | 中等 | 高 |
5.5.4 同时使用两种方案(互为备份)
如果希望同时使用两种统计方式,可以都集成,显示阅读量时取其中一个来源的数据:
<!-- 双统计(实际使用时可只显示一个) -->
<span class="view-count">
阅读: <span id="busuanzi_value_page_pv">0</span> 次
<!-- 或使用 Valine: -->
<!-- <span class="leancloud-visitors-count">0</span> 次 -->
</span>
5.7 配置搜索功能 (Tipue Search)
Tipue Search 是一个纯静态的 JavaScript 搜索方案。
1. 安装 Tipue Search 插件:
pip install pelican-tipue-search
2. 在 pelicanconf.py 中启用:
PLUGINS = ['tipue_search']
DIRECT_TEMPLATES = ['index', 'tags', 'categories', 'archives', 'sitemap', 'search']
TEMPLATE_PAGES = {'search': 'search.html'}
TIPUE_SEARCH = True
TIPUE_SEARCH_MODE = 'static'
3. 创建搜索页面模板(THEME/templates/search.html):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>搜索 - {{ SITENAME }}</title>
<link rel="stylesheet" href="{{ SITEURL }}/theme/css/normalize.css">
<link rel="stylesheet" href="{{ SITEURL }}/theme/css/tipuesearch.css">
</head>
<body>
<h1>搜索</h1>
<form action="{{ SITEURL }}/search.html">
<input type="text" name="q" id="tipue_search_input" placeholder="输入关键词搜索...">
<button type="submit">搜索</button>
</form>
<div id="tipue_search_content"></div>
<script src="{{ SITEURL }}/theme/js/tipuesearch_set.js"></script>
<script src="{{ SITEURL }}/theme/js/tipuesearch.js"></script>
<script>
tipuesearch({"show": 10, "newWindow": false});
</script>
</body>
</html>
4. 下载 Tipue Search 文件:
# 创建目录
mkdir -p themes/your-theme/static/js
mkdir -p themes/your-theme/static/css
# 下载 Tipue Search 文件(从官网下载)
# https://tipue.com/search/
# 需要:tipuesearch.js, tipuesearch_set.js, tipuesearch.css, tipuesearch.img/
5.8 标签和分类的区别
| 特性 | 标签 (Tags) | 分类 (Categories) |
|---|---|---|
| 数量限制 | 文章可有多个标签 | 文章只能属于一个分类 |
| 层级 | 扁平结构 | 可嵌套层级 |
| 用途 | 关键词/主题 | 主要主题分组 |
| 页面 | /tags/ |
/category/ |
示例:
Title: 学习 Python 列表
Category: 编程 # 只能一个
Tags: Python, 列表, 入门 # 可以多个
8. 配置 Nginx
5.1 创建 Nginx 配置文件
nano /etc/nginx/conf.d/blog.conf
配置文件内容:
server {
listen 80;
server_name chenlip.top www.chenlip.top;
# 重定向到 HTTPS(可选,如已配置 SSL)
# return 301 https://$server_name$request_uri;
# 博客根目录
root /home/app/my_blog/output;
# 日志
access_log /var/log/nginx/blog_access.log;
error_log /var/log/nginx/blog_error.log;
# 默认首页
index index.html;
# 字符集
charset utf-8;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
application/x-javascript application/xml application/rss+xml
application/atom+xml image/svg+xml;
# 静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 安全 headers
location ~ /\. {
deny all;
}
# 主路由
location / {
try_files $uri $uri/ $uri.html =404;
}
# 禁止访问隐藏文件
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}
# HTTPS 配置(可选,如需要)
# server {
# listen 443 ssl http2;
# server_name chenlip.top www.chenlip.top;
#
# ssl_certificate /etc/letsencrypt/live/chenlip.top/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/chenlip.top/privkey.pem;
#
# root /var/www/blog/output;
# index index.html;
#
# # ... 其他配置同上
# }
5.2 测试并重载 Nginx
# 测试配置语法
nginx -t
# 重载 Nginx
systemctl reload nginx
# 启用开机自启
systemctl enable nginx
9. 配置 Git 仓库
6.1 在服务器上克隆仓库
# 切换到博客目录
cd /home/app/my_blog
# 克隆 Gitee 仓库(使用 HTTPS)
git clone https://gitee.com/hoeking/my_note.git .
# 或者使用 SSH(如果已配置密钥)
# git clone git@gitee.com:hoeking/my_note.git .
# 查看克隆的内容
ls -la
6.2 配置 Git 钩子(可选)
# 创建 post-merge 钩子(每次 git pull 后自动构建)
cat > .git/hooks/post-merge << 'EOF'
#!/bin/bash
# 自动构建博客(可选,按需启用)
# /home/app/my_blog/rebuild.sh
EOF
chmod +x .git/hooks/post-merge
10. 配置 Webhook 服务
7.1 创建 Python 依赖文件
# 激活虚拟环境
source /home/app/my_blog/.venv/bin/activate
# 创建 requirements.txt
cat > /home/app/my_blog/requirements.txt << 'EOF'
pelican[markdown]
fastapi
uvicorn[standard]
python-dotenv
httpx
EOF
7.2 创建 Webhook 服务脚本
# 创建 /home/app/my_blog/webhook_server.py, 请参考项目中的 webhook_server.py 文件
chmod +x /home/app/my_blog/webhook_server.py
7.3 创建构建脚本
# 创建 /home/app/my_blog/rebuild.sh, 请参考项目中的 rebuild.sh 文件
chmod +x /home/app/my_blog/rebuild.sh
# 创建日志文件
touch /var/log/pelican-rebuild.log
7.4 创建环境变量文件
# 创建 .env 文件, 请参考项目中的 .env 文件
cat > /home/app/my_blog/.env << 'EOF'
WEBHOOK_SECRET=xiongxiong-is-cool
EOF
7.5 配置 Systemd 服务
# 创建 systemd 服务文件, 请参考项目中的 blog-webhook.service 文件
cat > /etc/systemd/system/blog-webhook.service << 'EOF'
....
EOF
# 重新加载 systemd
systemctl daemon-reload
# 启动服务
systemctl start blog-webhook
# 检查状态
systemctl status blog-webhook
# 启用开机自启
systemctl enable blog-webhook
7.6 配置反向代理(可选)
如果您希望使用域名访问 Webhook 管理界面:
# /etc/nginx/conf.d/webhook.conf
server {
listen 80;
server_name webhook.chenlip.top;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
7.7 忽略文件与 Webhook 构建流程
Webhook 自动构建时,pelicanconf.py 中的 IGNORE_FILES 配置会自动生效:
┌─────────────────────────────────────────────────────────────┐
│ 1. Git Push 触发 Webhook │
└─────────────────────┬───────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. 服务器执行 rebuild.sh │
│ - git pull 拉取所有文件(包括 _drafts/、*.bak 等) │
└─────────────────────┬───────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. Pelican 构建时自动过滤 │
│ - 根据 pelicanconf.py 的 IGNORE_FILES 配置 │
│ - 跳过以下划线开头的文件和目录 │
│ - 跳过 draft-*、private-* 等模式 │
│ - 只生成正常文章到 output/ 目录 │
└─────────────────────┬───────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────┐
│ 4. Nginx 发布 output/ 目录 │
│ - 草稿、临时文件不会出现在网站上 │
└─────────────────────────────────────────────────────────────┘
结论:无需额外配置,Pelican 会自动根据 IGNORE_FILES 在构建时过滤文件。
11. 配置 Gitee Webhook
8.1 在 Gitee 仓库设置 Webhook
- 登录 Gitee,进入
hoeking/my_note仓库 - 点击 管理 → WebHooks → 添加 WebHook
- 填写配置:
| 配置项 | 值 |
|---|---|
| WebHook 地址 | http://chenlip.top:5000/webhook 或 http://<服务器IP>:5000/webhook |
| 密钥 | 设置一个安全的密钥(如 MySecretKey123!) |
| 触发条件 | 选择 Push 事件 |
- 点击 添加
8.2 在服务器上设置密钥
# 编辑 .env 文件, 或者将 example.env 复制为 .env
cat > /home/app/my_blog/.env << 'EOF'
WEBHOOK_SECRET=MySecretKey123!
EOF
# 重启服务
systemctl restart blog-webhook
8.3 测试 Webhook
# 手动测试 Webhook
curl -X POST http://127.0.0.1:5000/webhook \
-H "Content-Type: application/json" \
-H "X-Gitee-Event: Push Hook" \
-d '{"ref": "refs/heads/master", "commits": []}'
# 检查服务日志
journalctl -u blog-webhook -f
12. 初始化博客内容
9.1 本地测试构建
在本地 Windows 机器上:
请参考上面 第 2 章 中的说明。开始编写博客文章。
9.2 推送到 Gitee
:: 初始化 Git(如果尚未初始化)
git init
git remote add origin https://gitee.com/hoeking/my_note.git
:: 添加所有文件
git add .
:: 提交
git commit -m "初始化博客项目"
:: 推送
git push -u origin master
9.3 触发首次构建
推送后,Gitee 会发送 Webhook 请求,服务器会自动构建博客(前提是服务端已经部署好环境并启动了 Webhook 服务)。
或者手动触发:
# 在服务器上
cd /home/app/my_blog
git pull origin master
/home/app/my_blog/rebuild.sh
13. 验证部署
10.1 检查服务状态
# 检查 Nginx
systemctl status nginx
# 检查 Webhook 服务
systemctl status blog-webhook
# 检查进程
ps aux | grep -E "nginx|pelican|uvicorn"
10.2 检查日志
# Nginx 访问日志
tail -f /var/log/nginx/blog_access.log
# Nginx 错误日志
tail -f /var/log/nginx/blog_error.log
# Webhook 服务日志
journalctl -u blog-webhook -f
# 构建日志
tail -f /var/log/pelican-rebuild.log
10.3 测试访问
# 测试 HTTP 访问
curl -I http://chenlip.top
# 测试 HTTPS(如果配置了)
curl -I https://chenlip.top
# 检查页面内容
curl -s http://chenlip.top | head -20
14. SSL/HTTPS 配置(可选但推荐)
11.1 安装 Certbot
# 安装 Certbot
dnf install -y epel-release
dnf install -y certbot python3-certbot-nginx
# 申请证书
certbot --nginx -d chenlip.top -d www.chenlip.top
11.2 自动续期
# 测试自动续期
certbot renew --dry-run
# 添加定时任务
crontab -e
# 添加:0 0 * * * certbot renew
15. 故障排查
12.1 常见问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| Webhook 无法访问 | 防火墙未开放 5000 端口 | 开放端口或使用反向代理 |
| 构建失败 | 权限问题 | 检查目录权限 |
| 页面样式丢失 | STATIC_PATH 配置错误 | 检查主题静态文件路径 |
| 中文乱码 | 文件编码问题 | 确保使用 UTF-8 编码 |
UnicodeDecodeError |
Windows 编码与文件编码不匹配 | 使用 dev_win.bat 启动(见下方说明) |
| Docutils 中文警告 | Docutils 无中文本地化 | 可忽略,不影响功能 |
12.2 Windows 本地开发编码问题详解
12.2.1 问题原因
Windows 中文版的默认编码是 GBK (代码页 936),而 Pelican 的内容文件(Markdown)是 UTF-8 编码。当 Python 用 GBK 去读 UTF-8 文件时,就会出现 UnicodeDecodeError:
┌─────────────────────────────────────────────────────────────┐
│ 编码不匹配问题 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 你的 .md 文件保存格式 Python 默认读取编码 │
│ ↓ ↓ │
│ ┌──────────┐ ┌──────────┐ │
│ │ UTF-8 │ ≠ ≠ ≠ ≠ ≠ │ GBK │ │
│ │ 中文"你好"│ │ 乱码"浣犲ソ"│ │
│ └──────────┘ └──────────┘ │
│ │
│ → Python 用 GBK 解码 UTF-8 文件 = 崩溃 │
└─────────────────────────────────────────────────────────────┘
12.2.2 解决方案:使用 dev_win.bat启动
完整的 dev_win.bat内容见第 2.9.1 节,此处仅说明编码相关的关键配置。
在 D:\pythonapp\my_blog 目录下创建 dev_win.bat 文件,关键编码设置如下:
@echo off
chcp 65001 >nul
set PYTHONIOENCODING=utf-8
set PYTHONLEGACYWINDOWSSTDIO=utf-8
title Pelican Blog Manager
cd /d "%~dp0"
:: ... 完整内容见 2.9.1 节
⚠️ 重要:dev_win.bat已更新,新增了"自动重载"和"Invoke livereload"选项,详见第 2.9.1 节。
12.2.3 dev_win.bat配置说明
| 命令 | 作用 |
|---|---|
chcp 65001 |
让 CMD 窗口显示 UTF-8 |
PYTHONIOENCODING=utf-8 |
让 Python 输出/读取 UTF-8 |
PYTHONLEGACYWINDOWSSTDIO=utf-8 |
让 Windows 标准输入输出使用 UTF-8 |
注意:
chcp 65001和环境变量设置的是不同层面的编码,两者缺一不可!
12.2.4 CentOS 上的编码问题
在 CentOS/Linux 上基本不会遇到编码问题!
| 系统 | 默认编码 | 说明 |
|---|---|---|
| Windows | GBK (cp936) | 混乱,容易出问题 |
| CentOS/Linux | UTF-8 | 统一,兼容性好 |
CentOS 上可以直接运行:
pelican content/
不需要任何额外的编码设置。
12.2.5 Docutils 中文警告说明
运行 Pelican 时可能会看到以下警告:
WARNING Docutils has no localization for 'zh'. Using 'en' instead.
含义:Docutils(文档处理库)没有中文语言包,所以用英文替代。
| 组成部分 | 含义 |
|---|---|
Docutils |
Python 文档工具库,Pelican 用它处理 reStructuredText 格式 |
no localization for 'zh' |
没有中文本地化文件 |
Using 'en' instead |
退回到英文 |
这只是一个警告,不影响功能! 可以安全忽略。
12.3 调试命令
# 查看所有运行的服务
systemctl list-units --type=service
# 查看端口占用
netstat -tlnp | grep -E "80|443|5000"
# 测试 Python 环境
source /home/app/my_blog/.venv/bin/activate
python -c "import fastapi; print(fastapi.__version__)"
# 手动运行构建
cd /home/app/my_blog
source /home/app/my_blog/.venv/bin/activate
pelican content/ -s publishconf.py -v
16. 维护命令
13.1 常用操作
# 激活虚拟环境
source /home/app/my_blog/.venv/bin/activate
# 手动触发构建
/home/app/my_blog/rebuild.sh
# 重启 Webhook 服务
systemctl restart blog-webhook
# 重载 Nginx
systemctl reload nginx
# 查看构建历史
tail -20 /var/log/pelican-rebuild.log
# 更新依赖
pip install --upgrade pelican fastapi uvicorn
13.2 备份
# 备份博客内容
tar -czf blog-backup-$(date +%Y%m%d).tar.gz /home/app/my_blog
# 备份配置
cp /home/app/my_blog/.env /root/blog-env-backup
17. 完整部署检查清单
- [x] 服务器环境已准备(Python、Git、Nginx、uv 已安装)
- [x] 防火墙已配置(80、443 端口)
- [ ] /home/app/my_blog 目录已创建
- [ ] uv 虚拟环境已创建(Python 3.11)
- [ ] Pelican 和依赖已安装到虚拟环境
- [ ] 配置文件已创建
- [ ] Nginx 已配置并运行
- [ ] Git 仓库已克隆到 /home/app/my_blog
- [ ] Webhook 服务已安装并运行
- [ ] Systemd 服务已配置
- [ ] Gitee Webhook 已设置
- [ ] SSL 证书已配置(如需要)
- [ ] 首次构建测试成功
文档信息
- 部署日期:2024年
- 服务器:CentOS 9 Stream
- 适用版本:Pelican 最新版