一个有审美、有边界感的现代化全栈博客系统。基于 https://github.com/talen8/FlecBlog.git 二次开发。
原作者博客:https://blog.talen.top
JeriBlog 是一个三端分离的博客系统,围绕内容创作这件事,做了相对完整的一套产品闭环。
把前台博客、后台管理、后端服务拆分成清晰的三个部分,让内容系统既能保持表现力,也能维持长期可维护性。
| 模块 | 技术栈 | 定位 |
|---|---|---|
server |
Go 1.25 / Gin / GORM / PostgreSQL | 后端服务、认证、接口、数据与定时任务 |
admin |
Vue 3 / Element Plus / Vite | 内容管理、仪表盘、编辑器、运营后台 |
blog |
Nuxt 4.2.2 / Vue 3 / SCSS | 博客前台、SSR、SEO、阅读体验 |
为什么选择 JeriBlog
- 有完整工程结构,而不是只做出一个页面展示
- 管理端与博客端解耦,前后台体验更纯粹
- 支持文章、评论、友链、统计等博客常见能力
- 适合个人品牌博客,也适合继续扩展成内容型产品
| 博客加载页 | 博客主页 |
|---|---|
| 博客首页 | 文章详情 |
|---|---|
| 后台仪表盘 | 后台编辑器 |
|---|---|
- 语言: Go 1.25
- 框架: Gin
- ORM: GORM
- 数据库: PostgreSQL
- 认证: JWT (JSON Web Tokens), OAuth2, Goth
- API 文档: Swagger
- 定时任务: Cron
- 其他: User-Agent 解析, 飞书 SDK, 微信公众号
- 框架: Vue 3 + Vite
- UI 组件: Element Plus
- 状态管理: VueUse
- Markdown 编辑器: CodeMirror 6
- 图表: ECharts, echarts-wordcloud
- 其他: TypeScript, Vue Router, Axios, dayjs, SCSS
- 框架: Nuxt 4 - Vue.js 全栈框架
- 文章渲染: markdown-it, Highlight.js, Mermaid
- 样式: SCSS
- SEO: @nuxtjs/seo, Sitemap, Atom Feed
- PWA: @vite-pwa/nuxt
- 其他: TypeScript, VueUse, dayjs, Lenis, medium-zoom, APlayer
server/
├── api/ # API 层
│ ├── middleware/ # 中间件 (认证、CORS、日志、限流、RBAC、恢复)
│ ├── router/ # 路由配置
│ └── v1/ # API v1 接口
│ ├── feeds/ # 订阅源 (Atom/RSS)
│ ├── ai.go # AI 功能
│ ├── article.go # 文章管理
│ ├── category.go # 分类管理
│ ├── comment.go # 评论管理
│ ├── feedback.go # 反馈投诉
│ ├── file.go # 文件管理
│ ├── friend.go # 友链管理
│ ├── menu.go # 菜单管理
│ ├── moment.go # 动态管理
│ ├── notification.go # 通知管理
│ ├── rssfeed.go # RSS 订阅管理
│ ├── setting.go # 配置管理
│ ├── stats.go # 统计数据
│ ├── subscriber.go # 订阅者管理
│ ├── system.go # 系统信息
│ ├── tag.go # 标签管理
│ ├── tools.go # 工具接口
│ └── user.go # 用户管理
├── cmd/ # 应用入口
│ └── main.go # 主程序入口
├── config/ # 配置管理
├── docs/ # Swagger API 文档
├── internal/ # 内部业务逻辑
│ ├── dto/ # 数据传输对象 (Data Transfer Object)
│ ├── model/ # 数据模型 (GORM 实体)
│ ├── repository/ # 数据访问层 (Repository Pattern)
│ └── service/ # 业务逻辑层 (Service Layer)
├── pkg/ # 可复用的公共包
│ ├── ai/ # AI 服务封装 (OpenAI/Claude 等)
│ ├── auth/ # 认证工具 (JWT/OAuth)
│ ├── database/ # 数据库连接管理
│ ├── email/ # 邮件发送服务
│ ├── errcode/ # 统一错误码定义
│ ├── feishu/ # 飞书 SDK 封装
│ ├── linkparser/ # 链接元数据解析
│ ├── logger/ # 日志工具
│ ├── mcp/ # MCP 协议支持
│ ├── notification/ # 通知服务聚合 (邮件/飞书)
│ ├── random/ # 随机数生成工具
│ ├── response/ # 统一响应格式
│ ├── scheduler/ # 定时任务调度器
│ ├── upload/ # 文件上传管理 (本地/MinIO/OSS/COS/七牛云)
│ ├── utils/ # 通用工具函数
│ ├── videoparser/ # 视频平台解析 (B站/抖音等)
│ └── wechatmp/ # 微信公众号 SDK
├── templates/ # 邮件等模板文件
├── go.mod # Go 模块依赖
└── Dockerfile # Docker 镜像构建文件admin/
├── src/
│ ├── api/ # API 接口封装
│ ├── assets/ # 静态资源 (图片、字体、样式)
│ ├── components/ # 公共组件
│ │ ├── common/ # 通用组件 (表格、表单、对话框)
│ │ └── editor/ # Markdown 编辑器组件
│ ├── layouts/ # 页面布局组件
│ ├── router/ # Vue Router 路由配置
│ ├── types/ # TypeScript 类型定义
│ ├── utils/ # 工具函数 (日期、验证、请求)
│ ├── views/ # 页面组件
│ │ ├── article/ # 文章管理
│ │ ├── comment/ # 评论管理
│ │ ├── dashboard/ # 仪表盘
│ │ ├── friend/ # 友链管理
│ │ ├── moment/ # 动态管理
│ │ ├── rssfeed/ # RSS 订阅管理
│ │ ├── system/ # 系统设置
│ │ └── user/ # 用户管理
│ ├── App.vue # 根组件
│ └── main.ts # 应用入口
├── public/ # 公共静态文件
├── index.html # HTML 模板
├── vite.config.ts # Vite 构建配置
├── nginx.conf # Nginx 配置
├── package.json # npm 依赖
└── Dockerfile # Docker 镜像构建文件blog/
├── app/ # 应用主目录
│ ├── assets/ # 静态资源 (样式、图片)
│ ├── components/ # Vue 组件
│ │ ├── article/ # 文章相关组件
│ │ ├── comment/ # 评论组件
│ │ ├── layout/ # 布局组件 (头部、底部、侧边栏)
│ │ └── widget/ # 小部件 (标签云、归档、友链)
│ ├── composables/ # 组合式函数 (Composables)
│ ├── layouts/ # 页面布局
│ ├── pages/ # 页面路由 (基于文件系统)
│ │ ├── article/ # 文章页面
│ │ ├── category/ # 分类页面
│ │ ├── tag/ # 标签页面
│ │ ├── friend/ # 友链页面
│ │ └── about/ # 关于页面
│ ├── plugins/ # Nuxt 插件
│ ├── utils/ # 工具函数
│ └── app.vue # 根组件
├── public/ # 公共静态文件
├── server/ # 服务端代码 (SSR)
│ ├── plugins/ # 服务端插件
│ └── routes/ # API 路由
├── types/ # TypeScript 类型定义
├── nuxt.config.ts # Nuxt 配置
├── package.json # npm 依赖
└── Dockerfile # Docker 镜像构建文件Blog 端采用 Nuxt 4 的 SSR 模式,提供:
- 更好的 SEO 优化,搜索引擎可直接抓取完整内容
- 更快的首屏加载速度
- 更好的用户体验
集成完整的 SEO 功能:
- 动态 sitemap.xml
- robots.txt
- Atom Feed 订阅
- Open Graph 标签
- 结构化数据
服务启动后,访问以下地址查看 API 文档:
http://localhost:8080/swagger/index.htmlJeriBlog 想做的不是“更复杂”,而是“更完整”。
简约,不是把内容做空。 高级,也不是故作夸张。
它更像一个安静但可靠的内容容器, 适合长期写作,也适合慢慢生长出自己的品牌风格。
在容器化部署环境下(如 Docker),后端服务需要正确配置信任代理范围才能获取真实客户端 IP 地址。
问题场景:
- 使用 Docker 网络时,客户端 IP 可能显示为容器网关地址(如 172.170.0.1)
- Nginx 反向代理传递的
X-Forwarded-For头部无法被正确解析
解决方案:
在 server/api/router/router.go 中配置 SetTrustedProxies,确保包含您的 Docker 网络段:
// 示例:Docker 使用 172.170.0.0/24 网段
r.SetTrustedProxies([]string{
"127.0.0.1",
"172.0.0.0/8", // 包含所有 172.x.x.x 网段(推荐)
"10.0.0.0/8",
"192.168.0.0/16",
})常见 Docker 网络段:
- 默认 bridge 网络:
172.17.0.0/16 - 自定义网络:
172.16.0.0/12或172.0.0.0/8(更宽泛)
验证方法:
- 查看 Docker 网络配置:
docker network inspect <network_name> - 检查容器日志中的 IP 地址是否为真实客户端 IP
- 确保信任代理范围覆盖 Docker 网关地址
博客支持在 Markdown 文章中嵌入 B 站、YouTube 和本地视频。
使用方法:
B 站视频:
:::video bilibili BV1xx411c7mD :::YouTube 视频:
:::video youtube dQw4w9WgXcQ :::本地/在线视频:
:::video https://example.com/video.mp4 :::注意事项:
- B 站视频需要提供 BV 号(如
BV1xx411c7mD) - YouTube 视频需要提供视频 ID(如
dQw4w9WgXcQ) - 本地视频需要先上传到服务器或使用在线视频链接
- 视频会自动适配响应式布局,支持移动端播放
后端使用 Swagger 自动生成 API 文档。当修改 API 接口注释后,需要重新生成文档。
安装 swag 工具:
首次使用前需要安装 swag 命令行工具:
# 方式1:使用 go install(推荐,Go 1.16+)
go install github.com/swaggo/swag/cmd/swag@latest
# 方式2:使用 go get(Go 1.16 以下版本)
go get -u github.com/swaggo/swag/cmd/swag
# 验证安装
swag --version生成命令:
# 进入 server 目录
cd server
# 生成 Swagger 文档
swag init -g cmd/main.go -o docs --parseDependency --parseInternal参数说明:
-g cmd/main.go:指定主入口文件-o docs:指定文档输出目录--parseDependency:解析依赖包中的类型定义--parseInternal:解析 internal 包中的类型定义
注意事项:
- 修改 API 注释后必须重新生成文档
- 确保注释中引用的类型已正确导入
- 生成的文档文件位于
server/docs/目录 - 如果
swag命令不可用,请确认$GOPATH/bin或$GOBIN已添加到系统 PATH 环境变量中
| 依赖 | 版本要求 |
|---|---|
| Go | >= 1.25 (server) |
| Node.js | >= 20 (admin, blog) |
| PostgreSQL | >= 12 (server) |
- Node.js >= 20 (admin, blog)
- Go >= 1.25 (server)
- PostgreSQL >= 12 (server)
如果本地没有安装部署 PostgreSQL,可参考以下docker快速部署相关数据库(可选)。
创建 pgsql 指令:
docker run -d --name pg-prod \
-p 5432:5432 \
-v /data/PgSqlData:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD="123456ok!" \
-e LANG=C.UTF-8 \
-e TZ=Asia/Shanghai \
postgres:17-alpine查看是否创建成功:
[root@docker-server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22205f8e78c6 postgres:17-alpine "docker-entrypoint.s…" 34 minutes ago Up 34 minutes 0.0.0.0:5432->5432/tcp, [::]:5432->5432/tcp pg-prodgit clone https://github.com/zyx3721/JeriBlog.git /data/myBlog
cd /data/myBlog创建 PostgreSQL 数据库:
psql -Upostgres -c " \
CREATE DATABASE blogdb \
WITH OWNER = postgres \
ENCODING = 'UTF8' \
LC_COLLATE = 'en_US.UTF-8' \
LC_CTYPE = 'en_US.UTF-8' \
TEMPLATE = template0;"进入容器内的 psql 交互界面:
docker exec -it pg-prod psql -U postgres在 psql 中创建 blogdb 库(执行后输入 \q 退出):
CREATE DATABASE blogdb
WITH OWNER = postgres
ENCODING = 'UTF8'
LC_COLLATE = 'en_US.UTF-8'
LC_CTYPE = 'en_US.UTF-8'
TEMPLATE = template0;应用会在首次启动时自动执行 pkg/database/sql/init_database.sql 初始化数据库,包括创建表结构和初始数据。
⚠️ PostgreSQL 15+ 权限配置:如果使用 PostgreSQL 15 或更高版本,且数据库用户不是postgres(超级用户),需要额外配置 schema 权限:sudo -i -u postgres psql -U postgres -d <数据库名> -c "GRANT CREATE ON SCHEMA public TO <用户名>;"PostgreSQL 15+ 默认限制了普通用户在 public schema 上的创建权限,上述命令会授予必要的权限。
如果没有配置go的镜像代理,可以参考 Go 国内加速:Go 国内加速镜像 | Go 技术论坛。
- 进入后端目录下载相关依赖:
cd server
go mod download- 配置数据库连接等信息:
# 步骤1:复制模板文件
cp env.example .env
# 步骤2:编辑 .env,配置数据库连接等信息
vim .env
# 服务器配置
SERVER_HOST=localhost
SERVER_PORT=8080
SERVER_ALLOW_ORIGINS=*
# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_NAME=postgres
DB_USER=postgres
DB_PASSWORD=your_database_password
# JWT 配置
JWT_SECRET=your_jwt_secret_key- 修改
router.go文件:
# 添加允许本机 127.0.0.1 地址访问
sed -i 's@r\.SetTrustedProxies(\[\]string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"})@r.SetTrustedProxies([]string{"127.0.0.1", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"})@g' api/router/router.go- 运行后端服务:
# 方式1:前台运行(终端关闭则服务停止)
go run cmd/main.go
# 方式2:后台运行(日志输出到 app.log)
nohup go run cmd/main.go > app.log 2>&1 &后端服务默认运行在 http://localhost:8080 ,如需指定外部监听地址和端口,请修改环境变量文件内的 SERVER_HOST 和 SERVER_PORT 参数。首次启动会自动创建数据库和默认管理员账户 admin@example.com / 123456 。
- 进入前端目录下载相关依赖:
cd admin
npm install- 配置 API 地址(可选):
# 配置说明:
# - 后端端口 = 8080:无需创建 .env 文件(默认值为 http://localhost:8080/api/v1)
# - 后端端口 ≠ 8080:需要创建 .env 文件(指定正确端口,例如后端端口改为 8090)
# 创建 .env 文件,例如:
echo "VITE_API_URL=http://localhost:8090/api/v1" > .env- 修改
config.js文件(可选):
# 配置说明:
# - 后端端口 = 8080:无需修改(默认值为 http://localhost:8080/api/v1)
# - 后端端口 ≠ 8080:需要修改(指定正确端口,例如后端端口改为 8090)
# 修改 config.js 文件,例如:
cat > public/config.js <<EOF
window.__APP_CONFIG__ = {
apiUrl: "http://localhost:8090/api/v1"
};
EOF- 启动前端服务:
# 方式1:前台运行(终端关闭则服务停止)
npm run dev
# 方式2:后台运行(日志输出到 admin-frontend.log)
nohup npm run dev > admin-frontend.log 2>&1 &Admin 前端服务默认运行在 http://localhost:5174/admin/ 。
- 进入前端目录下载相关依赖:
cd blog
npm install- 配置 API 地址(可选):
# 配置说明:
# - 后端端口 = 8080:无需创建 .env 文件(默认值为 http://localhost:8080/api/v1)
# - 后端端口 ≠ 8080:需要创建 .env 文件(指定正确端口,例如后端端口改为 8090)
# 创建 .env 文件,例如:
echo "NUXT_PUBLIC_API_URL=http://localhost:8090/api/v1" > .env- 启动前端服务:
# 方式1:前台运行(终端关闭则服务停止)
npm run dev
# 方式2:后台运行(日志输出到 blog-frontend.log)
nohup npm run dev > blog-frontend.log 2>&1 &Blog 前端服务默认运行在 http://localhost:3000 。
- 博客端:
http://localhost:3000 - 管理端:
http://localhost:5174/admin/- 默认管理员账户:
admin@example.com - 默认管理员密码:
123456
- 默认管理员账户:
- API 文档:
http://localhost:8080/swagger/index.html
所有相关文件统一放在 deploy/ 目录下,单镜像包含前端(Nginx)、后端(blog-backend),通过 supervisord 管理多进程。
deploy/
├── docker-compose.yml # 服务编排配置
├── .env # 环境变量(需自行创建,见 4.2)
├── .env.example # 环境变量模板
├── BlogData/ # 应用持久化数据(首次启动自动创建)
│ ├── uploads/ # 上传文件
│ └── logs/ # 运行日志
└── PgSqlData/ # PostgreSQL 数据(首次启动自动创建)进入 deploy 目录,创建 .env 环境变量文件:
cd deploy
vim .env.env 文件内容参考:
# 数据库配置
DB_HOST=postgres
DB_PORT=5432
DB_NAME=blogdb
DB_USER=postgres
DB_PASSWORD=your_database_password
# 默认留空,外部有 HTTPS 反代时设置为 https
SERVER_SCHEME=https
# JWT 配置
JWT_SECRET=your_jwt_secret_key
# 博客前台 Nuxt SSR 服务端渲染时使用(填写你的域名或IP)
NUXT_PUBLIC_API_URL=https://your-domain.com/api/v1
# 管理后台 config.js 注入的 API 地址(填写你的域名或IP)
API_URL=https://your-domain.com/api/v1如果不想使用阿里云镜像仓库的镜像,可直接在本地手动构建(默认使用阿里云镜像仓库地址):
# 在 deploy/ 目录下构建(构建上下文为项目根目录)
cd deploy
docker build \
-f Dockerfile \
-t jeriblog:latest \
--build-arg ALPINE_MIRROR=mirrors.aliyun.com \
..
# 如果要指定版本,可执行以下命令(默认系统信息版本为 dev)
docker build \
-f Dockerfile \
-t jeriblog:latest \
--build-arg ALPINE_MIRROR=mirrors.aliyun.com \
--build-arg APP_VERSION=v3.2.2 \
..然后修改 deploy/docker-compose.yml 中 jeriblog 服务的 image 字段为 jeriblog:latest 。
docker-compose.yml 支持两种模式,按需选择:
模式一:新建 PostgreSQL 容器(默认)
首次启动会自动创建 blogdb 数据库:
cd deploy
docker compose up -d模式二:使用已有容器
.env 环境变量文件中确保数据库配置填入已有容器地址,并编辑 deploy/docker-compose.yml:
- 注释掉
postgres服务块 - 注释掉
blog.depends_on块
cd deploy
docker compose up -d# 查看服务状态
docker compose ps
# 查看实时日志
docker compose logs -f blog
# 重启 blog 服务
docker compose restart blog
# 停止所有服务
docker compose down
# 停止并删除数据卷(谨慎!数据会丢失)
docker compose down -v服务启动后,访问以下地址:
- 博客端:
https://your-domain.com - 管理端:
https://your-domain.com/admin- 默认管理员账户:
admin@example.com - 默认管理员密码:
123456
- 默认管理员账户:
- API 文档:
https://your-domain.com/swagger/index.html - 健康检查:
https://your-domain.com/health
如需通过宿主机 Nginx 配置 HTTPS,将 deploy/docker-compose.yml 中的端口映射改为非 80 端口(如 8080:80),再配置外部 Nginx 代理:
server {
listen 80;
server_name your-domain.com;
# 限制上传文件大小(可选)
client_max_body_size 50m;
# Gzip 压缩配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;
gzip_min_length 1000;
# 日志配置
access_log /usr/local/nginx/logs/jeriblog-access.log;
error_log /usr/local/nginx/logs/jeriblog-error.log warn;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时配置
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
}HTTPS 示例(含 80→443 跳转,请替换证书路径):
# HTTP 80端口配置,自动重定向到HTTPS
server {
listen 80;
server_name your-domain.com; # 修改为你的域名/主机名,例如:blog.cn
return 301 https://$host$request_uri;
}
# blog 站点 HTTPS 配置
server {
# listen 443 ssl http2; # Nginx 1.25 以下版本写法
listen 443 ssl;
http2 on;
server_name your-domain.com; # 修改为你的域名/主机名,例如:blog.cn
# 证书路径(替换为实际证书文件)
ssl_certificate /usr/local/nginx/ssl/your-domain.com.pem; # 例如:/usr/local/nginx/ssl/blog.cn.pem
ssl_certificate_key /usr/local/nginx/ssl/your-domain.com.key; # 例如:/usr/local/nginx/ssl/blog.cn.key
# SSL安全优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
# 限制上传文件大小(可选)
client_max_body_size 50m;
# Gzip 压缩配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;
gzip_min_length 1000;
# 日志配置
access_log /usr/local/nginx/logs/jeriblog-access.log;
error_log /usr/local/nginx/logs/jeriblog-error.log warn;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时配置
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
}git clone https://github.com/zyx3721/JeriBlog.git /data/myBlog
cd /data/myBlog- 进入后端目录下载相关依赖:
cd server
go mod download- 配置数据库连接等信息:
# 步骤1:复制模板文件
cp env.example .env
# 步骤2:编辑 .env,配置数据库连接等信息
vim .env
# 服务器配置
SERVER_HOST=localhost
SERVER_PORT=8080
SERVER_ALLOW_ORIGINS=*
# 数据库配置
DB_HOST=localhost
DB_PORT=5432
DB_NAME=postgres
DB_USER=postgres
DB_PASSWORD=your_database_password
# JWT 配置
JWT_SECRET=your_jwt_secret_key- 修改
router.go文件:
# 添加允许本机 127.0.0.1 地址访问
sed -i 's@r\.SetTrustedProxies(\[\]string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"})@r.SetTrustedProxies([]string{"127.0.0.1", "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"})@g' api/router/router.go- 构建后端可执行文件:
go build -o blog-backend cmd/main.go- 运行后端服务:
# 方式1:前台运行(终端关闭则服务停止)
./blog-backend
# 方式2:后台运行(日志输出到 app.log)
nohup ./blog-backend > app.log 2>&1 &
# 方法3:加入 systemd 管理启动运行
# 服务配置参考如下,请自行修改相应目录路径
cat > /etc/systemd/system/blog-backend.service <<EOF
[Unit]
Description=Blog Backend Golang Service
After=network.target network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/data/myBlog/server
ExecStart=/data/myBlog/server/blog-backend
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
StandardOutput=journal
StandardError=journal
SyslogIdentifier=blog-backend
[Install]
WantedBy=multi-user.target
EOF
# 重载服务配置并启动
systemctl daemon-reload
systemctl start blog-backend
# 设置开机自启
systemctl enable --now blog-backend- 进入前端目录下载相关依赖:
cd admin
npm install- 配置 API 地址:
由于后续通过 Nginx 代理访问,因此这里配置为:
# 配置二选一
## HTTP 方式
echo "VITE_API_URL=http://your-domain.com/api/v1" > .env
## HTTPS 方式(SSL 证书)
echo "VITE_API_URL=https://your-domain.com/api/v1" > .env- 构建前端项目:
npm run build构建产物在 dist 目录,可部署到任何静态服务器(Nginx、Vercel、Netlify 等)。
- 进入前端目录下载相关依赖:
cd blog
npm install- 配置 API 地址:
由于后续通过 Nginx 代理访问,因此这里配置为:
# HTTP 方式
echo "NUXT_PUBLIC_API_URL=http://your-domain.com/api/v1" > .env
# HTTPS 方式(SSL 证书)
echo "NUXT_PUBLIC_API_URL=https://your-domain.com/api/v1" > .env- 构建前端项目:
npm run build构建产物在 .output 目录,这里无法通过静态服务器来部署,需提前进行启动。
- 启动前端服务:
方法一:命令行启动
# 方式1:前台运行(终端关闭则服务停止)
node .output/server/index.mjs
# 方式2:后台运行(日志输出到 blog-frontend.log)
nohup node .output/server/index.mjs > blog-frontend.log 2>&1 &方法二:加入 systemd 管理启动
# 服务配置参考如下,请自行修改相应目录路径
cat > /etc/systemd/system/blog-frontend.service <<EOF
[Unit]
Description=Blog Frontend Nuxt Vue Service
After=network.target network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/data/myBlog/blog
EnvironmentFile=/data/myBlog/blog/.env
ExecStart=$(which node) /data/myBlog/blog/.output/server/index.mjs
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
StandardOutput=journal
StandardError=journal
SyslogIdentifier=blog-frontend
[Install]
WantedBy=multi-user.target
EOF
# 重载服务配置并启动
systemctl daemon-reload
systemctl start blog-frontend
# 设置开机自启
systemctl enable --now blog-frontend注意:必须添加
EnvironmentFile环境配置,指向环境变量文件,否则无法读取到。
方法三:使用 PM2 工具启动
PM2 是一个流行的 Node.js 进程管理器,通常用于管理和监控 Node.js 应用。如果要使用该工具进行启动,需要先安装 PM2 工具。
# 全局安装 pm2
npm install -g pm2
# 启动服务进程(二选一)
## 先进入工作目录,再启动
cd /data/myBlog/blog
pm2 start npm --name "blog-frontend" -- run preview
## 带目录参数直接启动
pm2 start npm --name "blog-frontend" --cwd /data/myBlog/blog -- run preview
# 查看日志确认启动成功
pm2 logs blog-frontend --lines 20 --nostream
# 保存进程列表并设置开机自启(可选)
## 保存当前进程列表
pm2 save
## 生成开机自启配置(执行后按提示复制并运行输出的 systemctl 命令)
pm2 startup
## # 启动 PM2 服务,并设置开机自启
systemctl enable --now pm2-rootPM2 常用管理命令:
pm2 list # 查看所有进程,等价于:pm2 status
pm2 logs blog-frontend # 查看日志(实时)
pm2 logs blog-frontend --lines 50 --nostream # 查看最近50行日志
pm2 restart blog-frontend # 重启进程
pm2 stop blog-frontend # 停止进程
pm2 delete blog-frontend # 删除进程在服务器上准备前端目录(例如 /data/myBlog/admin/dist),将本地 dist 目录中的所有文件和子目录整体上传到该目录,保持结构不变,例如:
/data/myBlog/admin/dist/
├── apple-touch-icon.png
├── assets/
├── config.js
├── favicon.ico
├── index.html
├── manifest.webmanifest
├── pwa-192x192.png
├── registerSW.js
├── sw.js
├── workbox-8c29f6e4.js由于 Admin 前端使用二级路径,因此Nginx 中使用 alias 来指向 包含 index.html 的目录本身(如 /data/myBlog/admin/dist ,可按实际路径调整)。
在配置反向代理之前,先修改 /data/myBlog/admin/dist 目录下的 config.js 文件配置,该运行时配置用于每次修改 API 地址后,无需重新构建即可访问:
# 配置二选一
## HTTP 方式
cat > public/config.js <<EOF
window.__APP_CONFIG__ = {
apiUrl: "http://your-domain.com/api/v1"
};
EOF
## HTTPS 方式(SSL 证书)
cat > public/config.js <<EOF
window.__APP_CONFIG__ = {
apiUrl: "https://your-domain.com/api/v1"
};
EOF配置 Nginx (按需替换域名/路径/证书),
HTTP 示例:
server {
listen 80;
server_name your-domain.com; # 修改为你的域名/主机名,例如:blog.cn
# 限制上传文件大小(可选)
client_max_body_size 50m;
# Gzip 压缩配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;
gzip_min_length 1000;
# 日志配置
access_log /usr/local/nginx/logs/jeriblog-access.log;
error_log /usr/local/nginx/logs/jeriblog-error.log warn;
# blog 前端(Nuxt SSR)
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
# WebSocket(聊天室连接:/api/chat/ws),需保持连接与协议升级
location /api/chat/ws {
proxy_pass http://127.0.0.1:8080; # 与后端 API 相同地址
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 健康检查
location = /health {
proxy_pass http://127.0.0.1:8080/api/v1/health;
}
# RSS 订阅
location = /atom.xml {
proxy_pass http://127.0.0.1:8080/atom.xml;
}
location = /rss.xml {
proxy_pass http://127.0.0.1:8080/rss.xml;
}
# 动态音乐解析
location /tools/parse-music {
proxy_pass http://127.0.0.1:8080/api/v1/tools/parse-music;
}
# MCP 工具
location = /mcp {
proxy_pass http://127.0.0.1:8080/mcp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
# 后端 API 反向代理(其余 /api/* 请求)
location /api/ {
proxy_pass http://127.0.0.1:8080; # 与后端 API 相同地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时配置
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
# 后端 API 文档
location /swagger/ {
proxy_pass http://127.0.0.1:8080; # 与后端 API 相同地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 本地存储上传文件访问(通过后端读取 /uploads 下资源)
# 使用 ^~ 确保优先级高于下面的静态资源正则 location
location ^~ /uploads/ {
proxy_pass http://127.0.0.1:8080; # 与后端 API 相同地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location = /config.js {
alias /data/myBlog/admin/dist/config.js; # 按实际部署路径修改
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
expires off;
}
# 管理后台静态资源目录(dist 构建产物)
location /admin {
alias /data/myBlog/admin/dist; # 按实际部署路径修改
index index.html;
try_files $uri $uri/ /admin/index.html;
expires 7d;
add_header Cache-Control "public, max-age=604800";
}
}HTTPS 示例(含 80→443 跳转,请替换证书路径):
# HTTP 80端口配置,自动重定向到HTTPS
server {
listen 80;
server_name your-domain.com; # 修改为你的域名/主机名,例如:blog.cn
return 301 https://$host$request_uri;
}
# blog 站点 HTTPS 配置
server {
# listen 443 ssl http2; # Nginx 1.25 以下版本写法
listen 443 ssl;
http2 on;
server_name your-domain.com; # 修改为你的域名/主机名,例如:blog.cn
# 证书路径(替换为实际证书文件)
ssl_certificate /usr/local/nginx/ssl/your-domain.com.pem; # 例如:/usr/local/nginx/ssl/blog.cn.pem
ssl_certificate_key /usr/local/nginx/ssl/your-domain.com.key; # 例如:/usr/local/nginx/ssl/blog.cn.key
# SSL安全优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_session_timeout 10m;
ssl_session_cache shared:SSL:10m;
# 限制上传文件大小(可选)
client_max_body_size 50m;
# Gzip 压缩配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/rss+xml font/truetype font/opentype
application/vnd.ms-fontobject image/svg+xml;
gzip_min_length 1000;
# 日志配置
access_log /usr/local/nginx/logs/jeriblog-access.log;
error_log /usr/local/nginx/logs/jeriblog-error.log warn;
# blog 前端(Nuxt SSR)
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_read_timeout 60s;
}
# WebSocket(聊天室连接:/api/chat/ws),需保持连接与协议升级
location /api/chat/ws {
proxy_pass http://127.0.0.1:8080; # 与后端 API 相同地址
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 健康检查
location = /health {
proxy_pass http://127.0.0.1:8080/api/v1/health;
}
# RSS 订阅
location = /atom.xml {
proxy_pass http://127.0.0.1:8080/atom.xml;
}
location = /rss.xml {
proxy_pass http://127.0.0.1:8080/rss.xml;
}
# 动态音乐解析
location /tools/parse-music {
proxy_pass http://127.0.0.1:8080/api/v1/tools/parse-music;
}
# MCP 工具
location = /mcp {
proxy_pass http://127.0.0.1:8080/mcp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
# 后端 API 反向代理(其余 /api/* 请求)
location /api/ {
proxy_pass http://127.0.0.1:8080; # 与后端 API 相同地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 超时配置
proxy_connect_timeout 600s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
# 后端 API 文档
location /swagger/ {
proxy_pass http://127.0.0.1:8080; # 与后端 API 相同地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 本地存储上传文件访问(通过后端读取 /uploads 下资源)
# 使用 ^~ 确保优先级高于下面的静态资源正则 location
location ^~ /uploads/ {
proxy_pass http://127.0.0.1:8080; # 与后端 API 相同地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location = /config.js {
alias /data/myBlog/admin/dist/config.js; # 按实际部署路径修改
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
expires off;
}
# 管理后台静态资源目录(dist 构建产物)
location /admin {
alias /data/myBlog/admin/dist; # 按实际部署路径修改
index index.html;
try_files $uri $uri/ /admin/index.html;
expires 7d;
add_header Cache-Control "public, max-age=604800";
}
}重载 Nginx:
# 检查语法
nginx -t
# 重载配置
## 方法1
nginx -s reload
## 方法2
systemctl reload nginx- 博客端:
https://your-domain.com - 管理端:
https://your-domain.com/admin- 默认管理员账户:
admin@example.com - 默认管理员密码:
123456
- 默认管理员账户:
- API 文档:
https://your-domain.com/swagger/index.html - 健康检查:
https://your-domain.com/health
后端集成 Swagger,服务启动后可通过以下地址在线查阅完整接口文档:
| 环境 | 地址 |
|---|---|
| 本地开发 | http://localhost:8080/swagger/index.html |
| 生产环境 | http://your-domain.com/swagger/index.html |
以下为接口速查表,按模块分组列出所有路由。
GET /- 根路径欢迎页面(返回服务运行状态)GET /swagger/*any- Swagger API 文档
GET /atom.xml- Atom 订阅源GET /rss.xml- RSS 2.0 订阅源
基础路径:/api/v1
GET /api/v1/health- 服务健康检查(返回服务及数据库连接状态)GET /api/v1/settings/:group- 获取公开配置分组POST /api/v1/collect- 前端埋点数据收集GET /api/v1/stats/site- 网站统计信息GET /api/v1/stats/archives- 文章归档数据
POST /api/v1/auth/register- 用户注册POST /api/v1/auth/login- 用户登录POST /api/v1/auth/refresh- 刷新 TokenPOST /api/v1/auth/logout- 退出登录(需登录)POST /api/v1/auth/forgot-password- 忘记密码POST /api/v1/auth/reset-password- 重置密码GET /api/v1/auth/:provider- OAuth 第三方登录GET /api/v1/auth/:provider/callback- OAuth 回调
GET /api/v1/user/profile- 获取当前用户信息PATCH /api/v1/user/profile- 更新当前用户信息PUT /api/v1/user/password- 修改密码POST /api/v1/user/password- 设置密码(OAuth 用户首次设置)DELETE /api/v1/user/deactivate- 注销账号DELETE /api/v1/user/oauth/:provider- 解绑第三方账号
GET /api/v1/articles- 获取文章列表GET /api/v1/articles/search- 搜索文章GET /api/v1/articles/random- 随机获取一篇已发布文章的 slugGET /api/v1/articles/:slug- 获取文章详情
GET /api/v1/tags- 获取标签列表GET /api/v1/tags/:slug- 获取标签详情
GET /api/v1/categories- 获取分类列表GET /api/v1/categories/:slug- 获取分类详情
GET /api/v1/friends- 获取友链列表POST /api/v1/friends/apply- 申请友链(需登录)
GET /api/v1/moments- 获取动态列表
GET /api/v1/menus- 获取菜单树
GET /api/v1/comments- 获取评论列表POST /api/v1/comments- 发表评论(支持匿名和登录用户)PUT /api/v1/comments/:id- 更新评论(需登录)DELETE /api/v1/comments/:id- 删除评论(需登录)
GET /api/v1/notifications- 获取通知列表PUT /api/v1/notifications/:id/read- 标记已读PUT /api/v1/notifications/read-all- 全部标记已读
POST /api/v1/upload- 上传文件(支持匿名和登录用户)
POST /api/v1/feedback- 提交反馈GET /api/v1/feedback/ticket/:ticket_no- 查询工单状态
POST /api/v1/subscribe- 订阅邮件通知GET /api/v1/subscribe/unsubscribe- 退订邮件通知
基础路径:/api/v1/admin,所有接口需携带管理员 JWT Token。
GET /api/v1/admin/users- 获取用户列表GET /api/v1/admin/users/:id- 获取用户详情POST /api/v1/admin/users- 创建用户PUT /api/v1/admin/users/:id- 更新用户信息DELETE /api/v1/admin/users/:id- 删除用户
GET /api/v1/admin/articles- 获取文章列表GET /api/v1/admin/articles/:id- 获取文章详情POST /api/v1/admin/articles- 创建文章PUT /api/v1/admin/articles/:id- 更新文章DELETE /api/v1/admin/articles/:id- 删除文章POST /api/v1/admin/articles/import- 导入文章(支持 Hexo 等格式)POST /api/v1/admin/articles/:id/wechat/export- 导出到微信公众号GET /api/v1/admin/articles/:id/download/zip- 下载为 Markdown 压缩包
GET /api/v1/admin/tags- 获取标签列表GET /api/v1/admin/tags/:id- 获取标签详情POST /api/v1/admin/tags- 创建标签PUT /api/v1/admin/tags/:id- 更新标签DELETE /api/v1/admin/tags/:id- 删除标签
GET /api/v1/admin/categories- 获取分类列表GET /api/v1/admin/categories/:id- 获取分类详情POST /api/v1/admin/categories- 创建分类PUT /api/v1/admin/categories/:id- 更新分类DELETE /api/v1/admin/categories/:id- 删除分类
GET /api/v1/admin/friends/types- 获取友链类型列表GET /api/v1/admin/friends/types/:id- 获取类型详情POST /api/v1/admin/friends/types- 创建类型PUT /api/v1/admin/friends/types/:id- 更新类型DELETE /api/v1/admin/friends/types/:id- 删除类型GET /api/v1/admin/friends- 获取友链列表GET /api/v1/admin/friends/:id- 获取友链详情POST /api/v1/admin/friends- 创建友链PUT /api/v1/admin/friends/:id- 更新友链DELETE /api/v1/admin/friends/:id- 删除友链
GET /api/v1/admin/moments- 获取动态列表GET /api/v1/admin/moments/:id- 获取动态详情POST /api/v1/admin/moments- 创建动态PUT /api/v1/admin/moments/:id- 更新动态DELETE /api/v1/admin/moments/:id- 删除动态
GET /api/v1/admin/comments- 获取评论列表GET /api/v1/admin/comments/:id- 获取评论详情POST /api/v1/admin/comments- 创建评论(管理员回复)PUT /api/v1/admin/comments/:id/toggle-status- 切换评论状态DELETE /api/v1/admin/comments/:id- 删除评论POST /api/v1/admin/comments/import- 导入评论(支持 Artalk 等格式)
GET /api/v1/admin/files- 获取文件列表GET /api/v1/admin/files/:id- 获取文件详情GET /api/v1/admin/files/:id/references- 查询文件引用详情POST /api/v1/admin/files- 上传文件DELETE /api/v1/admin/files/:id- 删除文件
GET /api/v1/admin/stats/dashboard- 获取仪表盘统计数据GET /api/v1/admin/stats/trend- 获取访问趋势(支持按天/周/月聚合)GET /api/v1/admin/stats/category- 获取分类统计GET /api/v1/admin/stats/tag- 获取标签统计GET /api/v1/admin/stats/contribution- 获取文章贡献数据GET /api/v1/admin/stats/visits- 获取访问日志列表DELETE /api/v1/admin/stats/visits/:id- 删除单条访问日志DELETE /api/v1/admin/stats/visits/batch- 批量删除访问日志
GET /api/v1/admin/menus- 获取菜单树GET /api/v1/admin/menus/:id- 获取菜单详情POST /api/v1/admin/menus- 创建菜单PUT /api/v1/admin/menus/:id- 更新菜单DELETE /api/v1/admin/menus/:id- 删除菜单
GET /api/v1/admin/feedback- 获取反馈列表GET /api/v1/admin/feedback/:id- 获取反馈详情PUT /api/v1/admin/feedback/:id- 更新反馈POST /api/v1/admin/feedback/:id/reply- 回复反馈(自动发送邮件通知)DELETE /api/v1/admin/feedback/:id- 删除反馈
GET /api/v1/admin/notifications- 获取通知列表PUT /api/v1/admin/notifications/:id/read- 标记已读PUT /api/v1/admin/notifications/read-all- 全部标记已读DELETE /api/v1/admin/notifications/clear-all- 清空所有通知DELETE /api/v1/admin/notifications/clear-read- 清空已读通知
GET /api/v1/admin/settings/:group- 获取指定分组配置PATCH /api/v1/admin/settings/:group- 更新指定分组配置POST /api/v1/admin/settings/ai/mcp-secret/reset- 重置 MCP 密钥(需超级管理员权限)
GET /api/v1/admin/system/static- 获取系统静态信息(服务器配置、运行环境)GET /api/v1/admin/system/dynamic- 获取系统动态信息(CPU、内存、磁盘使用率)
POST /api/v1/admin/tools/parse-video- 解析视频信息(支持 B站、抖音等平台)POST /api/v1/admin/tools/fetch-linkmeta- 获取链接元数据(标题、描述、图标)POST /api/v1/admin/tools/download-image- 下载图片到服务器
POST /api/v1/admin/ai/test- 测试 AI 配置连通性POST /api/v1/admin/ai/summary- 生成文章摘要POST /api/v1/admin/ai/ai-summary- AI 智能摘要POST /api/v1/admin/ai/title- AI 生成文章标题
GET /api/v1/admin/rssfeed- 获取 RSS 文章列表PUT /api/v1/admin/rssfeed/:id/read- 标记文章已读(需超级管理员权限)PUT /api/v1/admin/rssfeed/read-all- 全部标记已读(需超级管理员权限)POST /api/v1/admin/rssfeed/refresh- 立即刷新 RSS 订阅源(需超级管理员权限)
GET /api/v1/admin/subscribers- 获取订阅者列表DELETE /api/v1/admin/subscribers/:id- 删除订阅者
-
v3.2.2 (2026-06-08) - 功能与修复版本:第三方服务配置化与部署优化
- 新增 Meting-API、头像服务、IP 查询、封面制作 API 等第三方服务地址配置
- 新增 OAuth Worker 代理后台配置,支持运行时热加载
- 修复前台全局横向溢出样式,优化 Dockerfile Alpine 镜像源配置
- 详见 v3.2.2 更新日志
-
v3.2.1 (2026-06-01) - 修复版本:前台加载动画与后台构建类型修复
- 优化前台加载动画触发逻辑,仅首次访问和浏览器刷新时播放
- 将前台主要站内跳转改为 Nuxt 内部路由,避免 SPA 跳转触发整页刷新
- 修复后台表格行数据类型导致的管理端构建失败问题
- 详见 v3.2.1 更新日志
-
v3.2.0 (2026-05-29) - 功能与修复版本:公众号订阅、开发配置与移动端体验优化
- 新增公众号订阅配置并完善 RSS 订阅页展示与复制兼容
- 支持
SERVER_HOST配置后端监听地址,适配局域网和容器访问 - 修复文件选择器
200条/页和全部分页入参问题 - 优化管理端博客配置移动端表单布局和 Docker 镜像后端版本注入
- 详见 v3.2.0 更新日志
-
v3.1.4 (2026-05-20) - 修复版本:移动端目录与导航菜单优化
- 适配移动端文章目录深浅色主题样式
- 修复导航子菜单被扁平化展示的问题
- 优化菜单图标对图片 URL 和 data URL 的兼容
- 详见 v3.1.4 更新日志
-
v3.1.3 (2026-05-18) - 功能版本:评论置顶与主题自动切换
- 新增评论置顶功能,后台可切换置顶状态,前台优先展示置顶评论
- 新增主题自动切换功能,支持配置日间和夜间主题开始时间
- 新增评论置顶字段与主题切换配置数据库迁移
- 详见 v3.1.3 更新日志
-
v3.1.2 (2026-05-16) - 修复版本:文章导出 GitHub 图片代理优化
- 优化管理后台文章导出 ZIP 图片下载逻辑
raw.githubusercontent.com图片导出时自动使用https://gh-proxy.com/- 保持非 GitHub raw 图片原链下载
- 详见 v3.1.2 更新日志
-
v3.1.1 (2026-05-16) - 功能与修复版本:随机阅读与图片代理优化
- 新增前台导航栏随机阅读入口
- 新增
GET /api/v1/articles/random随机文章公开接口 - 修复导入文章自定义图片代理二次拼接问题
- 详见 v3.1.1 更新日志
-
v3.1.0 (2026-05-10) - 修复版本:核心功能修复与优化
- 侧边栏交互逻辑重构(Vue 响应式状态管理)
- 修复邮件发件人格式处理问题
- 更新一言 API 地址
- 详见 v3.1.0 更新日志
-
v3.0.2 (2026-05-05) - 功能版本:移动端用户体验优化
- 移动端分页组件隐藏页码优化
- 移动端用户表单布局优化
- 移动端系统设置全面优化
- 详见 v3.0.2 更新日志
-
v3.0.1 (2026-05-03) - 补丁版本:修复阿里云 ESA 环境 IP 获取问题
- 修复阿里云 ESA 环境下获取真实客户端 IP 地址
- 优化 IP 获取逻辑,支持多种 CDN 和反向代理环境
- 提升日志记录、限流控制、统计分析的准确性
- 详见 v3.0.1 更新日志
-
v3.0.0 (2026-05-03) - 重大版本更新:架构重构与功能增强
- 新增 MCP 协议支持
- 新增动态音频功能
- 增强邮件服务配置
- 全面重构前后端代码
- 详见 v3.0.0 更新日志
-
v2.0.1 (2026-04-27) - RSS 订阅功能增强与系统优化
- 详见 v2.0.1 更新日志
-
v2.0.0 (2026-04-26) - 重大版本更新:RSS 订阅与通知系统
- 详见 v2.0.0 更新日志
-
v1.0.1 (2026-04-16) - RSS 订阅功能增强版本
- 详见 v1.0.1 更新日志
-
v1.0.0 (2026-04-15) - 首个正式版本
- 详见 v1.0.0 更新日志
本项目采用 MIT License 开源协议。
MIT License 是一个宽松的开源许可证,允许您自由地使用、复制、修改、合并、发布、分发、再许可和/或销售本软件的副本。唯一的要求是在所有副本或重要部分中保留版权声明和许可声明。
感谢以下开源项目和技术社区的支持:
- Gin - 高性能的 Go Web 框架
- Vue.js - 渐进式 JavaScript 框架
- Nuxt - Vue.js 全栈框架
- Element Plus - 基于 Vue 3 的组件库
- GORM - Go 语言 ORM 库
- PostgreSQL - 强大的开源关系型数据库
- markdown-it - Markdown 解析器
- Highlight.js - 代码高亮库
特别感谢所有为本项目贡献代码、提出建议和报告问题的开发者。
如果您在使用过程中遇到问题,或有任何建议和反馈,欢迎通过以下方式联系:
- Email: 416685476@qq.com
- GitHub Issues: https://github.com/zyx3721/JeriBlog/issues
- 项目主页: https://github.com/zyx3721/JeriBlog
⭐ 如果这个项目对您有帮助,欢迎 Star 支持!