目录
VanBlog 是一款开源的个人博客系统(GPL-3.0),仓库地址:
官方提供 Docker / 一键脚本部署。本文记录的是 从 GitHub 源码本地构建,并拆分前后端部署 的完整流程,适合需要前后端分离、内网托管管理后台的场景。
本站当前架构大致如下:
| 角色 | 说明 |
|---|---|
| 前台 Website | Next.js 静态站,对外提供访客页面 |
| 后端 Server | NestJS API + MongoDB + Waline 评论 |
| 后台 Admin | Umi 管理面板,建议仅内网访问 |
| 隧道 | 内网后端通过 SSH 反向隧道把 API 暴露给公网前台 |
一、项目结构(源码)
克隆仓库后,核心在 packages/:
textvanblog/ ├── packages/ │ ├── server/ # NestJS 后端(默认 :3000) │ ├── website/ # Next.js 前台(默认 :3001) │ ├── admin/ # 管理后台(构建为静态资源) │ ├── waline/ # 评论服务(由 server 拉起) │ └── cli/ ├── docs/ └── package.json # pnpm monorepo
运行关系可以简化为:
text浏览器 ──► Website(:3001) ── /api ──► Server(:3000) ──► MongoDB 浏览器 ──► Admin(静态) ── /api ──► Server(:3000) Server ──► Waline(:8360)
二、环境准备
建议环境:
- Node.js 18 LTS
- pnpm(仓库自带
pnpm-lock.yaml) - MongoDB 4.4+ / 5.x / 6.x
- Nginx(反代静态与 API)
- (可选)autossh / systemd,用于隧道与进程守护
bash# 示例:启用 pnpm
corepack enable
corepack prepare pnpm@8 --activate
git clone https://github.com/mereithhh/van-blog.git
cd van-blog
pnpm install
构建时若遇到 OpenSSL / 内存问题,可设置:
export NODE_OPTIONS='--max_old_space_size=4096 --openssl-legacy-provider'
三、从源码构建
1. 后端 Server
bashpnpm --filter server build
# 产物:packages/server/dist
生产启动示例环境变量:
bashexport NODE_ENV=production
export VAN_BLOG_DATABASE_URL='mongodb://127.0.0.1:27017/vanBlog?authSource=admin'
export VAN_BLOG_STATIC_PATH=/opt/vanblog/data/static
export VAN_BLOG_LOG=/opt/vanblog/log
# 前后端分离、本机不跑 website 时:
export VANBLOG_DISABLE_WEBSITE=true
node packages/server/dist/src/main.js
Server 默认监听 3000,并会按配置拉起 Waline(默认 8360)。
2. 管理后台 Admin
Admin 以子路径 /admin/ 部署时,需要生产构建:
bashexport EEE=production
pnpm build:admin
# 产物:packages/admin/dist
# base / publicPath 均为 /admin/
用 Nginx 托管 dist,并把 /api、/static 反代到 Server。
3. 前台 Website
bashpnpm --filter website build
# 使用 standalone 产物更利于部署
前台需要能访问到后端 API,例如:
bashexport VAN_BLOG_SERVER_URL=http://127.0.0.1:3000
export PORT=3001
node packages/website/server.js # standalone 路径以实际产物为准
四、推荐的拆分部署方式
拓扑示意
text公网机器 A(前台) 内网机器 B(后端 + 后台) ┌─────────────────────┐ ┌──────────────────────────┐ │ Nginx :80 │ │ Nginx :80 → Admin 静态 │ │ Website :3001 │◄─SSH隧道─│ Server :3000 │ │ 反代 /api → :3000 │ │ MongoDB │ └─────────────────────┘ │ Waline :8360 │ └──────────────────────────┘
要点:
- 前台放公网:只暴露 Website + 必要的
/api、/static。 - 后台放内网:Admin 不要映射到公网,降低爆破风险。
- SSH 反向隧道:由内网机器主动连公网,把本机
3000/8360映射到公网机的127.0.0.1:3000/8360,供前台 Nginx / Website 访问。 - 隧道建议做成 systemd 服务,并可用 timer 在每天凌晨做一次重连保活。
公网 Nginx(前台)示意
nginxserver { listen 80; server_name your.domain; location / { proxy_pass http://127.0.0.1:3001; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /api/ { proxy_pass http://127.0.0.1:3000/api/; client_max_body_size 50m; } location /static/ { proxy_pass http://127.0.0.1:3000/static/; } # 不建议对公网开放 /admin }
内网 Nginx(后台)示意
nginxserver { listen 80; root /var/www; location = / { return 302 /admin/; } location /admin/ { try_files $uri $uri/ /admin/index.html; } location /api/ { proxy_pass http://127.0.0.1:3000/api/; client_max_body_size 50m; } location /static/ { proxy_pass http://127.0.0.1:3000/static/; } }
将 packages/admin/dist 软链到 /var/www/admin 即可。
五、systemd 守护(示例)
MongoDB / Server / Website / 隧道 都可以写成 service。Server 示例:
ini[Unit]
Description=VanBlog NestJS API Server
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/vanblog/packages/server
Environment=NODE_ENV=production
Environment=VANBLOG_DISABLE_WEBSITE=true
Environment=VAN_BLOG_DATABASE_URL=mongodb://127.0.0.1:27017/vanBlog?authSource=admin
Environment=VAN_BLOG_STATIC_PATH=/opt/vanblog/data/static
Environment=VAN_BLOG_LOG=/opt/vanblog/log
ExecStart=/usr/local/bin/node dist/src/main.js
Restart=always
[Install]
WantedBy=multi-user.target
隧道(示意,按实际用户与端口调整):
bashautossh -M 0 -N \ -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \ -R 3000:127.0.0.1:3000 \ -R 8360:127.0.0.1:8360 \ user@公网机器
六、初始化与登录
- 浏览器访问内网 Admin:
http://<内网IP>/admin/ - 首次未初始化时,会进入初始化向导(创建管理员、站点信息)
- 初始化完成后,用管理员账号登录后台发文、改站点设置
站点「网站 URL」请填写完整协议,例如:https://www.example.com,否则 RSS、部分跳转可能异常。
图床本地模式下,图片一般落在 VAN_BLOG_STATIC_PATH,通过 /static/img/... 访问;前后端分离时请保证公网也能反代到 /static。
七、常见问题
1. /api/admin/meta 返回 401
站点已初始化后,该接口需要登录。未登录时返回 401 是正常现象,后台会跳到登录页。带上有效 token 请求头后应返回 200。
2. 登录提示密码错误
VanBlog 密码不是明文传输:
- 前端先用
encryptPwd(username, password)做浏览器侧哈希 - 后端再用盐
encryptPassword(username, hash, salt)校验
因此用接口调试时,不能直接把明文密码塞进 password 字段。
3. 前台发文后看不到更新
拆分部署且 VANBLOG_DISABLE_WEBSITE=true 时,Server 不会自动触发本机 ISR。需要:
- 给 Website 配置可达的 API,并依赖 ISR /
revalidate时间;或 - 手动请求前台:
/api/revalidate?path=/(以及文章、分类等路径)
4. 忘记管理员密码
Server 启动日志会打印恢复密钥;也可写入日志目录下的 restore.key。在后台「忘记密码」页用该密钥重置。
八、参考链接
- GitHub:https://github.com/mereithhh/van-blog
- 官方文档:https://vanblog.mereith.com
- 官方一键脚本适合「单机 Docker」;本文适合「源码构建 + 前后端分离」
以上即为本站采用的 VanBlog 源码搭建与拆分部署流程,后续文章会继续补充运维与使用笔记。
ai协作,人工编辑