Appearance
服务器配置手册
适用场景:阿里云 Windows Server,三域名部署,Caddy + Node + VitePress
架构概览
用户访问
↓
Caddy(监听 80/443,处理 HTTPS + 自动续期)
↓ ↓ ↓
logserverhub.cn qingsu.link moods.qingsu.link
反向代理到 直接读取 反向代理到
Node:3000 VitePress Node:3001
↓ 静态文件 ↓
Express + Express + MongoDB
MongoDB (Moods 情绪日志)
(日志写入服务)一、环境依赖
| 软件 | 用途 |
|---|---|
| Node.js | 运行 log-server 和 Moods 后端 |
| MongoDB | 存储日志数据和情绪数据 |
| pm2 | Node 进程管理、开机自启 |
| Caddy | Web 服务器、HTTPS、反向代理 |
二、目录结构
C:\caddy\
├── caddy.exe
└── Caddyfile
C:\log-server\
├── app.js
├── package.json
└── public\
└── index.html
C:\Moods\
├── src/
├── backend/
│ ├── server.js
│ ├── models/
│ ├── routes/
│ └── .env ← 环境变量(PORT=3001)
├── dist/ ← 前端构建产物,由 backend 托管
└── package.json
C:\caddy\.vitepress\dist\ ← VitePress 构建产物
(或其他你放 dist 的路径)三、Caddyfile 配置
logserverhub.cn, www.logserverhub.cn {
reverse_proxy localhost:3000
}
qingsu.link, www.qingsu.link {
root * C:\caddy\.vitepress\dist
file_server
try_files {path} /index.html
}
moods.qingsu.link {
reverse_proxy localhost:3001
}四、log-server 的 app.js
关键原则:
- 不自己处理 HTTPS,交给 Caddy
- 监听
3000端口 - 用
express.static('public')提供首页 /api/log接口写入 MongoDB
javascript
const express = require('express')
const mongoose = require('mongoose')
const bodyParser = require('body-parser')
const cors = require('cors')
const app = express()
app.use(cors())
app.use(bodyParser.json())
app.use(express.static('public'))
mongoose.connect('mongodb://localhost:27017/logs', {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log('✅ MongoDB connected')
app.listen(3000, () => {
console.log('✅ Server running on port 3000')
})
})
.catch(err => {
console.error('❌ MongoDB 连接失败:', err)
process.exit(1)
})
const videoLogSchema = new mongoose.Schema({
video_url: { type: String, required: true, index: true },
platform: { type: String, required: true },
created_at: { type: Date, default: Date.now }
})
videoLogSchema.index({ video_url: 1, platform: 1 }, { unique: true })
const VideoLog = mongoose.model('VideoLog', videoLogSchema)
app.post('/api/log', async (req, res) => {
try {
const { logs } = req.body
if (!Array.isArray(logs) || logs.length === 0) {
return res.status(400).json({ code: 400, message: '无效的日志数据' })
}
const result = await VideoLog.insertMany(logs, { ordered: false })
res.json({
code: 200,
message: '上传成功',
inserted_count: result.length,
skipped: logs.length - result.length
})
} catch (err) {
if (err.code === 11000) {
return res.status(409).json({
code: 409,
message: '部分或全部视频已存在',
error: err.keyValue
})
}
console.error('❌ 插入日志失败:', err)
res.status(500).json({ code: 500, message: '服务器内部错误' })
}
})五、Moods 应用配置
技术栈
- 前端:React 18 + Three.js(React Three Fiber)+ Vite
- 后端:Node.js + Express + MongoDB(Mongoose)
- 域名:
moods.qingsu.link(qingsu.link的子域名)
关键设计
- 后端生产环境直接托管前端
dist静态文件,无需单独部署前端 - 前端 API 请求使用相对路径
/api,无需配置域名 - 端口使用
3001,通过.env控制,避免与 log-server(3000)冲突
backend/.env 文件
PORT=3001
NODE_ENV=production
MONGODB_URI=mongodb://localhost:27017/moodsserver.js 关键配置说明
javascript
const PORT = process.env.PORT || 3000 // 读取 .env 中的 PORT=3001
// 生产环境托管前端静态文件
if (process.env.NODE_ENV === 'production') {
const frontendPath = path.join(__dirname, '../dist')
app.use(express.static(frontendPath))
app.get('*', (req, res) => {
res.sendFile(path.join(frontendPath, 'index.html'))
})
}src/services/api.js 关键配置
javascript
// 使用相对路径,前后端同域名,无需写死地址
const API_BASE_URL = import.meta.env.VITE_API_URL || '/api'DNS 解析
在域名控制台给 qingsu.link 新增一条 A 记录:
| 主机记录 | 记录类型 | 记录值 |
|---|---|---|
| moods | A | 47.109.130.211 |
六、部署步骤(迁移时按此顺序操作)
1. 安装全局依赖
cmd
npm install -g pm22. 确认 MongoDB 服务正在运行
在 Windows 服务管理器中确认 MongoDB 服务状态为"正在运行"。
3. 启动 log-server
cmd
cd C:\log-server
pm2 start app.js --name log-server4. 构建并启动 Moods
cmd
cd C:\Moods
npm install
npm run build
cd backend
pm2 start server.js --name moods
pm2 save5. 设置 pm2 开机自启
cmd
schtasks /create /tn "pm2-autostart" /tr "\"C:\Users\Administrator\AppData\Roaming\npm\pm2.cmd\" resurrect" /sc onstart /ru SYSTEM /f6. 部署 VitePress 静态文件
在本地 Mac 上构建:
bash
npm run build将 .vitepress/dist 文件夹上传到服务器对应路径。
7. 配置 Caddyfile
按第三节模板填好两个域名和路径,保存到 C:\caddy\Caddyfile。
8. 注册 Caddy 为系统服务
在管理员 cmd 中执行:
cmd
sc create caddy binPath= "C:\caddy\caddy.exe run --config C:\caddy\Caddyfile" start= auto DisplayName= "Caddy Web Server"
sc start caddy注意:
binPath=和start=后面的空格是必须的,不能删除。
9. 开放阿里云安全组端口
进入阿里云控制台 → ECS → 安全组 → 入方向,确认以下端口已开放:
| 端口 | 协议 | 来源 | 说明 |
|---|---|---|---|
| 80 | TCP | 0.0.0.0/0 | HTTP,Caddy 使用 |
| 443 | TCP | 0.0.0.0/0 | HTTPS,Caddy 使用 |
| 3000 | - | 不需要对外开放 | 仅本机内部使用 |
10. 验证
- 访问
https://logserverhub.cn→ 看到首页 - 访问
https://qingsu.link→ 看到 VitePress 网站 - 访问
https://moods.qingsu.link→ 看到 Moods 情绪日志应用 - 重启服务器 → 三个域名都能自动恢复访问
七、常用维护命令
pm2 相关
cmd
pm2 list # 查看所有进程状态
pm2 logs log-server # 查看 log-server 日志
pm2 logs moods # 查看 Moods 日志
pm2 restart log-server # 重启 log-server
pm2 restart moods # 重启 Moods
pm2 stop log-server # 停止 log-server
pm2 stop moods # 停止 Moods
pm2 save # 保存当前进程列表Caddy 相关
cmd
sc start caddy # 启动服务
sc stop caddy # 停止服务
sc query caddy # 查看状态
sc delete caddy # 删除服务修改 Caddyfile 后重载配置(不需要重启服务):
cmd
caddy.exe reload --config C:\caddy\Caddyfile八、备案信息
| 项目 | 内容 |
|---|---|
| 网站域名 | qingsu.link |
| 备案号 | 滇ICP备2025054458号-3 |
| 备案查询 | https://beian.miit.gov.cn |
| 配置位置 | .vitepress/config.mts → themeConfig.footer.copyright |
九、迁移时常见踩坑
- Caddy 必须用管理员权限运行,否则无法监听 80/443 端口
- 各 Node 服务端口不能冲突:log-server 用 3000,Moods 用 3001
- 阿里云安全组记得开 443,这一步经常忘
- 域名 DNS 先解析到新服务器 IP,再启动 Caddy,否则证书申请会失败
- pm2 save 要在所有服务启动后执行,否则重启后进程列表不完整
- Caddy 下载选 windows amd64 版本,从 caddyserver.com 或 GitHub Releases 下载
- Moods 必须先 build 再启动后端,否则前端页面不存在
- Moods backend/.env 必须设置 NODE_ENV=production,否则不会托管前端静态文件
- 子域名 DNS 解析不会自动继承主域名,moods.qingsu.link 需要单独添加 A 记录