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:
root
2026-02-28 11:42:51 +08:00
parent d37d82bc13
commit e3fa7e86f3
16 changed files with 741 additions and 0 deletions
+287
View File
@@ -0,0 +1,287 @@
# X-Server Mobile 部署检查清单
## 部署前检查
### 服务器环境
- [ ] 服务器已安装 1Panel 面板
- [ ] 已安装 OpenResty 并正常运行
- [ ] 已安装 MySQL 容器(1Panel 管理)
- [ ] 已安装 Redis 容器(1Panel 管理)
- [ ] Docker 网络配置正确(1panel-network 存在)
### 网络配置
- [ ] 域名 DNS 已解析到服务器 IP
- [ ] 服务器防火墙已开放 80、443 端口
- [ ] 服务器可从外网访问
### 数据库准备
- [ ] 创建生产数据库 `xserver`
- [ ] 创建专用数据库用户 `xserver`
- [ ] 授予用户权限
- [ ] 导入数据库结构和初始数据
### SSL 证书
- [ ] 安装 certbot: `apt-get install certbot`
- [ ] 获取证书: `certbot certonly --standalone -d xsm.hnxinyouhe.com`
- [ ] 验证证书路径正确
### 环境变量
- [ ] 复制 `.env.production.template` 为 `.env.production`
- [ ] 填写数据库配置
- [ ] 填写 Redis 配置
- [ ] 填写飞书配置
- [ ] 更新飞书回调地址为 `https://xsm.hnxinyouhe.com/login/callback`
### 目录结构
- [ ] 创建部署目录: `/opt/x-server-mobile`
- [ ] 创建子目录: frontend, backend, logs, backup
- [ ] 设置正确的目录权限
---
## 部署步骤
### 1. 准备服务器环境
```bash
# SSH 登录服务器
ssh root@your-server
# 创建目录结构
mkdir -p /opt/x-server-mobile/{frontend,backend,logs,backup}
mkdir -p /opt/x-server-mobile/logs/backend
mkdir -p /opt/x-server-mobile/logs/nginx
# 创建日志文件
touch /opt/x-server-mobile/logs/nginx_access.log
touch /opt/x-server-mobile/logs/nginx_error.log
```
### 2. 配置 OpenResty
```bash
# 复制配置文件到 OpenResty 配置目录
cp deploy/nginx/x-server-mobile-prod.conf /usr/local/openresty/nginx/conf/conf.d/x-server-mobile.conf
# 测试配置
openresty -t
# 如果测试通过,重载配置
openresty -s reload
```
### 3. 构建前端
```bash
# 在开发环境
cd /www/x-server-mobile/frontend
npm install
npm run build
# 验证构建产物
ls -la dist/
```
### 4. 部署
```bash
# 方式1: 使用部署脚本
./deploy.sh your-server-ip
# 方式2: 手动部署
# 上传前端
scp -r frontend/dist/* root@server:/opt/x-server-mobile/frontend/
# 上传后端
scp -r backend/ root@server:/opt/x-server-mobile/backend/
# 上传 docker-compose
scp docker-compose.prod.yml root@server:/opt/x-server-mobile/
```
### 5. 启动后端
```bash
# SSH 登录服务器
ssh root@server
# 进入部署目录
cd /opt/x-server-mobile
# 加载环境变量
source .env.production
# 启动容器
docker-compose -f docker-compose.prod.yml up -d
# 查看容器状态
docker ps | grep x-server
# 查看日志
docker logs -f x-server-backend-prod
```
---
## 部署后验证
### 前端验证
- [ ] 访问 `https://xsm.hnxinyouhe.com` 显示登录页面
- [ ] 页面样式加载正常
- [ ] 浏览器控制台无错误
### 后端验证
- [ ] 容器运行正常: `docker ps | grep x-server`
- [ ] 健康检查通过
- [ ] 日志无错误信息
### 功能验证
- [ ] 邮箱密码登录功能正常
- [ ] 飞书客户端内免登正常
- [ ] 飞书扫码登录正常
- [ ] 审批列表正常显示
- [ ] 出差申请功能正常
- [ ] 飞书卡片通知正常
### 飞书回调验证
- [ ] 飞书后台配置回调地址: `https://xsm.hnxinyouhe.com/login/callback`
- [ ] 点击飞书卡片"查看详情"跳转正确
- [ ] 快速审批按钮功能正常
---
## 监控配置
### 日志监控
```bash
# Nginx 访问日志
tail -f /opt/x-server-mobile/logs/nginx_access.log
# Nginx 错误日志
tail -f /opt/x-server-mobile/logs/nginx_error.log
# 后端容器日志
docker logs -f x-server-backend-prod
# 后端应用日志
tail -f /opt/x-server-mobile/logs/backend/*.log
```
### 性能监控
```bash
# 容器资源使用
docker stats x-server-backend-prod
# 磁盘使用
du -sh /opt/x-server-mobile/*
# 内存使用
free -h
```
### 数据库监控
```bash
# 检查 MySQL 连接
docker exec x-server-backend-prod php -r "
try {
new PDO('mysql:host=DB_HOST;dbname=xserver', 'xserver', 'password');
echo 'Database connection OK\n';
} catch (Exception \$e) {
echo 'Database connection FAILED: ' . \$e->getMessage() . '\n';
}
"
```
---
## 回滚准备
### 备份检查
```bash
# 检查备份目录
ls -la /opt/x-server-mobile/backup/
# 查看最新备份
ls -lt /opt/x-server-mobile/backup/ | head -5
```
### 回滚测试
```bash
# 测试回滚脚本
./rollback.sh <backup_name>
```
---
## 定期维护
### 每周
- [ ] 检查容器运行状态
- [ ] 检查日志错误
- [ ] 检查磁盘空间
### 每月
- [ ] 更新 SSL 证书(自动续期)
- [ ] 数据库备份
- [ ] 日志归档和清理
### 每季度
- [ ] 安全更新检查
- [ ] 性能优化评估
- [ ] 灾难恢复演练
---
## 应急处理
### 服务异常
```bash
# 查看容器状态
docker ps -a | grep x-server
# 重启后端容器
docker restart x-server-backend-prod
# 查看详细日志
docker logs --tail 100 x-server-backend-prod
```
### 数据库异常
```bash
# 检查 MySQL 容器
docker ps | grep mysql
# 进入 MySQL
docker exec -it <mysql-container> mysql -uxserver -p
# 检查连接数
SHOW PROCESSLIST;
```
### 网络异常
```bash
# 检查端口监听
netstat -tlnp | grep -E '80|443|8787'
# 检查防火墙
ufw status
# 测试外网访问
curl -I https://xsm.hnxinyouhe.com
```
---
## 联系信息
- 开发负责人: ___________
- 运维负责人: ___________
- 紧急联系电话: ___________
+254
View File
@@ -0,0 +1,254 @@
# uniservice-mobile.hnxinyouhe.com 线上部署说明
## 线上环境信息
| 项目 | 值 |
|------|-----|
| **域名** | uniservice-mobile.hnxinyouhe.com |
| **站点目录** | /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index |
| **项目目录** | /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server |
| **后端容器** | x-server-backend-prod (端口 8787) |
| **MySQL 容器** | 1Panel-mysql-XyxS |
| **Redis 容器** | 1Panel-redis-pxdb |
| **Docker 网络** | 1panel-network |
---
## 部署架构
| 组件 | 部署方式 |
|------|---------|
| **前端** | 本地构建 → 上传静态文件 |
| **后端** | Git 拉取 → Docker 重启 |
---
## 目录结构
```
/opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/
├── index.html # 前端入口
├── assets/ # 前端静态资源
└── server/ # 整个项目(Git 仓库)
├── backend/ # 后端代码
│ ├── app/
│ ├── config/
│ └── ...
├── deploy/ # 部署配置
│ ├── docker-compose.prod.yml
│ ├── .env.production
│ └── deploy.sh
├── frontend/ # 前端源码(不使用)
├── docs/ # 文档
└── logs/ # 日志
└── backend/
```
---
## 快速部署
### 前端部署(本地)
```bash
# 本地构建
cd /www/x-server-mobile/frontend
npm run build
# 上传静态文件
rsync -avz --delete \
frontend/dist/ \
root@45.153.130.80:/opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/
```
### 后端部署(服务器)
```bash
# 登录服务器
ssh root@45.153.130.80
cd /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server
# 拉取代码
git pull origin master
# 重启容器
docker-compose -f deploy/docker-compose.prod.yml down
docker-compose -f deploy/docker-compose.prod.yml up -d
```
或使用部署脚本:
```bash
ssh root@45.153.130.80
cd /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server
./deploy/deploy.sh
```
---
## 首次部署
### 1. 克隆后端代码
```bash
ssh root@45.153.130.80
cd /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index
# 克隆 master 分支
git clone <your-git-repository-url> server
cd server
git checkout master
```
### 2. 上传 Dockerfile
```bash
# 本地执行
scp backend/Dockerfile.prod root@45.153.130.80:/opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server/backend/
```
### 3. 配置环境变量
```bash
ssh root@45.153.130.80
vi /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server/deploy/.env.production
```
填写飞书配置:
```env
FEISHU_APP_ID=cli_axxxxxxxxxxxx
FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxx
FEISHU_ENCRYPT_KEY=xxxxxxxxxxxxxxxxxxxx
FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxxxxxx
```
### 4. 创建日志目录
```bash
ssh root@45.153.130.80
mkdir -p /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server/logs/backend
```
### 5. 上传部署脚本
```bash
# 本地执行
scp deploy/server-deploy.sh root@45.153.130.80:/opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server/deploy/deploy.sh
# 赋予执行权限
ssh root@45.153.130.80
chmod +x /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server/deploy/deploy.sh
```
### 6. 启动后端容器
```bash
ssh root@45.153.130.80
cd /opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/server
docker-compose -f deploy/docker-compose.prod.yml up -d
docker ps | grep x-server
```
### 7. 上传前端
```bash
cd /www/x-server-mobile/frontend
npm run build
rsync -avz --delete \
frontend/dist/ \
root@45.153.130.80:/opt/1panel/www/sites/uniservice-mobile.hnxinyouhe.com/index/
```
---
## 1Panel Nginx 配置
在 1Panel 面板(网站设置 → 配置文件)添加反向代理:
```nginx
# 后端 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;
}
# 飞书登录回调
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;
proxy_set_header Host $host;
}
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;
proxy_set_header Host $host;
}
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;
proxy_set_header Host $host;
}
# 飞书卡片回调
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;
proxy_set_header Host $host;
}
```
---
## 部署验证
```bash
# 检查前端
curl -I https://uniservice-mobile.hnxinyouhe.com
# 检查后端容器
ssh root@45.153.130.80
docker ps | grep x-server
docker logs -f x-server-backend-prod
```
---
## 常见问题
| 问题 | 解决方案 |
|------|---------|
| API 404 | 检查 Nginx 反向代理配置 |
| 容器启动失败 | 检查数据库/Redis 容器状态,查看日志 |
| 飞书登录失败 | 检查 `/login/*` 反向代理配置 |
| 静态资源 404 | 确认前端上传到正确目录 |
---
## 文件清单
需要上传到服务器的文件:
| 文件 | 目标位置 |
|------|---------|
| `backend/Dockerfile.prod` | `server/backend/` |
| `deploy/docker-compose.prod.yml` | `server/deploy/` |
| `deploy/.env.production` | `server/deploy/` |
| `deploy/server-deploy.sh` | `server/deploy/deploy.sh` |
+219
View File
@@ -0,0 +1,219 @@
# 开发环境反向代理配置指南
本指南用于配置开发环境的 OpenResty 和 frpc,以便将本地 API 暴露到公网调试飞书登录。
## 前提条件
- 已安装并运行 OpenResty
- 已安装并运行 frpc
- Docker 中运行的后端服务 (localhost:8787)
## 配置步骤
### 1. OpenResty 配置
在你的 OpenResty 配置目录中创建以下配置文件:
```nginx
# /usr/local/openresty/nginx/conf/conf.d/x-server-api.conf
server {
listen 8080; # 本地开发端口,避免与 80 端口冲突
server_name api.x-server.local;
# API 反向代理
location /api/ {
proxy_pass http://127.0.0.1:8787/api/;
proxy_http_version 1.1;
proxy_set_header Host $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;
# CORS 配置(飞书请求需要)
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,X-Tenant-Key';
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# 健康检查
location /health {
return 200 "OK\n";
add_header Content-Type text/plain;
}
}
```
重载配置:
```bash
sudo openresty -s reload
# 或
sudo systemctl reload openresty
```
### 2. frpc 配置
配置 frpc 将本地 OpenResty 服务暴露到公网:
```ini
# ~/.frpc.ini 或 /etc/frp/frpc.ini
[common]
server_addr = your-frp-server.com # 你的 frp 服务器地址
server_port = 7000
token = your-token
[x-server-api]
type = http
local_ip = 127.0.0.1
local_port = 8080 # OpenResty 监听端口
custom_domains = api-dev.x-server.your-domain.com # 开发环境域名
# 可选:启用加密和压缩
use_encryption = true
use_compression = true
```
启动 frpc:
```bash
frpc -c ~/.frpc.ini
```
### 3. 本地 hosts 配置
在本地开发时配置 hosts:
```bash
# /etc/hosts
127.0.0.1 api.x-server.local
```
### 4. 飞书应用配置
在飞书开放平台配置开发环境回调 URL:
```
https://api-dev.x-server.your-domain.com/api/v1/auth/feishu-login
```
## 验证配置
### 1. 本地测试
```bash
# 直接访问后端
curl http://localhost:8787/api/v1/user/info
# 通过 OpenResty 访问
curl http://localhost:8080/api/v1/user/info
# 通过本地域名访问
curl http://api.x-server.local/api/v1/user/info
```
### 2. 公网测试
```bash
# 通过 frps 域名访问
curl https://api-dev.x-server.your-domain.com/api/v1/user/info
```
### 3. 飞书调试
1. 在飞书开放平台创建测试应用
2. 配置回调 URL 为开发环境域名
3. 使用飞书 APP ID 和 APP SECRET 进行测试
4. 检查后端日志查看请求详情
## 开发与生产环境区分
### 开发环境(使用 frpc)
- 域名:`api-dev.x-server.your-domain.com`
- 使用 frpc 暴露本地服务
- CORS 允许所有来源
- 详细日志输出
### 生产环境(不使用 frpc)
- 域名:`api.x-server.com`
- 直接部署到服务器
- CORS 严格限制
- 日志级别调整
## 故障排查
### OpenResty 无法访问后端
1. 检查 Docker 容器是否运行:`docker ps`
2. 检查端口是否正确:`docker ps | grep 8787`
3. 检查网络连通性:`curl http://127.0.0.1:8787`
### frpc 连接失败
1. 检查 frp 服务器是否可访问
2. 检查 token 是否正确
3. 查看 frpc 日志:`frpc -c ~/.frpc.ini`
### 飞书回调失败
1. 检查域名 DNS 解析是否指向 frp 服务器
2. 检查 frp 服务器是否配置了域名白名单
3. 检查后端日志是否收到请求
4. 验证 CORS 配置是否正确
## 安全建议
1. **开发环境使用独立的域名和 token**
2. **定期更新 frp token**
3. **不要在代码中硬编码生产环境配置**
4. **使用环境变量管理敏感信息**
5. **生产环境部署前移除 frpc 配置**
## 常用命令
```bash
# 查看 Docker 容器日志
docker logs x-server-backend -f
# 重启后端服务
docker compose restart backend
# 重载 OpenResty 配置
sudo openresty -s reload
# 查看 frpc 状态
frpc status -c ~/.frpc.ini
# 测试 API 连通性
curl -v http://localhost:8787/api/v1/user/info
```
## 环境变量配置
创建 `.env.development` 文件用于开发环境:
```env
# 后端配置
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=x_server_mobile
DB_USERNAME=root
DB_PASSWORD=mysql_xEsdPa
# Redis 配置
REDIS_HOST=redis
REDIS_PORT=6379
# 飞书配置(开发环境)
FEISHU_APP_ID=cli_xxxxxxxxxxxxx
FEISHU_APP_SECRET=xxxxxxxxxxxxxxxxxxxx
FEISHU_ENCRYPT_KEY=xxxxxxxxxxxxxxxxxxxx
FEISHU_VERIFICATION_TOKEN=xxxxxxxxxxxxxxxxxxxx
# API 配置
API_BASE_URL=http://localhost:8787
PUBLIC_API_URL=https://api-dev.x-server.your-domain.com
```
生产环境使用 `.env.production` 文件,移除 frpc 相关配置。
+257
View File
@@ -0,0 +1,257 @@
# 环境配置说明
本文档说明开发环境和生产环境的区别,避免混淆。
---
## 一、环境对比
| 项目 | 开发环境 | 生产环境 |
|------|----------|----------|
| **Git 分支** | `feature/mzl-dev` | `master` |
| **服务器** | 本地 WSL2 | 45.153.130.80 |
| **域名** | `xsm.dev.hnxinyouhe.com` | `uniservice-mobile.hnxinyouhe.com` |
| **前端端口** | 5173 (Vite Dev) | 静态文件托管 |
| **后端端口** | 8787 (Webman) | 8787 (Webman) |
| **代理** | OpenResty 8080 + frpc 内网穿透 | OpenResty 80/443 |
| **数据库** | `1Panel-mysql-409s` | 生产 MySQL 容器 |
| **调试模式** | `APP_DEBUG=true` | `APP_DEBUG=false` |
| **日志级别** | debug | info |
---
## 二、域名使用说明
### 开发环境域名
```
xsm.dev.hnxinyouhe.com
```
- 用途:飞书登录回调调试
- 通过 frpc 内网穿透暴露到公网
- 只在开发时使用
### 生产环境域名
```
uniservice-mobile.hnxinyouhe.com
```
- 用途:正式生产环境
- 用户实际访问的域名
- 飞书开放平台配置的回调地址
---
## 三、飞书开放平台配置
### 生产环境配置(重要!)
飞书开放平台必须配置生产环境的回调地址:
| 配置项 | 值 |
|--------|-----|
| **重定向 URL** | `https://uniservice-mobile.hnxinyouhe.com/login/callback` |
| **可信域名** | `uniservice-mobile.hnxinyouhe.com` |
**注意**:开发环境使用 frpc 穿透,但飞书回调仍需要配置正式域名。开发时可以临时添加开发域名到白名单进行测试。
---
## 四、Git 工作流程
```
┌─────────────────────────────────────────────────────────────┐
│ 开发环境 (本地) │
│ feature/mzl-dev 分支 │
└───────────────────────────┬─────────────────────────────────┘
│ 开发、测试
▼
┌─────────────────────────────────────────────────────────────┐
│ 合并到 master │
│ git merge feature/mzl-dev │
└───────────────────────────┬─────────────────────────────────┘
│ 推送到远程
▼
┌─────────────────────────────────────────────────────────────┐
│ 生产服务器拉取 │
│ ssh root@45.153.130.80 │
│ git pull origin master │
└───────────────────────────┬─────────────────────────────────┘
│ 重新构建部署
▼
┌─────────────────────────────────────────────────────────────┐
│ 生产环境更新完成 │
└─────────────────────────────────────────────────────────────┘
```
### 日常开发命令
```bash
# 1. 开发环境:在 feature/mzl-dev 分支工作
git checkout feature/mzl-dev
git pull origin feature/mzl-dev
# ... 开发、提交 ...
git add .
git commit -m "feat: xxx"
git push origin feature/mzl-dev
# 2. 发布上线:合并到 master
git checkout master
git pull origin master
git merge feature/mzl-dev --no-edit
git push origin master
git checkout feature/mzl-dev # 切回开发分支
# 3. 生产服务器:拉取并部署
ssh root@45.153.130.80
cd /opt/x-server-mobile
git pull origin master
# 后端已在容器中,只需重启
docker restart x-server-backend
# 前端需重新构建
```
---
## 五、前端构建
### 开发环境
```bash
cd /www/x-server-mobile/frontend
npm run dev
# 访问: http://localhost:5173
```
### 生产环境
```bash
cd /www/x-server-mobile/frontend
npm run build --mode production
# 生成文件: frontend/dist/
# 上传到生产服务器
rsync -avz --delete frontend/dist/ root@45.153.130.80:/www/sites/uniservice-mobile.hnxinyouhe.com/index/
```
---
## 六、环境变量配置
### 开发环境 (.env)
```env
APP_ENV=local
APP_DEBUG=true
DB_HOST=127.0.0.1
DB_PASSWORD=mysql_xEsdPa
```
### 生产环境 (.env.production)
```env
APP_ENV=production
APP_DEBUG=false
DB_HOST=1Panel-mysql-prod-xxxx
DB_PASSWORD=strong_production_password
```
**注意**:生产环境密码和密钥不要提交到代码仓库!
---
## 七、常见操作错误
### ❌ 错误操作
1. 在 `master` 分支直接开发新功能
2. 在开发环境修改生产数据库
3. 用开发域名 `xsm.dev.hnxinyouhe.com` 配置飞书开放平台
4. 将生产环境 `.env.production` 提交到 git
5. 忘记合并到 master 就让生产服务器拉取
### ✅ 正确操作
1. 始终在 `feature/mzl-dev` 分支开发
2. 开发完成后合并到 `master`
3. 生产服务器只拉取 `master` 分支
4. 敏感配置使用环境变量,不提交到代码
5. 飞书开放平台配置生产环境域名
---
## 八、调试飞书登录
### 开发环境调试
```bash
# 1. 确保开发服务器运行
cd /www/x-server-mobile/frontend
npm run dev
# 2. 确保后端运行
docker logs x-server-backend -f
# 3. 确保内网穿透运行
frpc -c /www/x-server-mobile/frpc/frpc-dev.ini
# 4. 访问环境检测页
https://xsm.dev.hnxinyouhe.com/feishu-env-test?company=2
# 5. 访问登录页
https://xsm.dev.hnxinyouhe.com/login?company=2
```
### 生产环境测试
```bash
# 直接访问生产域名
https://uniservice-mobile.hnxinyouhe.com/login?company=2
# 查看生产后端日志
ssh root@45.153.130.80
docker logs x-server-backend -f
```
---
## 九、部署检查清单
上线前检查:
- [ ] 代码已合并到 `master` 分支
- [ ] 前端已执行 `npm run build --mode production`
- [ ] 生产服务器已拉取最新代码 (`git pull origin master`)
- [ ] 后端容器已重启 (`docker restart x-server-backend`)
- [ ] 前端静态文件已上传到生产服务器
- [ ] 飞书开放平台配置的是生产环境域名
- [ ] 环境变量配置正确(数据库、Redis、密钥等)
---
## 十、快速参考
### 环境判断
```typescript
// 前端判断开发/生产环境
const isDev = import.meta.env.DEV
const isProd = import.meta.env.PROD
// 后端判断(PHP)
$appEnv = config('app.env'); // local, production
$isDebug = config('app.debug'); // true, false
```
### API 地址
```typescript
// 开发环境:通过代理访问
const API_BASE = '/api/v1'
// 生产环境:同样通过代理访问(OpenResty)
const API_BASE = '/api/v1'
```
### 回调地址
```typescript
// 开发环境(调试用)
const CALLBACK_URL = 'https://xsm.dev.hnxinyouhe.com/login/callback'
// 生产环境(正式)
const CALLBACK_URL = 'https://uniservice-mobile.hnxinyouhe.com/login/callback'
```
---
**最后更新**: 2026-02-28
+321
View File
@@ -0,0 +1,321 @@
# Git 工作流程
## 分支说明
| 分支 | 用途 | 部署环境 |
|------|------|---------|
| `master` | 生产分支 | 线上生产环境 (45.153.130.80) |
| `develop` | 开发集成分支 | 测试/预发布环境 |
| `feature/*` | 个人功能分支 | 本地开发环境 |
## 分支结构
```
master (生产)
↑
发布合并
↑
develop (开发)
↑
功能合并
↑
┌──────────────┬────┴────┬──────────────┐
↓ ↓ ↓ ↓
feature/xxx-1 feature/xxx-2 feature/xxx-3 feature/xxx-4
(个人A) (个人B) (个人A) (个人B)
```
---
## 一、工作流程
### 1.1 开发新功能
**从 develop 创建个人功能分支:**
```bash
# 确保本地 develop 是最新的
git checkout develop
git pull origin develop
# 创建个人功能分支(命名规范:feature/功能名 或 feature/功能名-姓名首字母)
git checkout -b feature/user-login
# 或带姓名标识
git checkout -b feature/user-login-mzl
```
**在功能分支上开发:**
```bash
# 开发、提交
git add .
git commit -m "feat: add user login"
git push origin feature/user-login
# 继续开发...
git add .
git commit -m "fix: correct login error handling"
git push origin feature/user-login
```
### 1.2 功能开发完成
**合并到 develop 进行团队测试:**
```bash
# 1. 切换到 develop 并更新
git checkout develop
git pull origin develop
# 2. 合并功能分支(使用 --no-ff 保留合并历史)
git merge --no-ff feature/user-login -m "Merge feature/user-login into develop"
# 3. 推送到远程
git push origin develop
# 4. (可选)删除已合并的功能分支
git branch -d feature/user-login
git push origin --delete feature/user-login
```
### 1.3 发布到生产
**从 develop 合并到 master:**
```bash
# 1. 切换到 master 并更新
git checkout master
git pull origin master
# 2. 合并 develop(使用 --no-ff 保留合并历史)
git merge --no-ff develop -m "Release: merge develop into master"
# 3. 添加版本标签(可选)
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
# 4. 推送到远程
git push origin master
```
### 1.4 生产服务器部署
```bash
ssh root@45.153.130.80
cd /opt/x-server-mobile
git pull origin master
docker restart x-server-backend
# 或
docker-compose -f docker-compose.prod.yml down
docker-compose -f docker-compose.prod.yml up -d
```
---
## 二、分支命名规范
| 分支类型 | 命名格式 | 示例 |
|---------|---------|------|
| 功能分支 | `feature/功能名` 或 `feature/功能名-姓名` | `feature/user-login`, `feature/user-login-mzl` |
| 修复分支 | `fix/问题描述` 或 `fix/问题描述-姓名` | `fix/login-error`, `fix/login-error-mzl` |
| 热修复分支 | `hotfix/问题描述` | `hotfix/security-fix` |
---
## 三、前端部署
```bash
# 1. 切换到 master
git checkout master
git pull origin master
# 2. 构建前端
cd frontend
npm run build --mode production
# 3. 上传到服务器
rsync -avz --delete frontend/dist/ root@45.153.130.80:/www/sites/uniservice-mobile.hnxinyouhe.com/index/
```
---
## 四、提交信息规范
| 类型 | 说明 | 示例 |
|------|------|------|
| `feat` | 新功能 | `feat: add user login` |
| `fix` | 修复bug | `fix: correct i18n loading` |
| `docs` | 文档变更 | `docs: update deployment guide` |
| `style` | 代码格式 | `style: format code` |
| `refactor` | 重构 | `refactor: simplify auth logic` |
| `test` | 测试相关 | `test: add login test` |
| `chore` | 构建/工具 | `chore: update dependencies` |
**完整格式:**
```
<type>(<scope>): <subject>
<body>
<footer>
```
**示例:**
```
feat(login): add feishu auto-login support
- Add H5 JSSDK integration
- Implement tt.requestAuthCode for silent login
- Add token auto-refresh on 401
Closes #123
```
---
## 五、快速发布脚本
### 5.1 功能合并到 develop
```bash
# 添加到 ~/.bashrc 或 ~/.zshrc
git-finish() {
local branch=$(git branch --show-current)
if [[ $branch != feature/* ]]; then
echo "❌ 当前不在 feature 分支上"
return 1
fi
echo "=== 合并 $branch 到 develop ==="
git checkout develop && \
git pull origin develop && \
git merge --no-ff $branch -m "Merge $branch into develop" && \
git push origin develop && \
echo "✅ 完成,可删除功能分支: git branch -d $branch"
}
```
### 5.2 发布到 master
```bash
# 添加到 ~/.bashrc 或 ~/.zshrc
git-release() {
echo "=== 发布 develop 到 master ==="
git checkout master && \
git pull origin master && \
git merge --no-ff develop -m "Release: merge develop into master" && \
git push origin master && \
git checkout develop && \
echo "✅ 发布完成,请部署生产环境"
}
```
---
## 六、协作场景
### 6.1 多人同时开发
```
时间线:
┌─────────────────────────────────────────────────────────────┐
│ A 开发 feature/login │
│ B 开发 feature/dashboard │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ A 完成,合并 feature/login 到 develop │
│ B 继续开发 feature/dashboard │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ B 完成,合并 feature/dashboard 到 develop │
│ (此时 develop 包含 A 和 B 的更改) │
└───────────────────────────┬─────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 在 develop 上测试通过后,合并到 master 发布 │
└─────────────────────────────────────────────────────────────┘
```
### 6.2 处理冲突
```bash
# 合并时遇到冲突
git checkout develop
git merge feature/login
# Git 提示冲突
# Auto-merging src/login.tsx
# CONFLICT (content): Merge conflict in src/login.tsx
# 手动解决冲突后
git add src/login.tsx
git commit -m "Merge feature/login into develop (resolved conflicts)"
git push origin develop
```
---
## 七、远程仓库
- **仓库地址**:http://219.157.255.213:25311/xinyouhe/x-server-mobile.git
- **生产分支**:`master`
- **开发分支**:`develop`
- **个人分支**:`feature/*`
---
## 八、最佳实践
### ✅ 推荐做法
1. **保持分支简短** - 功能分支完成后及时合并并删除
2. **频繁提交** - 小步提交,便于代码审查和回滚
3. **写好提交信息** - 清晰描述做了什么
4. **推送前先拉取** - 避免不必要的冲突
5. **代码审查** - 合并前让团队成员审查代码
### ❌ 避免做法
1. **直接在 master/develop 上开发** - 始终使用功能分支
2. **长时间不合并** - 功能分支会越来越难合并
3. **提交敏感信息** - 密钥、配置等不要提交
4. **强制推送 master/develop** - 可能丢失他人代码
---
## 九、常用命令速查
```bash
# 查看分支状态
git status
git branch -vv
# 创建功能分支
git checkout develop && git pull
git checkout -b feature/xxx
# 合并功能分支
git checkout develop
git merge --no-ff feature/xxx
# 发布到生产
git checkout master
git merge --no-ff develop
# 删除已合并分支
git branch -d feature/xxx
git push origin --delete feature/xxx
# 查看差异
git diff develop master
git log --oneline --graph --all
```
---
**最后更新**: 2026-02-28
+287
View File
@@ -0,0 +1,287 @@
# X-Server Mobile 快速部署指南
## 一、服务器准备
### 1.1 安装必要软件
```bash
# 更新系统
apt-get update && apt-get upgrade -y
# 安装 certbot(SSL 证书)
apt-get install certbot -y
# 安装 rsync(文件同步)
apt-get install rsync -y
```
### 1.2 创建部署目录
```bash
mkdir -p /opt/x-server-mobile/{frontend,backend,logs,backup}
mkdir -p /opt/x-server-mobile/logs/{backend,nginx}
```
### 1.3 获取 SSL 证书
```bash
# 停止 OpenResty(如果占用 80 端口)
systemctl stop openresty
# 获取证书
certbot certonly --standalone -d xsm.hnxinyouhe.com
# 重新启动 OpenResty
systemctl start openresty
```
### 1.4 准备数据库
```bash
# 创建数据库用户
docker exec -it <mysql-container> mysql -uroot -p
# 在 MySQL 中执行:
CREATE USER 'xserver'@'%' IDENTIFIED BY 'your_strong_password';
GRANT ALL PRIVILEGES ON xserver.* TO 'xserver'@'%';
FLUSH PRIVILEGES;
# 导入数据库(如果有备份)
docker exec -i <mysql-container> mysql -uxserver -pyour_password xserver < backup.sql
```
---
## 二、配置文件准备
### 2.1 环境变量
```bash
# 在项目根目录
cp deploy/.env.production.template .env.production
# 编辑填写实际配置
vi .env.production
```
### 2.2 更新 docker-compose.prod.yml
```yaml
# 修改以下配置为实际值:
- DB_HOST=1Panel-mysql-xxxx # 实际 MySQL 容器名
- DB_PASSWORD=your_password # 实际密码
- REDIS_HOST=1Panel-redis-xxxx # 实际 Redis 容器名
- REDIS_PASSWORD=your_redis_password # 实际 Redis 密码
```
---
## 三、部署
### 3.1 方式一:使用部署脚本(推荐)
```bash
# 1. 构建前端
cd frontend
npm install
npm run build
cd ..
# 2. 执行部署脚本
./scripts/deploy.sh your-server-ip
# 脚本会自动完成:
# - 备份当前版本
# - 上传前端和后端
# - 重启容器
# - 重载 OpenResty
```
### 3.2 方式二:手动部署
```bash
# 1. 构建前端
cd frontend && npm run build && cd ..
# 2. 上传前端
rsync -avz --delete frontend/dist/ root@server:/opt/x-server-mobile/frontend/
# 3. 上传后端
rsync -avz --exclude='vendor' --exclude='runtime' backend/ root@server:/opt/x-server-mobile/backend/
# 4. 上传配置文件
scp deploy/docker-compose.prod.yml root@server:/opt/x-server-mobile/
scp deploy/nginx/x-server-mobile-prod.conf root@server:/tmp/
# 5. 登录服务器配置 OpenResty
ssh root@server
cp /tmp/x-server-mobile-prod.conf /usr/local/openresty/nginx/conf/conf.d/x-server-mobile.conf
openresty -t && openresty -s reload
# 6. 启动后端容器
cd /opt/x-server-mobile
docker-compose -f docker-compose.prod.yml up -d
```
---
## 四、验证部署
### 4.1 检查容器状态
```bash
docker ps | grep x-server
docker logs -f x-server-backend-prod
```
### 4.2 检查服务
```bash
# 检查前端
curl -I https://xsm.hnxinyouhe.com
# 检查 API
curl https://xsm.hnxinyouhe.com/api/v1/user/info \
-H "Authorization: Bearer YOUR_TOKEN"
```
### 4.3 功能测试
- [ ] 登录页面正常访问
- [ ] 邮箱密码登录成功
- [ ] 飞书免登成功
- [ ] 审批列表正常显示
- [ ] 飞书卡片通知正常
---
## 五、常见问题
### Q1: 容器无法启动
```bash
# 查看详细日志
docker logs x-server-backend-prod
# 检查网络
docker network ls | grep 1panel
docker network inspect 1panel-network
# 检查环境变量
docker exec x-server-backend-prod env | grep DB_
```
### Q2: API 返回 500
```bash
# 查看后端日志
docker logs x-server-backend-prod --tail 50
# 检查数据库连接
docker exec x-server-backend-prod php -r "
var_dump(getenv('DB_HOST'));
var_dump(getenv('DB_DATABASE'));
"
# 进入容器调试
docker exec -it x-server-backend-prod bash
```
### Q3: SSL 证书问题
```bash
# 检查证书路径
ls -la /etc/letsencrypt/live/xsm.hnxinyouhe.com/
# 测试证书
openssl s_client -connect xsm.hnxinyouhe.com:443 -servername xsm.hnxinyouhe.com
# 手动续期
certbot renew --force-renewal
```
### Q4: 前端刷新 404
检查 OpenResty 配置中的 `try_files` 指令:
```nginx
location / {
root /opt/x-server-mobile/frontend;
try_files $uri $uri/ /index.html; # 确保有这行
}
```
---
## 六、回滚
```bash
# 查看可用备份
ssh root@server "ls -la /opt/x-server-mobile/backup/"
# 执行回滚
./scripts/rollback.sh 20240227_150000
```
---
## 七、监控命令
```bash
# 实时日志
docker logs -f x-server-backend-prod
# 容器资源
docker stats x-server-backend-prod
# Nginx 访问日志
tail -f /opt/x-server-mobile/logs/nginx_access.log
# Nginx 错误日志
tail -f /opt/x-server-mobile/logs/nginx_error.log
```
---
## 八、更新部署
当代码有更新时:
```bash
# 1. 拉取最新代码
git pull
# 2. 构建前端
cd frontend && npm run build && cd ..
# 3. 部署
./scripts/deploy.sh your-server-ip
```
---
## 配置检查清单
部署前确认:
```bash
# 1. 检查环境变量
cat .env.production | grep -v "^#" | grep -v "^$"
# 2. 检查构建产物
ls -la frontend/dist/
# 3. 检查 OpenResty 配置
cat deploy/nginx/x-server-mobile-prod.conf | grep server_name
# 4. 测试 SSH 连接
ssh root@your-server "echo 'SSH OK'"
```
---
## 联系支持
如有问题,请参考完整文档:
- `DEPLOYMENT.md` - 完整部署文档
- `DEPLOYMENT_CHECKLIST.md` - 部署检查清单
- `PROJECT_ISSUES.md` - 问题汇总
+142
View File
@@ -0,0 +1,142 @@
# 反向代理配置指南
本指南用于配置 OpenResty 和 frpc 以将 API 暴露到公网,便于调试飞书登录。
## 环境要求
- 已安装 OpenResty 或 Nginx
- 已安装 frpc
- 拥有可用的 frp 服务器
- 拥有可配置的域名
## 安装步骤
### 1. 安装 OpenResty (Ubuntu/Debian)
```bash
# 导入 GPG 密钥
wget -qO - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
# 添加 OpenResty 仓库
sudo apt-get -y install -y wget gnupg ca-certificates
wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add -
echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list
# 安装 OpenResty
sudo apt-get update
sudo apt-get install -y openresty
# 启动服务
sudo systemctl start openresty
sudo systemctl enable openresty
```
### 2. 配置 OpenResty
将 `nginx/x-server-api.conf` 复制到 OpenResty 配置目录:
```bash
sudo cp nginx/x-server-api.conf /usr/local/openresty/nginx/conf/conf.d/
sudo mkdir -p /usr/local/openresty/nginx/logs
sudo openresty -s reload
```
### 3. 安装 frpc
```bash
# 下载 frpc(根据你的系统选择版本)
wget https://github.com/fatedier/frp/releases/download/v0.52.3/frp_0.52.3_linux_amd64.tar.gz
# 解压
tar xzf frp_0.52.3_linux_amd64.tar.gz
cd frp_0.52.3_linux_amd64
# 复制到系统路径
sudo cp frpc /usr/local/bin/
sudo chmod +x /usr/local/bin/frpc
```
### 4. 配置 frpc
编辑 `frpc/frpc.ini`,填入你的 frp 服务器信息:
```ini
[common]
server_addr = your-frp-server.com # 你的 frp 服务器地址
server_port = 7000 # frp 服务器端口
token = your-frp-token # 认证令牌
[x-server-api]
type = http
local_ip = 127.0.0.1
local_port = 8787
custom_domains = api.x-server.your-domain.com # 你的公网域名
```
### 5. 启动 frpc
```bash
# 前台运行(测试)
frpc -c frpc/frpc.ini
# 后台运行(生产)
nohup frpc -c frpc/frpc.ini > /dev/null 2>&1 &
```
### 6. 配置 DNS
将你的域名 `api.x-server.your-domain.com` 的 A 记录指向你的 frp 服务器 IP。
### 7. 配置飞书应用
在飞书开放平台配置回调 URL:
```
https://api.x-server.your-domain.com/api/v1/auth/feishu-login
```
## 验证配置
### 测试本地 API
```bash
curl http://localhost:8787/api/v1/user/info
```
### 测试反向代理
```bash
curl http://api.x-server.local/api/v1/user/info
```
### 测试公网访问
```bash
curl https://api.x-server.your-domain.com/api/v1/user/info
```
## 常见问题
### frpc 连接失败
1. 检查 frp 服务器是否在线
2. 检查 token 是否正确
3. 检查端口是否被防火墙阻止
### 域名无法访问
1. 检查 DNS 解析是否生效
2. 检查 frp 服务器是否配置了该域名
3. 检查 frpc 日志
### CORS 错误
如果前端调用 API 时出现 CORS 错误,检查 nginx 配置中的 CORS 头部设置。
## 安全建议
1. **生产环境务必使用 HTTPS**
2. 配置 IP 白名单限制访问
3. 使用强密码和 token
4. 定期更新 frp 和 OpenResty 版本
5. 配置防火墙规则
+598
View File
@@ -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)
---
## 联系方式
如有问题,请联系开发团队。