docs: 重组文档结构,按模块分类
新的文档结构:
docs/
├── README.md # 文档中心导航
├── modules/ # 模块文档
│ ├── auth/ # 认证模块
│ │ ├── README.md
│ │ ├── feishu-login.md
│ │ ├── feishu-qrcode.md
│ │ └── feishu-notification.md
│ ├── approval/ # 审批流程模块
│ │ └── README.md
│ ├── business-trip/ # 出差申请模块
│ │ └── README.md
│ └── user/ # 用户管理模块
│ └── README.md
└── guides/ # 指南文档
├── deployment.md
├── environment.md
├── git-workflow.md
└── ...
每个模块都有独立的 README.md 说明概述、API、关键文件等
This commit is contained in:
@@ -0,0 +1,598 @@
|
||||
# X-Server Mobile 线上部署方案
|
||||
|
||||
## 线上环境
|
||||
|
||||
- **面板**: 1Panel (Docker 管理)
|
||||
- **Web 服务器**: OpenResty
|
||||
- **数据库**: MySQL (容器)
|
||||
- **缓存**: Redis (容器)
|
||||
- **域名**: `xsm.hnxinyouhe.com` (待配置)
|
||||
|
||||
---
|
||||
|
||||
## 架构设计
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ OpenResty (80/443) │
|
||||
│ ┌─────────────────────────────┐ │
|
||||
│ │ 静态资源托管 │ │
|
||||
│ │ /frontend/dist/* │ │
|
||||
│ │ SPA Router fallback │ │
|
||||
│ └─────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────┐ │
|
||||
│ │ API 反向代理 │ │
|
||||
│ │ /api/* → localhost:8787 │ │
|
||||
│ └─────────────────────────────┘ │
|
||||
│ ┌─────────────────────────────┐ │
|
||||
│ │ 飞书回调代理 │ │
|
||||
│ │ /login/* → localhost:8787 │ │
|
||||
│ └─────────────────────────────┘ │
|
||||
└─────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
▼ ▼ ▼
|
||||
┌───────────┐ ┌───────────┐ ┌───────────┐
|
||||
│ 后端 │ │ MySQL │ │ Redis │
|
||||
│ :8787 │ │ :3306 │ │ :6379 │
|
||||
│ Docker │ │ 1Panel │ │ 1Panel │
|
||||
└───────────┘ └───────────┘ └───────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 部署步骤
|
||||
|
||||
### 第一步:准备线上目录结构
|
||||
|
||||
```bash
|
||||
# 在服务器上创建部署目录
|
||||
mkdir -p /opt/x-server-mobile
|
||||
mkdir -p /opt/x-server-mobile/frontend
|
||||
mkdir -p /opt/x-server-mobile/backend
|
||||
mkdir -p /opt/x-server-mobile/logs
|
||||
mkdir -p /opt/x-server-mobile/backup
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第二步:前端部署
|
||||
|
||||
#### 2.1 本地构建
|
||||
|
||||
```bash
|
||||
# 在开发环境
|
||||
cd /www/x-server-mobile/frontend
|
||||
|
||||
# 安装依赖(如果需要)
|
||||
npm install
|
||||
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
|
||||
# 生成的文件在 frontend/dist/ 目录
|
||||
```
|
||||
|
||||
#### 2.2 上传静态文件
|
||||
|
||||
```bash
|
||||
# 方式1:使用 scp 上传
|
||||
scp -r frontend/dist/* root@your-server:/opt/x-server-mobile/frontend/
|
||||
|
||||
# 方式2:使用 rsync 同步
|
||||
rsync -avz --delete frontend/dist/ root@your-server:/opt/x-server-mobile/frontend/
|
||||
```
|
||||
|
||||
#### 2.3 构建环境配置
|
||||
|
||||
创建 `frontend/.env.production`:
|
||||
|
||||
```env
|
||||
# API 地址(使用相对路径,由 OpenResty 代理)
|
||||
VITE_API_BASE=/api/v1
|
||||
|
||||
# 或使用绝对地址(如果前后端分离部署)
|
||||
# VITE_API_BASE=https://api.xsm.hnxinyouhe.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第三步:后端部署
|
||||
|
||||
#### 3.1 创建生产环境 Docker Compose
|
||||
|
||||
**文件**: `/opt/x-server-mobile/deploy/docker-compose.prod.yml`
|
||||
|
||||
```yaml
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
container_name: x-server-backend-prod
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8787:8787"
|
||||
environment:
|
||||
# 生产环境配置
|
||||
- APP_ENV=production
|
||||
- APP_DEBUG=false
|
||||
|
||||
# 数据库配置(使用 1Panel 的 MySQL)
|
||||
- DB_HOST=1Panel-mysql-xxxx # 替换为实际容器名
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=xserver
|
||||
- DB_USERNAME=xserver # 建议创建专用数据库用户
|
||||
- DB_PASSWORD=your_password # 强密码
|
||||
|
||||
# Redis 配置(使用 1Panel 的 Redis)
|
||||
- REDIS_HOST=1Panel-redis-xxxx # 替换为实际容器名
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_PASSWORD=your_redis_password
|
||||
|
||||
# 飞书配置
|
||||
- FEISHU_APP_ID=cli_xxxxxxxxxxxxx
|
||||
- FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxx
|
||||
- FEISHU_ENCRYPT_KEY=xxxxxxxxxxxxxxxxxxxx
|
||||
- FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxxxxxx
|
||||
- FEISHU_TENANT_KEY=xxxxxxxxxxxxxxxxxxxx
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
- ./logs/app:/app/runtime/logs
|
||||
networks:
|
||||
- 1panel-network
|
||||
healthcheck:
|
||||
test: ["CMD", "php", "-r", "exit(0);"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
networks:
|
||||
1panel-network:
|
||||
external: true
|
||||
```
|
||||
|
||||
#### 3.2 创建生产环境后端配置
|
||||
|
||||
**后端 OPcache 配置** (`deploy/php-prod.ini`):
|
||||
|
||||
```ini
|
||||
# 生产环境 OPcache 配置
|
||||
opcache.enable=1
|
||||
opcache.memory_consumption=128
|
||||
opcache.interned_strings_buffer=8
|
||||
opcache.max_accelerated_files=10000
|
||||
opcache.revalidate_freq=60
|
||||
opcache.fast_shutdown=1
|
||||
opcache.enable_cli=1
|
||||
|
||||
# 禁用错误显示
|
||||
display_errors=0
|
||||
display_startup_errors=0
|
||||
log_errors=1
|
||||
error_log=/app/runtime/logs/php_errors.log
|
||||
```
|
||||
|
||||
#### 3.3 更新 Dockerfile
|
||||
|
||||
```dockerfile
|
||||
FROM php:8.5-cli
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
unzip \
|
||||
git \
|
||||
libzip-dev \
|
||||
libpng-dev \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install PHP extensions
|
||||
RUN docker-php-ext-install zip pdo pdo_mysql bcmath pcntl opcache
|
||||
|
||||
# Install Composer
|
||||
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy composer files
|
||||
COPY composer.json composer.lock* ./
|
||||
|
||||
# Install dependencies
|
||||
RUN composer install --no-dev --optimize-autoloader --no-interaction
|
||||
|
||||
# Copy application files
|
||||
COPY . .
|
||||
|
||||
# Copy PHP configuration
|
||||
COPY php-prod.ini /usr/local/etc/php/conf.d/99-production.ini
|
||||
|
||||
# Create runtime directories
|
||||
RUN mkdir -p /app/runtime/logs
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8787
|
||||
|
||||
# Start webman in foreground mode
|
||||
CMD ["php", "start.php", "start"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第四步:OpenResty 配置
|
||||
|
||||
#### 4.1 站点配置
|
||||
|
||||
**文件**: `/usr/local/openresty/nginx/conf/conf.d/x-server-mobile.conf`
|
||||
|
||||
```nginx
|
||||
# X-Server Mobile 线上环境配置
|
||||
server {
|
||||
listen 80;
|
||||
server_name xsm.hnxinyouhe.com;
|
||||
|
||||
# 强制 HTTPS
|
||||
return 301 https://$server_name$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name xsm.hnxinyouhe.com;
|
||||
|
||||
# SSL 证书配置(使用 Let's Encrypt 或自签名)
|
||||
ssl_certificate /etc/nginx/ssl/xsm.hnxinyouhe.com.crt;
|
||||
ssl_certificate_key /etc/nginx/ssl/xsm.hnxinyouhe.com.key;
|
||||
|
||||
# SSL 安全配置
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
# 日志
|
||||
access_log /opt/x-server-mobile/logs/nginx_access.log;
|
||||
error_log /opt/x-server-mobile/logs/nginx_error.log;
|
||||
|
||||
# Gzip 压缩
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml text/javascript
|
||||
application/json application/javascript application/xml+rss
|
||||
application/rss+xml font/truetype font/opentype
|
||||
application/vnd.ms-fontobject image/svg+xml;
|
||||
|
||||
# 静态资源缓存
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|webp|svg|ico|woff|woff2|ttf|eot)$ {
|
||||
root /opt/x-server-mobile/frontend;
|
||||
expires 7d;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# 飞书回调(必须在 API 之前配置)
|
||||
location /login {
|
||||
proxy_pass http://127.0.0.1:8787;
|
||||
proxy_http_version 1.1;
|
||||
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;
|
||||
}
|
||||
|
||||
location /login/callback {
|
||||
proxy_pass http://127.0.0.1:8787;
|
||||
proxy_http_version 1.1;
|
||||
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;
|
||||
}
|
||||
|
||||
location /login/qrcode {
|
||||
proxy_pass http://127.0.0.1:8787;
|
||||
proxy_http_version 1.1;
|
||||
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;
|
||||
}
|
||||
|
||||
# 飞书卡片回调
|
||||
location /feishu/card/callback {
|
||||
proxy_pass http://127.0.0.1:8787;
|
||||
proxy_http_version 1.1;
|
||||
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 代理
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8787;
|
||||
proxy_http_version 1.1;
|
||||
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;
|
||||
proxy_set_header Host $host;
|
||||
|
||||
# 超时配置
|
||||
proxy_connect_timeout 60s;
|
||||
proxy_send_timeout 60s;
|
||||
proxy_read_timeout 60s;
|
||||
}
|
||||
|
||||
# 前端 SPA(所有其他请求返回 index.html)
|
||||
location / {
|
||||
root /opt/x-server-mobile/frontend;
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4.2 配置说明
|
||||
|
||||
1. **静态资源**: 直接由 OpenResty 托管,7天缓存
|
||||
2. **API 请求**: 代理到后端 8787 端口
|
||||
3. **飞书回调**: 特殊路径直接代理到后端
|
||||
4. **SPA 路由**: 所有其他请求返回 index.html
|
||||
|
||||
---
|
||||
|
||||
### 第五步:数据库准备
|
||||
|
||||
#### 5.1 创建数据库和用户
|
||||
|
||||
```sql
|
||||
-- 创建专用数据库用户
|
||||
CREATE USER 'xserver'@'%' IDENTIFIED BY 'your_strong_password';
|
||||
|
||||
-- 授予权限
|
||||
GRANT ALL PRIVILEGES ON xserver.* TO 'xserver'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
-- 如果数据库不存在,创建并导入结构
|
||||
CREATE DATABASE IF NOT EXISTS xserver CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
```
|
||||
|
||||
#### 5.2 数据库迁移
|
||||
|
||||
```bash
|
||||
# 从开发环境导出数据
|
||||
docker exec 1Panel-mysql-409s mysqldump -uroot -pmysql_xEsdPa xserver > xserver_backup.sql
|
||||
|
||||
# 导入到线上数据库
|
||||
docker exec -i 1Panel-mysql-xxxx mysql -uxserver -pyour_password xserver < xserver_backup.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第六步:SSL 证书配置
|
||||
|
||||
#### 6.1 使用 Let's Encrypt(推荐)
|
||||
|
||||
```bash
|
||||
# 安装 certbot
|
||||
apt-get install certbot
|
||||
|
||||
# 获取证书
|
||||
certbot certonly --standalone -d xsm.hnxinyouhe.com
|
||||
|
||||
# 证书路径
|
||||
# /etc/letsencrypt/live/xsm.hnxinyouhe.com/fullchain.pem
|
||||
# /etc/letsencrypt/live/xsm.hnxinyouhe.com/privkey.pem
|
||||
```
|
||||
|
||||
#### 6.2 自动续期
|
||||
|
||||
```bash
|
||||
# 添加 crontab
|
||||
0 3 * * * certbot renew --quiet && nginx -s reload
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第七步:部署流程
|
||||
|
||||
#### 开发到生产部署
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# deploy.sh - 部署脚本
|
||||
|
||||
set -e
|
||||
|
||||
echo "========================================="
|
||||
echo " X-Server Mobile 生产部署脚本"
|
||||
echo "========================================="
|
||||
|
||||
# 1. 备份当前版本
|
||||
echo "📦 备份当前版本..."
|
||||
ssh root@your-server "mkdir -p /opt/x-server-mobile/backup/\$(date +%Y%m%d_%H%M%S)"
|
||||
ssh root@your-server "cp -r /opt/x-server-mobile/frontend /opt/x-server-mobile/backup/\$(date +%Y%m%d_%H%M%S)/"
|
||||
|
||||
# 2. 构建前端
|
||||
echo "🔨 构建前端..."
|
||||
cd frontend
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# 3. 上传前端
|
||||
echo "📤 上传前端..."
|
||||
rsync -avz --delete dist/ root@your-server:/opt/x-server-mobile/frontend/
|
||||
|
||||
# 4. 上传后端
|
||||
echo "📤 上传后端..."
|
||||
rsync -avz --exclude='vendor' --exclude='runtime' \
|
||||
../backend/ root@your-server:/opt/x-server-mobile/backend/
|
||||
|
||||
# 5. 重启后端容器
|
||||
echo "🔄 重启后端..."
|
||||
ssh root@your-server "cd /opt/x-server-mobile && docker-compose -f docker-compose.prod.yml restart backend"
|
||||
|
||||
# 6. 重载 OpenResty
|
||||
echo "🔄 重载 OpenResty..."
|
||||
ssh root@your-server "openresty -s reload"
|
||||
|
||||
echo "✅ 部署完成!"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第八步:监控和日志
|
||||
|
||||
#### 8.1 日志位置
|
||||
|
||||
```bash
|
||||
# Nginx 访问日志
|
||||
/opt/x-server-mobile/logs/nginx_access.log
|
||||
|
||||
# Nginx 错误日志
|
||||
/opt/x-server-mobile/logs/nginx_error.log
|
||||
|
||||
# 后端应用日志
|
||||
docker logs x-server-backend-prod -f
|
||||
|
||||
# 后端运行时日志
|
||||
/opt/x-server-mobile/logs/app/
|
||||
```
|
||||
|
||||
#### 8.2 监控命令
|
||||
|
||||
```bash
|
||||
# 检查后端容器状态
|
||||
docker ps | grep x-server-backend-prod
|
||||
|
||||
# 检查后端健康
|
||||
curl http://127.0.0.1:8787/
|
||||
|
||||
# 检查数据库连接
|
||||
docker exec x-server-backend-prod php -r "var_dump(getenv('DB_HOST'));"
|
||||
|
||||
# 查看 PHP OPcache 状态
|
||||
# 需要在后端添加 OPcache 状态页面
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 第九步:安全加固
|
||||
|
||||
#### 9.1 防火墙配置
|
||||
|
||||
```bash
|
||||
# 只开放必要端口
|
||||
ufw allow 22 # SSH
|
||||
ufw allow 80 # HTTP
|
||||
ufw allow 443 # HTTPS
|
||||
ufw enable
|
||||
```
|
||||
|
||||
#### 9.2 PHP 安全配置
|
||||
|
||||
```ini
|
||||
# php-prod.ini
|
||||
expose_php = Off
|
||||
allow_url_fopen = Off
|
||||
allow_url_include = Off
|
||||
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
|
||||
```
|
||||
|
||||
#### 9.3 环境变量保护
|
||||
|
||||
- 不要将敏感信息提交到代码仓库
|
||||
- 使用 `.env` 文件或 Docker secrets 管理敏感信息
|
||||
- 定期轮换密码和密钥
|
||||
|
||||
---
|
||||
|
||||
### 第十步:回滚方案
|
||||
|
||||
#### 10.1 快速回滚
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# rollback.sh - 回滚脚本
|
||||
|
||||
BACKUP_DATE=$1 # 格式: 20240227_150000
|
||||
|
||||
if [ -z "$BACKUP_DATE" ]; then
|
||||
echo "请指定备份日期,格式: 20240227_150000"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🔄 回滚到 $BACKUP_DATE ..."
|
||||
|
||||
# 恢复前端
|
||||
cp -r /opt/x-server-mobile/backup/$BACKUP_DATE/frontend/* /opt/x-server-mobile/frontend/
|
||||
|
||||
# 恢复后端(可选)
|
||||
# cd /opt/x-server-mobile/backend
|
||||
# git checkout <previous-commit>
|
||||
# docker-compose -f docker-compose.prod.yml restart backend
|
||||
|
||||
# 重载 OpenResty
|
||||
openresty -s reload
|
||||
|
||||
echo "✅ 回滚完成"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 检查清单
|
||||
|
||||
部署前检查:
|
||||
|
||||
- [ ] 域名 DNS 已配置指向服务器 IP
|
||||
- [ ] SSL 证书已配置
|
||||
- [ ] MySQL 数据库已创建
|
||||
- [ ] Redis 可正常连接
|
||||
- [ ] 飞书应用回调地址已更新
|
||||
- [ ] 环境变量已正确配置
|
||||
- [ ] 防火墙规则已设置
|
||||
- [ ] 日志目录已创建
|
||||
|
||||
部署后验证:
|
||||
|
||||
- [ ] 前端页面可正常访问
|
||||
- [ ] API 接口返回正常
|
||||
- [ ] 飞书登录功能正常
|
||||
- [ ] 审批流程功能正常
|
||||
- [ ] 日志输出正常
|
||||
- [ ] 容器健康检查通过
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q1: 前端刷新 404
|
||||
|
||||
**原因**: OpenResty 配置没有正确处理 SPA 路由
|
||||
|
||||
**解决**: 确保 `try_files $uri $uri/ /index.html;` 配置正确
|
||||
|
||||
### Q2: API 请求跨域
|
||||
|
||||
**原因**: 前端和后端域名不同
|
||||
|
||||
**解决**: 在后端添加 CORS 头,或使用 OpenResty 代理统一域名
|
||||
|
||||
### Q3: 飞书回调失败
|
||||
|
||||
**原因**: 回调地址配置错误或 SSL 证书问题
|
||||
|
||||
**解决**:
|
||||
- 确认飞书后台配置的回调地址为 `https://xsm.hnxinyouhe.com/login/callback`
|
||||
- 确保服务器可公网访问
|
||||
- 检查 SSL 证书是否有效
|
||||
|
||||
### Q4: 容器无法连接数据库
|
||||
|
||||
**原因**: 容器网络不在同一个网络
|
||||
|
||||
**解决**: 确保后端容器和 MySQL/Redis 容器在同一个 Docker 网络(如 1panel-network)
|
||||
|
||||
---
|
||||
|
||||
## 联系方式
|
||||
|
||||
如有问题,请联系开发团队。
|
||||
Reference in New Issue
Block a user