Skip to content

服务器配置手册

适用场景:阿里云 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存储日志数据和情绪数据
pm2Node 进程管理、开机自启
CaddyWeb 服务器、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.linkqingsu.link 的子域名)

关键设计

  • 后端生产环境直接托管前端 dist 静态文件,无需单独部署前端
  • 前端 API 请求使用相对路径 /api,无需配置域名
  • 端口使用 3001,通过 .env 控制,避免与 log-server(3000)冲突

backend/.env 文件

PORT=3001
NODE_ENV=production
MONGODB_URI=mongodb://localhost:27017/moods

server.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 记录:

主机记录记录类型记录值
moodsA47.109.130.211

六、部署步骤(迁移时按此顺序操作)

1. 安装全局依赖

cmd
npm install -g pm2

2. 确认 MongoDB 服务正在运行

在 Windows 服务管理器中确认 MongoDB 服务状态为"正在运行"。

3. 启动 log-server

cmd
cd C:\log-server
pm2 start app.js --name log-server

4. 构建并启动 Moods

cmd
cd C:\Moods
npm install
npm run build
cd backend
pm2 start server.js --name moods
pm2 save

5. 设置 pm2 开机自启

cmd
schtasks /create /tn "pm2-autostart" /tr "\"C:\Users\Administrator\AppData\Roaming\npm\pm2.cmd\" resurrect" /sc onstart /ru SYSTEM /f

6. 部署 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 → 安全组 → 入方向,确认以下端口已开放:

端口协议来源说明
80TCP0.0.0.0/0HTTP,Caddy 使用
443TCP0.0.0.0/0HTTPS,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.mtsthemeConfig.footer.copyright

九、迁移时常见踩坑

  1. Caddy 必须用管理员权限运行,否则无法监听 80/443 端口
  2. 各 Node 服务端口不能冲突:log-server 用 3000,Moods 用 3001
  3. 阿里云安全组记得开 443,这一步经常忘
  4. 域名 DNS 先解析到新服务器 IP,再启动 Caddy,否则证书申请会失败
  5. pm2 save 要在所有服务启动后执行,否则重启后进程列表不完整
  6. Caddy 下载选 windows amd64 版本,从 caddyserver.com 或 GitHub Releases 下载
  7. Moods 必须先 build 再启动后端,否则前端页面不存在
  8. Moods backend/.env 必须设置 NODE_ENV=production,否则不会托管前端静态文件
  9. 子域名 DNS 解析不会自动继承主域名,moods.qingsu.link 需要单独添加 A 记录