Files
rxthinkcmf-wiki/RXThinkCMF_ThinkPhp8_EleVue/zh/deploy/backend.md
T
2026-10-10 12:20:37 +08:00

424 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 11.4 后端部署
:::tip 概述
本节详细说明后端服务的部署配置,包括 Nginx、Apache、PHP 生产优化、定时任务配置,以及多数据库部署注意事项。
:::
## Nginx 配置
```nginx
# =============================================================================
# Nginx 站点配置 — ThinkPHP 8 后端 API
# =============================================================================
# 用途:生产环境 Nginx 反向代理,将 HTTP 请求转发给 PHP-FPM 处理
# 配置路径:/etc/nginx/sites-available/rxthinkcmf
# 启用方式:ln -s /etc/nginx/sites-available/rxthinkcmf /etc/nginx/sites-enabled/
# =============================================================================
server {
# 监听 80 端口(HTTP),生产环境建议改为 443(HTTPS)
listen 80;
# 绑定域名(替换为实际域名)
server_name api.example.com;
# 网站根目录指向 ThinkPHP 入口目录
# 注意:必须指向 public/ 子目录,而非项目根目录
root /www/api/public;
index index.php;
# -----------------------------------------------------------------
# URL 重写(ThinkPHP 必需)
# -----------------------------------------------------------------
# 将所有非真实文件请求转发到 index.php,由 ThinkPHP 路由解析
# 例:GET /api/user/page → /index.php?s=/api/user/page
location / {
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
}
}
# -----------------------------------------------------------------
# PHP-FPM 处理
# -----------------------------------------------------------------
# 所有 .php 请求通过 FastCGI 协议转发给 PHP-FPM 进程
# 127.0.0.1:9000 是 PHP-FPM 默认监听地址
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000; # PHP-FPM 监听地址
fastcgi_index index.php; # 默认索引文件
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; # 引入标准 FastCGI 参数
# 超时设置(秒),防止长请求(如 Excel 导出)被 Nginx 提前断开
fastcgi_read_timeout 300; # PHP 脚本最长执行时间
fastcgi_send_timeout 300; # Nginx 向 PHP-FPM 发送请求的超时
}
# -----------------------------------------------------------------
# 安全规则
# -----------------------------------------------------------------
# 禁止访问隐藏文件(如 .env、.git、.htaccess)
location ~ /\. {
deny all;
}
# 禁止上传目录执行 PHP(防止恶意文件上传后被当作脚本执行)
location ~ /uploads/.*\.php$ {
deny all;
}
# -----------------------------------------------------------------
# 静态资源缓存
# -----------------------------------------------------------------
# 常见静态文件类型设置 30 天浏览器缓存,减少重复请求
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# -----------------------------------------------------------------
# Gzip 压缩
# -----------------------------------------------------------------
# 对文本类响应启用压缩,减少传输体积(可节省 60%+ 带宽)
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 1024; # 小于 1KB 的响应不压缩(压缩收益低)
}
```
### CDN / 负载均衡部署
当项目部署在 CDN、云防护或负载均衡后面时,PHP 获取到的 `REMOTE_ADDR` 是代理服务器的 IP(通常为 `127.0.0.1`),而非真实客户端 IP。
框架内置 `ProxyMiddleware` 全局中间件,会自动从 `X-Forwarded-For` / `X-Real-IP` 请求头中提取真实客户端 IP。只需在 `.env` 的 `[API]` 段配置受信代理 IP:
```ini
[API]
# 受信代理 IP(逗号分隔,支持 CIDR 网段)
# 腾讯云 CDN 常用 IP 段(完整列表请参考云服务商文档)
PROXY_IPS = 127.0.0.1,::1,101.226.0.0/15,112.65.0.0/16,140.207.0.0/16,180.101.0.0/16,182.254.0.0/16,223.166.0.0/16
```
:::warning 重要
- 未配置 `PROXY_IPS` 时,默认信任 `127.0.0.1` 和 `::1`
- **不要**在 Nginx 的 `fastcgi_param` 中手动覆盖 `REMOTE_ADDR`、`HTTP_X_REAL_IP`、`HTTP_X_FORWARDED_FOR`,否则会丢失 CDN 传递的真实 IP
- 配置后需清除运行时缓存:`rm -rf runtime/*`
:::
## Apache 配置
项目 `public/.htaccess` 已配置好 URL 重写,确保启用 `mod_rewrite`:
```bash
# 启用 Apache 重写模块(ThinkPHP 路由依赖此模块)
sudo a2enmod rewrite
# 编辑站点配置文件
sudo nano /etc/apache2/sites-available/000-default.conf
```
```apache
# =============================================================================
# Apache 虚拟主机配置 — ThinkPHP 8 后端 API
# =============================================================================
# 配置路径:/etc/apache2/sites-available/000-default.conf
# 生效命令:sudo systemctl restart apache2
# =============================================================================
<VirtualHost *:80>
# 绑定域名(替换为实际域名)
ServerName api.example.com
# 网站根目录指向 ThinkPHP 入口目录(必须是 public/)
DocumentRoot /www/api/public
# 允许 .htaccess 覆盖配置(ThinkPHP URL 重写依赖此设置)
<Directory /www/api/public>
AllowOverride All # 允许 .htaccess 覆盖所有配置
Require all granted # 允许所有 IP 访问
</Directory>
# 安全:禁止上传目录执行 PHP
<Directory /www/api/public/uploads>
<FilesMatch "\.php$">
Require all denied # 拒绝所有 .php 文件的访问
</FilesMatch>
</Directory>
</VirtualHost>
```
## PHP 生产环境优化
### php.ini 推荐配置
```ini
; =============================================================================
; php.ini 生产环境推荐配置
; =============================================================================
; 配置路径:/etc/php/8.2/fpm/php.ini(Nginx + PHP-FPM 场景)
; 生效命令:sudo systemctl restart php8.2-fpm
; =============================================================================
; -----------------------------------------------------------------------------
; 错误处理(生产环境必须关闭错误显示)
; -----------------------------------------------------------------------------
display_errors = Off ; 不向浏览器显示错误(防止 SQL/路径泄露)
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED ; 记录除通知和弃用外的所有错误
; -----------------------------------------------------------------------------
; OPcache 加速(生产环境必须启用)
; -----------------------------------------------------------------------------
opcache.enable = 1 ; 启用 OPcache 字节码缓存
opcache.memory_consumption = 256 ; OPcache 共享内存大小(MB),按项目规模调整
opcache.interned_strings_buffer = 16 ; 驻留字符串内存(MB)
opcache.max_accelerated_files = 10000 ; 最大缓存文件数(需大于项目 PHP 文件总数)
opcache.validate_timestamps = 0 ; 不检查文件修改时间(性能最优,更新代码后需重启 PHP-FPM)
opcache.save_comments = 1 ; 保留注释(ThinkPHP 注解依赖此配置)
```
:::warning OPcache 注意事项
`opcache.validate_timestamps = 0` 表示不检查文件修改时间,性能最优但更新代码后需要手动清除缓存:`php opcache:clear` 或重启 PHP-FPM。开发环境建议设为 `1`。
:::
```ini
; -----------------------------------------------------------------------------
; 内存与超时
; -----------------------------------------------------------------------------
memory_limit = 256M ; 单脚本最大内存(Excel 导出建议 256M+)
max_execution_time = 60 ; 单脚本最大执行时间(秒)
max_input_time = 60 ; 解析请求数据的最大时间(秒)
; -----------------------------------------------------------------------------
; 文件上传
; -----------------------------------------------------------------------------
upload_max_filesize = 50M ; 单文件最大上传大小
post_max_size = 50M ; POST 请求最大大小(必须 >= upload_max_filesize)
max_file_uploads = 20 ; 单次请求最大上传文件数
; -----------------------------------------------------------------------------
; 时区与会话
; -----------------------------------------------------------------------------
date.timezone = Asia/Shanghai ; 时区(与 .env 中 APP.DEFAULT_TIMEZONE 一致)
session.gc_maxlifetime = 7200 ; 会话过期时间(秒),默认 2 小时
```
### PHP-FPM 配置
```ini
; =============================================================================
; PHP-FPM 进程池配置
; =============================================================================
; 配置路径:/etc/php/8.2/fpm/pool.d/www.conf
; 生效命令:sudo systemctl restart php8.2-fpm
; =============================================================================
[www]
; 运行用户(Nginx 也需使用同一用户,否则权限冲突)
user = www-data
group = www-data
; -----------------------------------------------------------------------------
; 进程管理方式
; -----------------------------------------------------------------------------
; dynamic = 动态管理(推荐生产环境),根据负载自动调整进程数
; static = 固定进程数(高并发场景)
pm = dynamic
pm.max_children = 50 ; 最大子进程数(根据服务器内存调整,每个约 30-50MB)
pm.start_servers = 5 ; 启动时的进程数
pm.min_spare_servers = 5 ; 最小空闲进程数(低于此值会自动创建)
pm.max_spare_servers = 35 ; 最大空闲进程数(高于此值会自动销毁)
pm.max_requests = 500 ; 单进程最大请求数(达到后重启,防内存泄漏)
; -----------------------------------------------------------------------------
; 慢请求日志(排查性能问题)
; -----------------------------------------------------------------------------
slowlog = /var/log/php-fpm-slow.log ; 慢请求日志路径
request_slowlog_timeout = 5s ; 超过 5 秒的请求记录为慢请求
```
## 定时任务配置
### Linux Crontab
```bash
# 编辑当前用户的 crontab 定时任务
crontab -e
# 添加定时任务:每分钟执行一次任务调度器
# 格式:分 时 日 月 周 命令
# * * * * * = 每分钟
# cd /www/api → 切换到项目目录(ThinkPHP 需要工作目录定位配置文件)
# /usr/bin/php → PHP 绝对路径(crontab 环境变量不完整,必须用绝对路径)
# think job:run → 执行 ThinkPHP 命令行任务调度
# >> /dev/null 2>&1 → 丢弃输出(有日志系统记录,不需要控制台输出)
* * * * * cd /www/api && /usr/bin/php think job:run >> /dev/null 2>&1
# 验证 crontab 是否配置成功
crontab -l
```
### Windows 计划任务
```powershell
# =============================================================================
# Windows 计划任务 — 每分钟执行一次任务调度器
# =============================================================================
# /create → 创建新任务
# /tn → 任务名称(在任务计划程序中显示的名称)
# /tr → 要执行的命令
# cmd /c → 执行后关闭 cmd 窗口
# cd /d → 切换驱动器和目录(/d 支持跨盘符)
# /sc minute → 调度频率为"分钟"
# /mo 1 → 每 1 分钟执行一次
# /f → 强制覆盖同名任务
# =============================================================================
schtasks /create /tn "RXThinkCMF_Job" /tr "cmd /c cd /d D:\xampp8.2\htdocs\RXThinkCMF_ThinkPhp8_EleVue && C:\xampp\php\php.exe think job:run" /sc minute /mo 1 /f
# 或通过图形界面:Win+R → 输入 taskschd.msc → 回车
```
### Daemon 守护进程(Supervisor)
```ini
; =============================================================================
; Supervisor 进程守护配置
; =============================================================================
; 配置路径:/etc/supervisor/conf.d/rxthinkcmf-job.conf
; 生效命令:sudo supervisorctl reread && sudo supervisorctl update
; 优势:进程崩溃自动重启,比 crontab 更适合常驻进程
; =============================================================================
[program:rxthinkcmf-job]
command = php /www/api/think job:daemon ; 守护进程模式运行任务调度
directory = /www/api ; 工作目录
autostart = true ; Supervisor 启动时自动启动此进程
autorestart = true ; 进程退出后自动重启
user = www-data ; 运行用户
stdout_logfile = /var/log/rxthinkcmf-job.log ; 标准输出日志路径
```
```bash
# 重新读取 Supervisor 配置文件(发现新增的 conf 文件)
sudo supervisorctl reread
# 更新进程状态(应用新配置)
sudo supervisorctl update
# 启动 rxthinkcmf-job 进程
sudo supervisorctl start rxthinkcmf-job
# 查看进程状态
sudo supervisorctl status rxthinkcmf-job
```
## 多数据库部署注意事项
### MySQL
```bash
# 确保 MySQL 服务已启动
sudo systemctl start mysql
# 创建生产数据库
# CHARACTER SET utf8mb4 → 支持 emoji 等四字节字符
# COLLATE utf8mb4_general_ci → 不区分大小写的排序规则
mysql -u root -proot -e "CREATE DATABASE `rxthinkcmf.thinkphp8.elevue` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
# 导入初始化数据(项目自带的 SQL 文件)
mysql -u root -proot rxthinkcmf.thinkphp8.elevue < document/mysql/rxthinkcmf.thinkphp8.elevue.sql
```
### PostgreSQL
```bash
# 确保 PostgreSQL 服务已启动
sudo systemctl start postgresql
# 安装 PHP 的 PostgreSQL 扩展(如果尚未安装)
sudo apt install php8.2-pgsql
# 重启 PHP-FPM 使扩展生效
sudo systemctl restart php8.2-fpm
# 创建数据库(-u postgres 以 postgres 用户执行)
sudo -u postgres createdb rxthinkcmf.thinkphp8.elevue
```
### SQLite
```bash
# 创建数据库文件存放目录
mkdir -p /www/api/runtime
# 创建空的 SQLite 数据库文件(touch 创建空文件即可)
touch /www/api/runtime/database.sqlite
# 设置文件权限(664 = owner/group 可读写,others 只读)
chmod 664 /www/api/runtime/database.sqlite
```
```ini
; .env 配置(切换到 SQLite 数据库)
[DATABASE]
TYPE = sqlite ; 数据库类型改为 sqlite
DATABASE = /www/api/runtime/database.sqlite ; SQLite 文件路径
```
### 数据库连接池
高并发场景建议配置持久连接:
```ini
; php.ini — 使用 Unix Socket 连接 MySQL(比 TCP 更快)
; 前提:PHP-FPM 和 MySQL 在同一台服务器上
pdo_mysql.default_socket = /var/run/mysqld/mysqld.sock
```
## 目录权限
```bash
# -----------------------------------------------------------------------------
# 项目目录(owner 可读写执行,group/others 可读和执行)
# -----------------------------------------------------------------------------
chmod -R 755 /www/api/ # 目录 755,文件 644
chown -R www-data:www-data /www/api/ # 设置 owner 为 Web 服务器用户
# -----------------------------------------------------------------------------
# 运行时目录(必须可写 — ThinkPHP 缓存、日志、编译模板)
# -----------------------------------------------------------------------------
chmod -R 777 /www/api/runtime/ # 777 确保 PHP-FPM 进程可写入
chown -R www-data:www-data /www/api/runtime/
# -----------------------------------------------------------------------------
# 上传目录(必须可写 — 用户上传文件存储位置)
# -----------------------------------------------------------------------------
mkdir -p /opt/data/uploads # 创建上传目录(如不存在)
chmod -R 755 /opt/data/uploads # 目录可写
chown -R www-data:www-data /opt/data/uploads # 设置 owner
```
## SSL 证书(HTTPS)
```nginx
# =============================================================================
# HTTPS 配置(生产环境必须启用)
# =============================================================================
# HTTPS 站点配置
server {
listen 443 ssl; # 监听 443 端口,启用 SSL
server_name api.example.com;
# SSL 证书文件路径(替换为实际证书路径)
ssl_certificate /etc/ssl/certs/api.example.com.pem; # 证书文件(含证书链)
ssl_certificate_key /etc/ssl/private/api.example.com.key; # 私钥文件
# ... 其他配置(location、fastcgi 等)同上方 Nginx 配置 ...
}
# HTTP 自动跳转 HTTPS(301 永久重定向)
server {
listen 80; # 监听 80 端口(HTTP)
server_name api.example.com;
return 301 https://$server_name$request_uri; # 301 跳转到 HTTPS
}
```