424 lines
17 KiB
Markdown
424 lines
17 KiB
Markdown
# 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_ThinkPhp6_NaiveVue && 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.naivevue` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
|
||
|
||
# 导入初始化数据(项目自带的 SQL 文件)
|
||
mysql -u root -proot rxthinkcmf.thinkphp8.naivevue < document/mysql/rxthinkcmf.thinkphp8.naivevue.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.naivevue
|
||
```
|
||
|
||
### 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
|
||
}
|
||
```
|