提示信息
# 同伴后端 — 服务器部署指南
> 适用:PHP 8.4 · Slim 4 · PostgreSQL · Redis
>
> 本文档描述从 git 拉取代码后,在服务器上完成部署所需的全部步骤。
---
## 目录
1. [环境要求](#1-环境要求)
2. [安装 PHP 依赖](#2-安装-php-依赖)
3. [配置环境变量 .env](#3-配置环境变量-env)
4. [初始化数据库](#4-初始化数据库)
5. [目录权限](#5-目录权限)
6. [Web 服务器配置](#6-web-服务器配置)
7. [验证部署](#7-验证部署)
8. [(可选)生成 API 文档](#8-可选生成-api-文档)
9. [生产环境加固](#9-生产环境加固)
10. [常见问题](#10-常见问题)
---
## 1. 环境要求
在开始之前,请确认服务器已安装以下软件:
| 软件 | 最低版本 | 说明 |
|------|---------|------|
| PHP | **8.4** | 需开启扩展:`pdo_pgsql`, `redis`, `mbstring`, `json`, `openssl`, `fileinfo` |
| Composer | 2.x | PHP 包管理器 |
| PostgreSQL | 14+ (推荐 18) | 主数据库 |
| Redis | 6+ | 缓存 / JWT 黑名单 / 频率限制 |
| Nginx / Apache | 任意现代版本 | Web 服务器(推荐 Nginx) |
检查 PHP 版本:
```bash
php -v
# 确认输出包含 PHP 8.4.x
```
检查必要 PHP 扩展:
```bash
php -m | grep -E "pdo_pgsql|redis|mbstring|json|openssl|fileinfo"
```
---
## 2. 安装 PHP 依赖
> **注意**:`vendor/` 目录已在 `.gitignore` 中,拉取代码后不存在,必须执行此步骤。
```bash
cd /path/to/tongban-backend
# 生产环境(不安装 dev 依赖,优化自动加载)
composer install --no-dev --optimize-autoloader
# 开发/测试环境
composer install
```
---
## 3. 配置环境变量 .env
`.env` 文件不在 git 仓库中,需手动从模板创建:
```bash
cp .env.example .env
```
然后逐项编辑 `.env`,以下是各模块的配置说明:
### 3.1 应用基础
```ini
APP_ENV=production # 生产环境改为 production
APP_DEBUG=false # 生产环境必须为 false,否则会暴露错误详情
APP_KEY= # 用于 Illuminate Encryption,必须填写
```
生成 `APP_KEY`(32字节随机串 base64 编码):
```bash
php -r "echo 'base64:' . base64_encode(random_bytes(32)) . PHP_EOL;"
```
### 3.2 数据库(PostgreSQL)
```ini
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=tongban # 数据库名,需提前在 PostgreSQL 中创建
DB_USERNAME=postgres
DB_PASSWORD=your_password
DB_SSLMODE=require # 生产环境改为 require
```
### 3.3 Redis
```ini
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD= # 有密码就填,无密码留空
REDIS_DB=0
REDIS_PREFIX=companion: # 多项目共用 Redis 时建议修改前缀
```
### 3.4 JWT 鉴权
```ini
JWT_SECRET= # 至少 32 位随机字符串,绝对不能泄露
JWT_EXPIRE=7200 # access token 有效期(秒),默认 2 小时
JWT_REFRESH_EXPIRE=2592000 # refresh token 有效期(秒),默认 30 天
```
生成 JWT_SECRET:
```bash
php -r "echo bin2hex(random_bytes(32)) . PHP_EOL;"
```
### 3.5 阿里云 OSS(图片/音频存储)
```ini
OSS_ACCESS_KEY_ID= # 阿里云 RAM 子账号 AccessKey
OSS_ACCESS_KEY_SECRET=
OSS_ENDPOINT=oss-cn-hangzhou.aliyuncs.com
OSS_BUCKET=tongban-signal # 信号媒体文件 bucket
OSS_BUCKET_DEV=tongban-signal
OSS_BUCKET_AVATAR= # 头像 bucket(通常独立)
OSS_ENDPOINT_AVATAR=oss-cn-shanghai.aliyuncs.com
OSS_DOMAIN=cdn.yourdomain.com # 信号 CDN 域名
OSS_DOMAIN_AVATAR=avatar.yourdomain.com # 头像 CDN 域名
OSS_STS_ROLE_ARN= # STS 授权角色 ARN,客户端直传使用
```
### 3.6 OpenIM(即时通讯)
```ini
OPENIM_API_URL=https://im-api.yourdomain.com
OPENIM_SECRET= # 与 OpenIM 服务端配置保持一致
OPENIM_ADMIN_UID=imAdmin
OPENIM_UID_PREFIX=tb_ # IM 用户 ID 前缀
```
### 3.7 应用签名(客户端请求签名)
```ini
APP_KEY_IOS_DEV=tongban_ios_dev
APP_KEY_ANDROID_DEV=tongban_android_dev
APP_SECRET_DEV= # 开发环境签名密钥
APP_KEY_IOS_PROD=tongban_ios_prod
APP_KEY_ANDROID_PROD=tongban_android_prod
APP_SECRET_PROD= # 生产环境签名密钥
```
### 3.8 支付(支付宝 / 微信)
```ini
# 支付宝(App 端支付)
ALIPAY_APPID=
ALIPAY_PUBLIC_KEY= # 支付宝平台公钥
ALIPAY_PRIVATE_KEY= # 应用私钥
# 微信支付
WECHAT_APPID=
WECHAT_MCH_ID=
WECHAT_MCH_V3_KEY=
WECHAT_CERT_PUBLIC= # 商户证书公钥内容
WECHAT_CERT_PRIVATE= # 商户证书私钥内容
```
### 3.9 阿里云短信
```ini
ALIYUN_SMS_ACCESS_KEY_ID=
ALIYUN_SMS_ACCESS_KEY_SECRET=
ALIYUN_SMS_SIGN_NAME= # 短信签名名称
ALIYUN_SMS_TEMPLATE_LOGIN= # 登录验证码模板 ID
ALIYUN_SMS_TEMPLATE_RESET= # 重置密码模板 ID
ALIYUN_SMS_TEMPLATE_BIND= # 绑定手机模板 ID
```
### 3.10 其他
```ini
CDN_DOMAIN= # 阿里云 CDN 域名(含协议和结尾斜杠)
CDN_AUTH_SECRET= # CDN 鉴权 key
ADMIN_TOKEN= # 后台管理接口认证 token
ADMIN_CORS_ORIGIN= # 后台允许的跨域来源,多个用逗号分隔
LOG_LEVEL=info # 生产建议 info;调试时用 debug
PRIVACY_POLICY_VERSION=1 # 隐私政策版本基准
```
---
## 4. 初始化数据库
### 4.1 创建数据库
```bash
# 进入 PostgreSQL
psql -U postgres
# 创建数据库
CREATE DATABASE tongban;
\q
```
### 4.2 按顺序执行 Schema 文件
> ⚠️ **必须先执行 `00_types.sql`**,它定义了其他表所依赖的自定义枚举类型。
```bash
cd /path/to/tongban-backend
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/00_types.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/01_users.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/02_user_devices.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/03_user_blocks.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/04_user_login_logs.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/05_user_risk_logs.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/06_user_forbidden.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/07_user_sign.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/08_user_module_cursors.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/09_user_verifications.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/10_user_cancellations.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/11_reports.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/12_signals.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/13_signal_receives.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/14_signal_replies.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/15_signal_low_quality_feedbacks.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/16_im_stranger_limit.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/17_im_daily_greet.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/18_im_day_stats.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/19_im_upload_logs.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/20_im_violation_logs.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/21_app_versions.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/22_orders.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/23_sms_logs.sql
PGPASSWORD=your_password psql -U postgres -d tongban -f database/schema/24_app_documents.sql
```
或者用一条命令批量执行(按文件名数字顺序):
```bash
ls database/schema/*.sql | sort -V | xargs -I{} sh -c \
'echo "=== Running {} ===" && PGPASSWORD=your_password psql -U postgres -d tongban -f {}'
```
### 4.3(可选)填充基础数据
```bash
# 应用文档(隐私政策、用户协议等)
PGPASSWORD=your_password psql -U postgres -d tongban -f database/seed_documents.sql
# 应用版本数据
PGPASSWORD=your_password psql -U postgres -d tongban -f database/mock_app_versions.sql
```
---
## 5. 目录权限
确保 Web 进程(通常是 `www-data` 或 `nginx`)有读写权限:
```bash
# 创建必要目录(如果不存在)
mkdir -p logs storage
# 设置权限
chmod -R 755 /path/to/tongban-backend
chmod -R 777 logs storage
# 或者指定用户
chown -R www-data:www-data logs storage
```
---
## 6. Web 服务器配置
### Nginx 配置示例
```nginx
server {
listen 80;
server_name api.yourdomain.com;
root /path/to/tongban-backend/public;
index index.php;
# 将所有请求转发到 index.php(Slim 4 路由)
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.4-fpm.sock; # 根据实际路径调整
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 禁止访问 .env 等敏感文件
location ~ /\. {
deny all;
}
# 日志
access_log /var/log/nginx/tongban-access.log;
error_log /var/log/nginx/tongban-error.log;
}
```
> 生产环境加 HTTPS(Let's Encrypt / 自有证书),并在 Nginx 中开启 SSL。
### Apache 配置示例(.htaccess)
项目 `public/` 目录下需要有 `.htaccess`:
```apache
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]
```
---
## 7. 验证部署
### 7.1 检查服务是否响应
```bash
curl -X GET https://api.yourdomain.com/v1/health
# 期望返回:{"code":0,"msg":"success","data":null}
# 或 curl http://127.0.0.1/v1/health(本地测试)
```
### 7.2 检查数据库连接
```bash
php -r "
require 'vendor/autoload.php';
\$pdo = new PDO('pgsql:host=127.0.0.1;dbname=tongban', 'postgres', 'your_password');
echo 'DB OK: ' . \$pdo->query('SELECT version()')->fetchColumn() . PHP_EOL;
"
```
### 7.3 检查 Redis 连接
```bash
redis-cli ping
# 返回 PONG 则正常
```
### 7.4 访问 API 文档
浏览器打开:`https://api.yourdomain.com/docs/api`
---
## 8. (可选)生成 API 文档
```bash
# 方式一:Composer 脚本
composer run-script gen-doc
# 输出到 docs/openapi.json
# 方式二:访问接口动态刷新(需认证)
curl https://api.yourdomain.com/docs/refresh
```
---
## 9. 生产环境加固
| 项目 | 操作 |
|------|------|
| `APP_DEBUG=false` | 禁止错误详情对外暴露 |
| `APP_ENV=production` | 开启生产模式 |
| `DB_SSLMODE=require` | 强制 PostgreSQL SSL 连接 |
| `LOG_LEVEL=info` | 减少日志量,避免敏感信息泄露 |
| Nginx 屏蔽敏感路径 | 禁止访问 `.env`、`.git`、`composer.json` 等 |
| HTTPS | 全站强制 HTTPS,防止 JWT / 签名中间人攻击 |
| Redis 密码 | 设置 `requirepass`,`REDIS_PASSWORD` 同步填写 |
| 文件权限 | `logs/`、`storage/` 仅 Web 进程可写,不对外暴露 |
| `ADMIN_TOKEN` | 使用长随机串,后台接口仅限内网 IP 访问 |
---
## 10. 常见问题
### Q: `vendor/` 不存在,报 autoload 错误
**A**: 执行 `composer install --no-dev --optimize-autoloader`。
### Q: 数据库连接失败
**A**: 检查 `.env` 中 `DB_*` 配置,确认 PostgreSQL 已启动且账号有连接权限:
```bash
psql -U postgres -h 127.0.0.1 -d tongban
```
### Q: Redis 连接失败
**A**: 确认 Redis 已启动:`systemctl status redis` / `brew services list | grep redis`。
### Q: `00_types.sql` 报错"类型已存在"
**A**: 说明之前已执行过,可忽略此错误,或在 SQL 前加 `DROP TYPE IF EXISTS ... CASCADE;`。
### Q: JWT Token 校验失败
**A**: 确认 `.env` 中 `JWT_SECRET` 与客户端约定一致,且长度 ≥ 32 位。
### Q: OSS 上传失败
**A**: 检查 `OSS_ACCESS_KEY_ID` / `OSS_ACCESS_KEY_SECRET`,确认 RAM 子账号对 bucket 有 `oss:PutObject` 权限。
### Q: 生成 API 文档时 PHP 报内存溢出
**A**: 增大 PHP 内存限制:
```bash
php -d memory_limit=512M -r "..."
# 或修改 php.ini: memory_limit = 512M
```
---
## 部署检查清单
```
[ ] PHP 8.4 已安装,pdo_pgsql / redis 扩展已启用
[ ] Composer 已安装,vendor/ 已生成
[ ] .env 已从 .env.example 复制并填写完毕
[ ] APP_KEY 已生成并填写
[ ] JWT_SECRET 已生成并填写(≥32位)
[ ] PostgreSQL 数据库 tongban 已创建
[ ] database/schema/*.sql 按顺序执行完毕(00 → 24)
[ ] logs/ 和 storage/ 目录存在且有写权限
[ ] Nginx/Apache 已配置,指向 public/index.php
[ ] curl /v1/health 返回正常
[ ] API 文档页面可访问
[ ] 生产环境:APP_DEBUG=false,DB_SSLMODE=require,LOG_LEVEL=info
```