DEPLOY_PROD.md 9.1 KB

有声书项目 - 生产环境部署文档

环境信息

项目
服务器 IP 8.159.134.106
部署路径 /data/ai/audio
后端端口 3100
前端路径 /data/ai/audio/frontend/build/h5
域名 book.rrbrr.com
后端 API 域名 book.rrbrr.com/api
SSH 端口 22622
SSH Key ~/.ssh/id_rsa

Nginx 配置由宝塔面板管理,配置文件位于 /www/server/panel/vhost/nginx/

服务地址

服务 地址
前端 http://book.rrbrr.com
后端 API http://book.rrbrr.com/api
健康检查 http://book.rrbrr.com/api/health

快速部署

# 一键部署(本地执行)
./deploy-prod.sh

服务器目录结构

/data/ai/audio/
├── server/              # 后端服务
│   ├── dist/            # 编译后的 JS 文件
│   ├── prisma/         # 数据库 schema
│   ├── uploads/         # 上传文件
│   ├── public/videos/  # 视频文件
│   └── .env            # 环境变量
├── frontend/
│   └── build/h5/       # 前端构建产物
└── backup_YYYYMMDD_HHMMSS/  # 备份

服务管理命令

# SSH 连接
ssh -i ~/.ssh/id_rsa -p 22622 root@8.159.134.106

# 查看后端服务状态
pm2 status

# 查看后端日志
pm2 logs server --lines 100

# 重启后端服务
pm2 restart server

# 重载 Nginx
nginx -s reload

手动部署步骤

1. 构建本地项目

# 构建前端
cd my-uniapp-vue3
npm run build:h5

# 构建后端
cd ../server
npm run build

2. 同步文件到服务器

# 同步后端(排除 node_modules, .ts 等)
rsync -azP -e "ssh -i ~/.ssh/id_rsa -p 22622" \
  --exclude='node_modules' --exclude='.git' --exclude='*.ts' \
  --exclude='test-*.js' --exclude='*.log' \
  server/ root@8.159.134.106:/data/ai/audio/server/

# 同步前端
rsync -azP -e "ssh -i ~/.ssh/id_rsa -p 22622" \
  my-uniapp-vue3/dist/ root@8.159.134.106:/data/ai/audio/frontend/

3. 服务器端配置

3.1 安装依赖

cd /data/ai/audio/server
npm install --production
npx prisma generate

3.2 环境变量 (.env)

NODE_ENV=production
SERVER_PORT=3100
AUTH_ENABLED=false

JWT_SECRET=my-jwt-secret-key-2024
JWT_EXPIRES_IN=7d

# 阿里云百炼 TTS
DASHSCOPE_API_KEY=sk-c25679401ba24c749f53be86b0c9a7a6
DASHSCOPE_MODEL=qwen3-tts-instruct-flash
DASHSCOPE_TTS_MODELS=qwen3-tts-flash
DASHSCOPE_VOICE=Cherry
DASHSCOPE_USE_REALTIME=true
DASHSCOPE_REALTIME_MODEL=qwen3-tts-instruct-flash-realtime

# MySQL (Docker MySQL 8.0)
DATABASE_URL="mysql://root:password@localhost:3306/audio_book"

# 存储
STORAGE_TYPE=oss

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0

# 阿里云 OSS
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com
OSS_ACCESS_KEY_ID=LTAI5tBn4G5HMo8PqMdNsqHd
OSS_ACCESS_KEY_SECRET=f0R5nOQf6E1lIGESENKiK8cNzFl8wd
OSS_BUCKET_NAME=aaaa33dfsf32rfsf
OSS_REGION=cn-hangzhou

# Minimax
MINIMAX_API_KEY=sk-cp-s8hGJr4ACdlZ4GM0LjZ1l2ZNBUAMGwd2ahl0c3W2g6C0EiNH0UvwOBx2q0oJOYO6ca5HqJccP_KRUPucoBizavlwDSZp-ohOGeUw2ymAdXPuM6r3CIDmmlY

4. 配置 Nginx

Nginx 配置文件位置:/www/server/panel/vhost/nginx/

4.1 前端 - html_book.rrbrr.com.conf

server
{
    listen 80;
    server_name book.rrbrr.com;
    return 301 https://$server_name$request_uri;
}

