# 有声书项目 - 生产环境部署文档 ## 环境信息 | 项目 | 值 | |------|-----| | 服务器 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 | ## 快速部署 ```bash # 一键部署(本地执行) ./deploy-prod.sh ``` ## 服务器目录结构 ``` /data/ai/audio/ ├── server/ # 后端服务 │ ├── dist/ # 编译后的 JS 文件 │ ├── prisma/ # 数据库 schema │ ├── uploads/ # 上传文件 │ ├── public/videos/ # 视频文件 │ └── .env # 环境变量 ├── frontend/ │ └── build/h5/ # 前端构建产物 └── backup_YYYYMMDD_HHMMSS/ # 备份 ``` ## 服务管理命令 ```bash # 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. 构建本地项目 ```bash # 构建前端 cd my-uniapp-vue3 npm run build:h5 # 构建后端 cd ../server npm run build ``` ### 2. 同步文件到服务器 ```bash # 同步后端(排除 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 安装依赖 ```bash cd /data/ai/audio/server npm install --production npx prisma generate ``` #### 3.2 环境变量 (.env) ```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 ```nginx 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 ```bash nginx -t && nginx -s reload ``` ### 5. 启动后端服务 ```bash 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 命令 ```bash # 进入 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 配置文件 | ## 故障排查 ### 后端服务无法启动 ```bash # 查看错误日志 pm2 logs server --err --lines 50 # 手动测试运行 cd /data/ai/audio/server export SERVER_PORT=3100 node dist/app.js ``` ### 数据库连接失败 ```bash # 检查 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 错误 ```bash # 检查后端是否运行 pm2 status # 检查端口监听 ss -tlnp | grep 3100 # 测试直接访问 curl http://localhost:3100/health # 检查 Nginx 配置 nginx -t ``` ### 重启所有服务 ```bash # 重启后端 pm2 restart server # 重载 Nginx nginx -s reload # 重启 MySQL(如需要) docker restart single-mysql ``` ### 重新部署完整流程 ```bash # 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 ```