server
{
    listen 443 ssl;
    http2 on;
    server_name book.rrbrr.com;
    index index.html index.htm default.htm default.html;
    root /data/ai/audio/frontend/build/h5;
    include /www/server/panel/vhost/nginx/extension/book.rrbrr.com/*.conf;
    #CERT-APPLY-CHECK--START
    # 用于SSL证书申请时的文件验证相关配置 -- 请勿删除并保持这段设置在优先级高的位置
    include /www/server/panel/vhost/nginx/well-known/book.rrbrr.com.conf;
    #CERT-APPLY-CHECK--END

    #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
    #error_page 404/404.html;
    ssl_certificate /www/server/panel/vhost/cert/book.rrbrr.com/fullchain.pem;
    ssl_certificate_key /www/server/panel/vhost/cert/book.rrbrr.com/privkey.pem;
    ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
    ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_tickets on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    add_header Strict-Transport-Security "max-age=31536000";
    add_header Alt-Svc 'quic=":443"; h3=":443"; h3-29=":443"; h3-27=":443";h3-25=":443"; h3-T050=":443"; h3-Q050=":443";h3-Q049=":443";h3-Q048=":443"; h3-Q046=":443"; h3-Q043=":443"';
    error_page 497 https://$host$request_uri;
    #SSL-END

    #ERROR-PAGE-START  错误页配置,可以注释、删除或修改
    #error_page 404 /404.html;
    #error_page 502 /502.html;
    #ERROR-PAGE-END

    #API-PROXY-START
    location /api/ {
        proxy_pass http://127.0.0.1:3100;
        proxy_set_header Host $http_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;
    }
    #API-PROXY-END

    #REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
    include /www/server/panel/vhost/rewrite/html_book.rrbrr.com.conf;
    #REWRITE-END

    #禁止访问的文件或目录
    location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
    {
        return 404;
    }

    #一键申请SSL证书验证目录相关设置
    location ~ \.well-known{
        allow all;
    }

    #禁止在证书验证目录放入敏感文件
    if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
        return 403;
    }

    location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
    {
        expires      30d;
        error_log /dev/null;
        access_log /dev/null;
    }

    location ~ .*\.(js|css)?$
    {
        expires      12h;
        error_log /dev/null;
        access_log /dev/null;
    }
    access_log  /www/wwwlogs/book.rrbrr.com.log;
    error_log  /www/wwwlogs/book.rrbrr.com.error.log;
}

4.3 重载 Nginx

nginx -t && nginx -s reload

5. 启动后端服务

cd /data/ai/audio/server
export SERVER_PORT=3100

# 停止旧服务
pm2 delete server 2>/dev/null || true

# 启动服务
pm2 start dist/app.js --name server --env production

# 保存并设置开机启动
pm2 save
pm2 startup

6. 数据库操作

MySQL Docker 信息

项目
容器名 single-mysql
版本 MySQL 8.0
端口 3306 (Docker 映射到主机)
密码 password
数据库 audio_book

常用 MySQL 命令

# 进入 MySQL 容器
docker exec -it single-mysql mysql -u root -ppassword

# 查看数据库
docker exec single-mysql mysql -u root -ppassword -e 'SHOW DATABASES;'

# 执行 SQL
docker exec single-mysql mysql -u root -ppassword audio_book -e 'SELECT 1;'

# 备份数据库
docker exec single-mysql mysqldump -u root -ppassword audio_book > audio_book_$(date +%Y%m%d).sql

# 数据库迁移
cd /data/ai/audio/server
npx prisma migrate deploy

数据库信息

项目
类型 MySQL 8.0 (Docker)
容器 single-mysql
主机连接 localhost:3306
容器内连接 3306
数据库名 audio_book
用户名 root
密码 password

文件说明

文件/目录 说明
/data/ai/audio/server/ 后端 Node.js 服务
/data/ai/audio/frontend/build/h5/ 前端 H5 构建产物
/data/ai/audio/server/uploads/ 用户上传文件
/data/ai/audio/server/public/videos/ 生成的视频文件
/www/server/panel/vhost/nginx/ Nginx 配置文件

故障排查

后端服务无法启动

# 查看错误日志
pm2 logs server --err --lines 50

# 手动测试运行
cd /data/ai/audio/server
export SERVER_PORT=3100
node dist/app.js

数据库连接失败

# 检查 MySQL 容器状态
docker ps | grep mysql

# 重启 MySQL 容器
docker restart single-mysql

# 测试连接
docker exec single-mysql mysql -u root -ppassword -e 'SELECT 1;'

# 检查 .env 数据库配置
cat /data/ai/audio/server/.env | grep DATABASE

Nginx 502 错误

# 检查后端是否运行
pm2 status

# 检查端口监听
ss -tlnp | grep 3100

# 测试直接访问
curl http://localhost:3100/health

# 检查 Nginx 配置
nginx -t

重启所有服务

# 重启后端
pm2 restart server

# 重载 Nginx
nginx -s reload

# 重启 MySQL(如需要)
docker restart single-mysql

重新部署完整流程

# 1. 同步文件
rsync -azP -e "ssh -i ~/.ssh/id_rsa -p 22622" --exclude='node_modules' --exclude='.git' --exclude='*.ts' server/ root@8.159.134.106:/data/ai/audio/server/
rsync -azP -e "ssh -i ~/.ssh/id_rsa -p 22622" my-uniapp-vue3/dist/ root@8.159.134.106:/data/ai/audio/frontend/

# 2. 服务器端
ssh -i ~/.ssh/id_rsa -p 22622 root@8.159.134.106
cd /data/ai/audio/server
npm install --production
npx prisma generate
export SERVER_PORT=3100
pm2 restart server
nginx -s reload