签入版本
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
|
||||
```nginx
|
||||
# =============================================================================
|
||||
# Nginx 站点配置 — ThinkPHP 6 后端 API
|
||||
# Nginx 站点配置 — Laravel 13 后端 API
|
||||
# =============================================================================
|
||||
# 用途:生产环境 Nginx 反向代理,将 HTTP 请求转发给 PHP-FPM 处理
|
||||
# 配置路径:/etc/nginx/sites-available/rxthinkcmf
|
||||
@@ -21,20 +21,18 @@ server {
|
||||
# 绑定域名(替换为实际域名)
|
||||
server_name api.example.com;
|
||||
|
||||
# 网站根目录指向 ThinkPHP 入口目录
|
||||
# 网站根目录指向 Laravel 入口目录
|
||||
# 注意:必须指向 public/ 子目录,而非项目根目录
|
||||
root /www/api/public;
|
||||
index index.php;
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# URL 重写(ThinkPHP 必需)
|
||||
# URL 重写(Laravel 必需)
|
||||
# -----------------------------------------------------------------
|
||||
# 将所有非真实文件请求转发到 index.php,由 ThinkPHP 路由解析
|
||||
# 例:GET /api/user/page → /index.php?s=/api/user/page
|
||||
# 将所有非真实文件请求转发到 index.php,由 Laravel 路由解析
|
||||
# 例:GET /api/user/page → /index.php?/api/user/page(QUERY_STRING 传递)
|
||||
location / {
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?s=$1 last;
|
||||
}
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
@@ -89,19 +87,18 @@ server {
|
||||
|
||||
当项目部署在 CDN、云防护或负载均衡后面时,PHP 获取到的 `REMOTE_ADDR` 是代理服务器的 IP(通常为 `127.0.0.1`),而非真实客户端 IP。
|
||||
|
||||
框架内置 `ProxyMiddleware` 全局中间件,会自动从 `X-Forwarded-For` / `X-Real-IP` 请求头中提取真实客户端 IP。只需在 `.env` 的 `[API]` 段配置受信代理 IP:
|
||||
框架内置 `ProxyMiddleware` 全局中间件,会自动从 `X-Forwarded-For` / `X-Real-IP` 请求头中提取真实客户端 IP。只需在 `.env` 中配置受信代理 IP:
|
||||
|
||||
```ini
|
||||
[API]
|
||||
# 受信代理 IP(逗号分隔,支持 CIDR 网段)
|
||||
# .env — 受信代理 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
|
||||
TRUSTED_PROXIES=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`
|
||||
- 未配置 `TRUSTED_PROXIES` 时,默认信任 `127.0.0.1` 和 `::1`
|
||||
- **不要**在 Nginx 的 `fastcgi_param` 中手动覆盖 `REMOTE_ADDR`、`HTTP_X_REAL_IP`、`HTTP_X_FORWARDED_FOR`,否则会丢失 CDN 传递的真实 IP
|
||||
- 配置后需清除运行时缓存:`rm -rf runtime/*`
|
||||
- 若执行过 `php artisan config:cache`,修改 `.env` 后需 `php artisan config:clear`(或重新 `config:cache`)再重启 PHP-FPM
|
||||
:::
|
||||
|
||||
## Apache 配置
|
||||
@@ -109,7 +106,7 @@ 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.
|
||||
项目 `public/.htaccess` 已配置好 URL 重写,确保启用 `mod_rewrite`:
|
||||
|
||||
```bash
|
||||
# 启用 Apache 重写模块(ThinkPHP 路由依赖此模块)
|
||||
# 启用 Apache 重写模块(Laravel 路由依赖此模块)
|
||||
sudo a2enmod rewrite
|
||||
|
||||
# 编辑站点配置文件
|
||||
@@ -118,7 +115,7 @@ sudo nano /etc/apache2/sites-available/000-default.conf
|
||||
|
||||
```apache
|
||||
# =============================================================================
|
||||
# Apache 虚拟主机配置 — ThinkPHP 6 后端 API
|
||||
# Apache 虚拟主机配置 — Laravel 13 后端 API
|
||||
# =============================================================================
|
||||
# 配置路径:/etc/apache2/sites-available/000-default.conf
|
||||
# 生效命令:sudo systemctl restart apache2
|
||||
@@ -127,10 +124,10 @@ sudo nano /etc/apache2/sites-available/000-default.conf
|
||||
<VirtualHost *:80>
|
||||
# 绑定域名(替换为实际域名)
|
||||
ServerName api.example.com
|
||||
# 网站根目录指向 ThinkPHP 入口目录(必须是 public/)
|
||||
# 网站根目录指向 Laravel 入口目录(必须是 public/)
|
||||
DocumentRoot /www/api/public
|
||||
|
||||
# 允许 .htaccess 覆盖配置(ThinkPHP URL 重写依赖此设置)
|
||||
# 允许 .htaccess 覆盖配置(Laravel URL 重写依赖此设置)
|
||||
<Directory /www/api/public>
|
||||
AllowOverride All # 允许 .htaccess 覆盖所有配置
|
||||
Require all granted # 允许所有 IP 访问
|
||||
@@ -153,8 +150,8 @@ sudo nano /etc/apache2/sites-available/000-default.conf
|
||||
; =============================================================================
|
||||
; php.ini 生产环境推荐配置
|
||||
; =============================================================================
|
||||
; 配置路径:/etc/php/8.2/fpm/php.ini(Nginx + PHP-FPM 场景)
|
||||
; 生效命令:sudo systemctl restart php8.2-fpm
|
||||
; 配置路径:/etc/php/8.3/fpm/php.ini(Nginx + PHP-FPM 场景)
|
||||
; 生效命令:sudo systemctl restart php8.3-fpm
|
||||
; =============================================================================
|
||||
|
||||
; -----------------------------------------------------------------------------
|
||||
@@ -171,11 +168,11 @@ 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 注解依赖此配置)
|
||||
opcache.save_comments = 1 ; 保留注释(反射文档注释、调试栈追踪依赖此配置)
|
||||
```
|
||||
|
||||
:::warning OPcache 注意事项
|
||||
`opcache.validate_timestamps = 0` 表示不检查文件修改时间,性能最优但更新代码后需要手动清除缓存:`php opcache:clear` 或重启 PHP-FPM。开发环境建议设为 `1`。
|
||||
`opcache.validate_timestamps = 0` 表示不检查文件修改时间,性能最优但更新代码后需要手动清除缓存:重启 PHP-FPM。开发环境建议设为 `1`。
|
||||
:::
|
||||
|
||||
```ini
|
||||
@@ -189,15 +186,15 @@ max_input_time = 60 ; 解析请求数据的最大时间(秒)
|
||||
; -----------------------------------------------------------------------------
|
||||
; 文件上传
|
||||
; -----------------------------------------------------------------------------
|
||||
upload_max_filesize = 50M ; 单文件最大上传大小
|
||||
upload_max_filesize = 50M ; 单文件最大上传大小(与 .env 中 FILE_MAX_SIZE 配合)
|
||||
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 小时
|
||||
date.timezone = Asia/Shanghai ; PHP 时区(Laravel 应用时区由 .env 的 APP_TIMEZONE 决定,默认 Asia/Shanghai,两者需一致)
|
||||
session.gc_maxlifetime = 7200 ; 会话过期时间(秒),与 .env 中 SESSION_LIFETIME=120 分钟一致
|
||||
```
|
||||
|
||||
### PHP-FPM 配置
|
||||
@@ -206,8 +203,8 @@ session.gc_maxlifetime = 7200 ; 会话过期时间(秒),默认 2 小
|
||||
; =============================================================================
|
||||
; PHP-FPM 进程池配置
|
||||
; =============================================================================
|
||||
; 配置路径:/etc/php/8.2/fpm/pool.d/www.conf
|
||||
; 生效命令:sudo systemctl restart php8.2-fpm
|
||||
; 配置路径:/etc/php/8.3/fpm/pool.d/www.conf
|
||||
; 生效命令:sudo systemctl restart php8.3-fpm
|
||||
; =============================================================================
|
||||
|
||||
[www]
|
||||
@@ -245,11 +242,11 @@ crontab -e
|
||||
# 添加定时任务:每分钟执行一次任务调度器
|
||||
# 格式:分 时 日 月 周 命令
|
||||
# * * * * * = 每分钟
|
||||
# cd /www/api → 切换到项目目录(ThinkPHP 需要工作目录定位配置文件)
|
||||
# cd /www/api → 切换到项目目录(Artisan 需要工作目录定位配置文件)
|
||||
# /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
|
||||
# artisan job:run → 执行 RXThinkCMF 任务调度(扫描 job 表执行到期任务)
|
||||
# >> /dev/null 2>&1 → 丢弃输出(任务执行结果记录在任务日志表中)
|
||||
* * * * * cd /www/api && /usr/bin/php artisan job:run >> /dev/null 2>&1
|
||||
|
||||
# 验证 crontab 是否配置成功
|
||||
crontab -l
|
||||
@@ -270,7 +267,7 @@ crontab -l
|
||||
# /mo 1 → 每 1 分钟执行一次
|
||||
# /f → 强制覆盖同名任务
|
||||
# =============================================================================
|
||||
schtasks /create /tn "RXThinkCMF_Job" /tr "cmd /c cd /d D:\xampp\htdocs\v3\thinkphp6 && C:\xampp\php\php.exe think job:run" /sc minute /mo 1 /f
|
||||
schtasks /create /tn "RXThinkCMF_Job" /tr "cmd /c cd /d D:\laragon\www\RXThinkCMF_Laravel13_EleVue && D:\laragon\bin\php\php-8.3\php.exe artisan job:run" /sc minute /mo 1 /f
|
||||
|
||||
# 或通过图形界面:Win+R → 输入 taskschd.msc → 回车
|
||||
```
|
||||
@@ -287,12 +284,12 @@ schtasks /create /tn "RXThinkCMF_Job" /tr "cmd /c cd /d D:\xampp\htdocs\v3\think
|
||||
; =============================================================================
|
||||
|
||||
[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 ; 标准输出日志路径
|
||||
command = php /www/api/artisan job:daemon ; 守护进程模式运行任务调度
|
||||
directory = /www/api ; 工作目录
|
||||
autostart = true ; Supervisor 启动时自动启动此进程
|
||||
autorestart = true ; 进程退出后自动重启
|
||||
user = www-data ; 运行用户
|
||||
stdout_logfile = /var/log/rxthinkcmf-job.log ; 标准输出日志路径
|
||||
```
|
||||
|
||||
```bash
|
||||
@@ -309,6 +306,20 @@ sudo supervisorctl start rxthinkcmf-job
|
||||
sudo supervisorctl status rxthinkcmf-job
|
||||
```
|
||||
|
||||
### 队列常驻进程(Supervisor)
|
||||
|
||||
本项目队列驱动为 Redis(`QUEUE_CONNECTION=redis`),生产环境需常驻进程消费队列:
|
||||
|
||||
```ini
|
||||
[program:rxthinkcmf-queue]
|
||||
command = php /www/api/artisan queue:work --tries=3 --timeout=60
|
||||
directory = /www/api
|
||||
autostart = true
|
||||
autorestart = true
|
||||
user = www-data
|
||||
stdout_logfile = /var/log/rxthinkcmf-queue.log
|
||||
```
|
||||
|
||||
## 多数据库部署注意事项
|
||||
|
||||
### MySQL
|
||||
@@ -320,10 +331,10 @@ sudo systemctl start mysql
|
||||
# 创建生产数据库
|
||||
# CHARACTER SET utf8mb4 → 支持 emoji 等四字节字符
|
||||
# COLLATE utf8mb4_general_ci → 不区分大小写的排序规则
|
||||
mysql -u root -proot -e "CREATE DATABASE `rxthinkcmf.thinkphp6.elevue` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
|
||||
mysql -u root -proot -e "CREATE DATABASE \`rxthinkcmf.laravel13.elevue\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
|
||||
|
||||
# 导入初始化数据(项目自带的 SQL 文件)
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue < document/mysql/rxthinkcmf.thinkphp6.elevue.sql
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue < document/mysql/rxthinkcmf.laravel13.elevue.sql
|
||||
```
|
||||
|
||||
### PostgreSQL
|
||||
@@ -333,33 +344,29 @@ mysql -u root -proot rxthinkcmf.thinkphp6.elevue < document/mysql/rxthinkcmf.thi
|
||||
sudo systemctl start postgresql
|
||||
|
||||
# 安装 PHP 的 PostgreSQL 扩展(如果尚未安装)
|
||||
sudo apt install php8.2-pgsql
|
||||
sudo apt install php8.3-pgsql
|
||||
|
||||
# 重启 PHP-FPM 使扩展生效
|
||||
sudo systemctl restart php8.2-fpm
|
||||
sudo systemctl restart php8.3-fpm
|
||||
|
||||
# 创建数据库(-u postgres 以 postgres 用户执行)
|
||||
sudo -u postgres createdb rxthinkcmf.thinkphp6.elevue
|
||||
sudo -u postgres createdb rxthinkcmf.laravel13.elevue
|
||||
```
|
||||
|
||||
### SQLite
|
||||
|
||||
```bash
|
||||
# 创建数据库文件存放目录
|
||||
mkdir -p /www/api/runtime
|
||||
|
||||
# 创建空的 SQLite 数据库文件(touch 创建空文件即可)
|
||||
touch /www/api/runtime/database.sqlite
|
||||
touch /www/api/database/database.sqlite
|
||||
|
||||
# 设置文件权限(664 = owner/group 可读写,others 只读)
|
||||
chmod 664 /www/api/runtime/database.sqlite
|
||||
chmod 664 /www/api/database/database.sqlite
|
||||
```
|
||||
|
||||
```ini
|
||||
; .env 配置(切换到 SQLite 数据库)
|
||||
[DATABASE]
|
||||
TYPE = sqlite ; 数据库类型改为 sqlite
|
||||
DATABASE = /www/api/runtime/database.sqlite ; SQLite 文件路径
|
||||
DB_CONNECTION=sqlite ; 数据库类型改为 sqlite
|
||||
DB_DATABASE=/www/api/database/database.sqlite ; SQLite 文件路径(绝对路径)
|
||||
```
|
||||
|
||||
### 数据库连接池
|
||||
@@ -382,17 +389,19 @@ chmod -R 755 /www/api/ # 目录 755,文件 644
|
||||
chown -R www-data:www-data /www/api/ # 设置 owner 为 Web 服务器用户
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 运行时目录(必须可写 — ThinkPHP 缓存、日志、编译模板)
|
||||
# 运行时目录(必须可写 — Laravel 缓存、日志、编译视图、框架引导缓存)
|
||||
# -----------------------------------------------------------------------------
|
||||
chmod -R 777 /www/api/runtime/ # 777 确保 PHP-FPM 进程可写入
|
||||
chown -R www-data:www-data /www/api/runtime/
|
||||
chmod -R 777 /www/api/storage/ # 777 确保 PHP-FPM 进程可写入
|
||||
chown -R www-data:www-data /www/api/storage/
|
||||
chmod -R 777 /www/api/bootstrap/cache/ # 配置/路由缓存文件写入位置
|
||||
chown -R www-data:www-data /www/api/bootstrap/cache/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 上传目录(必须可写 — 用户上传文件存储位置)
|
||||
# -----------------------------------------------------------------------------
|
||||
mkdir -p /opt/data/uploads # 创建上传目录(如不存在)
|
||||
chmod -R 755 /opt/data/uploads # 目录可写
|
||||
chown -R www-data:www-data /opt/data/uploads # 设置 owner
|
||||
mkdir -p /www/api/public/uploads # 创建上传目录(如不存在)
|
||||
chmod -R 755 /www/api/public/uploads # 目录可写
|
||||
chown -R www-data:www-data /www/api/public/uploads
|
||||
```
|
||||
|
||||
## SSL 证书(HTTPS)
|
||||
@@ -421,3 +430,7 @@ server {
|
||||
return 301 https://$server_name$request_uri; # 301 跳转到 HTTPS
|
||||
}
|
||||
```
|
||||
|
||||
:::tip 启用 HTTPS 后的前端配置
|
||||
前端 `.env` 中的 API 地址需改为 `https://` 域名,`.env` 的 `CORS_ALLOW_ORIGIN` 同步改为 `https://admin.example.com`,避免跨域失败。
|
||||
:::
|
||||
|
||||
@@ -16,27 +16,31 @@
|
||||
# -proot → 数据库密码(生产环境建议用 -p 后不跟密码,交互式输入)
|
||||
# rxthinkcmf... → 要备份的数据库名
|
||||
# > backup_*.sql → 输出到文件,$(date +%Y%m%d) 自动生成日期后缀
|
||||
mysqldump -u root -proot rxthinkcmf.thinkphp6.elevue > backup_$(date +%Y%m%d).sql
|
||||
mysqldump -u root -proot rxthinkcmf.laravel13.elevue > backup_$(date +%Y%m%d).sql
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 压缩备份(推荐 — 可节省 70%+ 磁盘空间)
|
||||
# -----------------------------------------------------------------------------
|
||||
# | gzip → 将 mysqldump 输出通过管道传给 gzip 压缩
|
||||
mysqldump -u root -proot rxthinkcmf.thinkphp6.elevue | gzip > backup_$(date +%Y%m%d).sql.gz
|
||||
mysqldump -u root -proot rxthinkcmf.laravel13.elevue | gzip > backup_$(date +%Y%m%d).sql.gz
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 仅备份表结构(不含数据 — 用于对比表结构变更)
|
||||
# -----------------------------------------------------------------------------
|
||||
# --no-data → 只导出 CREATE TABLE 语句,不导出数据
|
||||
mysqldump -u root -proot --no-data rxthinkcmf.thinkphp6.elevue > schema_$(date +%Y%m%d).sql
|
||||
mysqldump -u root -proot --no-data rxthinkcmf.laravel13.elevue > schema_$(date +%Y%m%d).sql
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 仅备份数据(不含表结构 — 用于数据迁移)
|
||||
# -----------------------------------------------------------------------------
|
||||
# --no-create-info → 只导出 INSERT 语句,不导出 CREATE TABLE
|
||||
mysqldump -u root -proot --no-create-info rxthinkcmf.thinkphp6.elevue > data_$(date +%Y%m%d).sql
|
||||
mysqldump -u root -proot --no-create-info rxthinkcmf.laravel13.elevue > data_$(date +%Y%m%d).sql
|
||||
```
|
||||
|
||||
:::info 大库提示
|
||||
本项目初始化数据约 216MB(导出后更大),全量备份建议使用压缩(gzip),并避开业务高峰时段。
|
||||
:::
|
||||
|
||||
### 自动备份脚本
|
||||
|
||||
```bash
|
||||
@@ -52,7 +56,7 @@ mysqldump -u root -proot --no-create-info rxthinkcmf.thinkphp6.elevue > data_$(d
|
||||
# 配置参数(按实际环境修改)
|
||||
# -----------------------------------------------------------------------------
|
||||
BACKUP_DIR="/backup/mysql" # 备份文件存放目录
|
||||
DB_NAME="rxthinkcmf.thinkphp6.elevue" # 要备份的数据库名
|
||||
DB_NAME="rxthinkcmf.laravel13.elevue" # 要备份的数据库名
|
||||
DB_USER="root" # 数据库用户名
|
||||
DB_PASS="root" # 数据库密码
|
||||
DATE=$(date +%Y%m%d_%H%M%S) # 当前时间戳(年月日_时分秒)
|
||||
@@ -119,7 +123,8 @@ crontab -e
|
||||
# -z → 用 gzip 压缩
|
||||
# -f → 指定输出文件名
|
||||
# $(date +%Y%m%d) → 自动生成日期后缀
|
||||
tar -czf /backup/uploads_$(date +%Y%m%d).tar.gz /opt/data/uploads/
|
||||
# 本项目上传目录默认在 public/uploads/(FILE_UPLOAD_DIR=uploads)
|
||||
tar -czf /backup/uploads_$(date +%Y%m%d).tar.gz /www/api/public/uploads/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 上传文件自动备份脚本
|
||||
@@ -128,7 +133,7 @@ tar -czf /backup/uploads_$(date +%Y%m%d).tar.gz /opt/data/uploads/
|
||||
BACKUP_DIR="/backup/uploads" # 备份存放目录
|
||||
DATE=$(date +%Y%m%d) # 日期后缀
|
||||
mkdir -p $BACKUP_DIR # 创建目录(如不存在)
|
||||
tar -czf $BACKUP_DIR/uploads_$DATE.tar.gz /opt/data/uploads/ # 压缩打包
|
||||
tar -czf $BACKUP_DIR/uploads_$DATE.tar.gz /www/api/public/uploads/ # 压缩打包
|
||||
find $BACKUP_DIR -name "uploads_*.tar.gz" -mtime +30 -delete # 清理 30 天前的备份
|
||||
```
|
||||
|
||||
@@ -141,25 +146,29 @@ find $BACKUP_DIR -name "uploads_*.tar.gz" -mtime +30 -delete # 清理 30 天
|
||||
# 从 SQL 文件恢复(全量覆盖)
|
||||
# -----------------------------------------------------------------------------
|
||||
# < backup_*.sql → 将文件内容作为 mysql 命令的输入
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue < backup_20260920.sql
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue < backup_20260920.sql
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 从压缩文件恢复(gunzip 解压后传给 mysql)
|
||||
# -----------------------------------------------------------------------------
|
||||
# gunzip < file.sql.gz → 解压并输出到标准输出
|
||||
# | mysql → 通过管道传给 mysql 命令执行
|
||||
gunzip < backup_20260920.sql.gz | mysql -u root -proot rxthinkcmf.thinkphp6.elevue
|
||||
gunzip < backup_20260920.sql.gz | mysql -u root -proot rxthinkcmf.laravel13.elevue
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 恢复到新数据库(安全起见 — 先验证再切换)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 1. 创建临时验证数据库
|
||||
mysql -u root -proot -e "CREATE DATABASE `rxthinkcmf.thinkphp6.elevue_restore`;"
|
||||
mysql -u root -proot -e "CREATE DATABASE \`rxthinkcmf.laravel13.elevue_restore\`;"
|
||||
# 2. 恢复备份到临时库
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue_restore < backup_20260920.sql
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue_restore < backup_20260920.sql
|
||||
# 3. 验证数据无误后,重命名数据库(需停机操作)
|
||||
```
|
||||
|
||||
:::warning 恢复后清理缓存
|
||||
恢复数据库后务必执行 `php artisan cache:clear`(或 `php artisan dict:clear-cache`),避免 Redis 中的旧字典/参数缓存与新数据不一致。
|
||||
:::
|
||||
|
||||
### 恢复上传文件
|
||||
|
||||
```bash
|
||||
@@ -177,7 +186,7 @@ tar -xzf /backup/uploads_20260920.tar.gz -C /
|
||||
# 仅恢复特定子目录(如只恢复文章附件)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 在归档文件名后追加要解压的路径前缀
|
||||
tar -xzf /backup/uploads_20260920.tar.gz -C / www/uploads/article/
|
||||
tar -xzf /backup/uploads_20260920.tar.gz -C / www/api/public/uploads/article/
|
||||
```
|
||||
|
||||
## 备份验证
|
||||
@@ -196,7 +205,7 @@ tar -xzf /backup/uploads_20260920.tar.gz -C / www/uploads/article/
|
||||
# =============================================================================
|
||||
|
||||
BACKUP_FILE=$1 # 第一个参数:备份文件路径
|
||||
VERIFY_DB="rxthinkcmf.thinkphp6.elevue_verify" # 临时验证数据库名
|
||||
VERIFY_DB="rxthinkcmf.laravel13.elevue_verify" # 临时验证数据库名
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 创建验证数据库(先删除旧的,再创建新的)
|
||||
@@ -217,8 +226,8 @@ gunzip < $BACKUP_FILE | mysql -u root -p $VERIFY_DB
|
||||
TABLE_COUNT=$(mysql -u root -p -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$VERIFY_DB';")
|
||||
echo "恢复的表数量: $TABLE_COUNT"
|
||||
|
||||
# 检查用户表数据量(验证核心数据是否完整)
|
||||
USER_COUNT=$(mysql -u root -p -N -e "SELECT COUNT(*) FROM $VERIFY_DB.think_user;")
|
||||
# 检查用户表数据量(验证核心数据是否完整,注意本项目表前缀为 laravel_)
|
||||
USER_COUNT=$(mysql -u root -p -N -e "SELECT COUNT(*) FROM $VERIFY_DB.laravel_user;")
|
||||
echo "用户数量: $USER_COUNT"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -243,4 +252,5 @@ echo "备份验证完成"
|
||||
- 异地保留最近 30 天的备份
|
||||
- 每月进行一次恢复测试
|
||||
- 备份文件加密存储(如含敏感数据)
|
||||
- 数据库与 `public/uploads/`、`.env` 一并纳入备份范围(.env 单独加密保管)
|
||||
:::
|
||||
|
||||
@@ -18,20 +18,24 @@
|
||||
|
||||
**PHP 环境**:
|
||||
|
||||
- [ ] 安装 PHP 8.2+
|
||||
- [ ] 安装必需扩展:`pdo_mysql`、`mbstring`、`json`、`openssl`、`fileinfo`、`gd`
|
||||
- [ ] 安装可选扩展:`redis`(缓存驱动)
|
||||
- [ ] 安装 PHP 8.3+(Laravel 13 要求)
|
||||
- [ ] 安装必需扩展:`pdo_mysql`、`mbstring`、`gd`、`bcmath`、`zip`、`openssl`、`fileinfo`、`json`
|
||||
- [ ] 安装 Redis 扩展:`redis`(phpredis,缓存/会话/队列/JWT 均依赖,**必需**)
|
||||
- [ ] 安装 Composer 2.x
|
||||
- [ ] 配置 PHP-FPM(如使用 Nginx)
|
||||
|
||||
**数据库**:
|
||||
|
||||
- [ ] 安装 MySQL 8.0+(或 PostgreSQL / SQL Server / Oracle / SQLite)
|
||||
- [ ] 创建数据库:`CREATE DATABASE \`rxthinkcmf.thinkphp6.elevue\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
|
||||
- [ ] 创建数据库:`CREATE DATABASE \`rxthinkcmf.laravel13.elevue\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;`
|
||||
- [ ] 创建数据库用户并授权
|
||||
- [ ] 导入 SQL 脚本:`mysql -u root -proot rxthinkcmf.thinkphp6.elevue < document/mysql/rxthinkcmf.thinkphp6.elevue.sql`
|
||||
- [ ] 导入 SQL 脚本:`mysql -u root -proot rxthinkcmf.laravel13.elevue < document/mysql/rxthinkcmf.laravel13.elevue.sql`
|
||||
|
||||
**Redis(可选)**:
|
||||
:::info 表结构来源
|
||||
本项目表结构以 SQL 脚本为准(`document/mysql/`),`database/migrations/` 为空,不要依赖 `php artisan migrate` 建表。
|
||||
:::
|
||||
|
||||
**Redis(必需)**:
|
||||
|
||||
- [ ] 安装 Redis 6.0+
|
||||
- [ ] 配置密码
|
||||
@@ -39,7 +43,7 @@
|
||||
|
||||
**Node.js(前端构建)**:
|
||||
|
||||
- [ ] 安装 Node.js 22+
|
||||
- [ ] 安装 Node.js 22 LTS(根目录资源构建 Vite 7 要求 20.19+/22.12+;ui/ 前端为 Vite 3,兼容 Node 14+)
|
||||
- [ ] 安装 pnpm:`npm install -g pnpm`
|
||||
|
||||
### 第 3 阶段:应用部署
|
||||
@@ -48,11 +52,11 @@
|
||||
|
||||
- [ ] 上传项目代码到服务器
|
||||
- [ ] 安装 Composer 依赖:`composer install --no-dev --optimize-autoloader`
|
||||
- [ ] 配置 `.env` 文件(数据库、JWT 密钥、文件上传等)
|
||||
- [ ] 生成 JWT 密钥:`php -r "echo bin2hex(random_bytes(32));"`
|
||||
- [ ] 设置目录权限:`chmod -R 755 runtime/`、`chmod -R 755 public/uploads/`
|
||||
- [ ] 测试启动:`php think run`
|
||||
- [ ] 配置定时任务:`crontab -e` → `* * * * * cd /www/api && php think job:run`
|
||||
- [ ] 配置 `.env` 文件(数据库、Redis、JWT 密钥、文件上传等)
|
||||
- [ ] 生成应用密钥与 JWT 密钥:`php artisan key:generate`、`php -r "echo bin2hex(random_bytes(32));"`(写入 `JWT_SECRET`)
|
||||
- [ ] 设置目录权限:`chmod -R 755 storage/`、`chmod -R 755 bootstrap/cache/`、`chmod -R 755 public/uploads/`
|
||||
- [ ] 测试启动:`php artisan serve --host=127.0.0.1 --port=8000`(生产由 Nginx + PHP-FPM 承载)
|
||||
- [ ] 配置定时任务:`crontab -e` → `* * * * * cd /www/api && php artisan job:run`
|
||||
|
||||
**前端**:
|
||||
|
||||
@@ -69,14 +73,12 @@
|
||||
server {
|
||||
listen 80; # 监听 80 端口
|
||||
server_name api.example.com; # 绑定域名
|
||||
root /www/api/public; # ThinkPHP 入口目录
|
||||
root /www/api/public; # Laravel 入口目录(必须指向 public/)
|
||||
index index.php; # 默认索引文件
|
||||
|
||||
# URL 重写(ThinkPHP 路由必需)
|
||||
# URL 重写(Laravel 路由必需)
|
||||
location / {
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?s=$1 last; # 非真实文件请求转发到 index.php
|
||||
}
|
||||
try_files $uri $uri/ /index.php?$query_string; # 非真实文件请求转发到 index.php
|
||||
}
|
||||
|
||||
# PHP-FPM 转发
|
||||
@@ -97,7 +99,7 @@ server {
|
||||
server {
|
||||
listen 80; # 监听 80 端口
|
||||
server_name admin.example.com; # 绑定域名
|
||||
root /www/admin/dist; # 前端构建产物目录
|
||||
root /www/admin/dist; # 前端构建产物目录(ui/dist)
|
||||
index index.html; # 默认索引文件
|
||||
|
||||
# Vue Router History 模式(所有非文件请求回退到 index.html)
|
||||
@@ -116,22 +118,24 @@ server {
|
||||
|
||||
### 第 5 阶段:安全加固
|
||||
|
||||
- [ ] `.env` 中 `APP_DEBUG = false`
|
||||
- [ ] `.env` 中 `SHOW_ERROR_MSG = false`
|
||||
- [ ] `.env` 中 `JWT.SECRET` 已修改为强随机密钥
|
||||
- [ ] `.env` 中 `CORS.ALLOW_ORIGIN` 已限制为实际域名
|
||||
- [ ] `.env` 中 `APP_DEBUG=false`
|
||||
- [ ] `.env` 中 `APP_ENV=production`
|
||||
- [ ] `.env` 中 `JWT_SECRET` 已修改为强随机密钥(≥32 字符)
|
||||
- [ ] `.env` 中 `CORS_ALLOW_ORIGIN` 已限制为实际域名
|
||||
- [ ] 启用 HTTPS(SSL 证书)
|
||||
- [ ] 上传目录禁止执行 PHP
|
||||
- [ ] 数据库不允许外网访问
|
||||
- [ ] Redis 已设置密码
|
||||
- [ ] Redis 已设置密码且不对公网开放
|
||||
|
||||
### 第 6 阶段:验证
|
||||
|
||||
- [ ] 健康检查正常:访问 `/up` 返回 200
|
||||
- [ ] 验证码接口正常:`/api/captcha` 返回 `code=0`
|
||||
- [ ] 访问前端页面正常
|
||||
- [ ] 登录功能正常(admin / root)
|
||||
- [ ] 各模块 CRUD 功能正常
|
||||
- [ ] 文件上传功能正常
|
||||
- [ ] 定时任务正常执行
|
||||
- [ ] 定时任务正常执行(`php artisan job:run`,查看任务日志表)
|
||||
- [ ] 操作日志正常记录
|
||||
|
||||
## 版本更新 Checklist
|
||||
@@ -146,7 +150,7 @@ server {
|
||||
cp -r /www/api /www/api_backup_$(date +%Y%m%d)
|
||||
|
||||
# 备份数据库(mysqldump 导出 SQL,$(date +%Y%m%d) 自动生成日期后缀)
|
||||
mysqldump -u root -proot rxthinkcmf.thinkphp6.elevue > /backup/db_$(date +%Y%m%d).sql
|
||||
mysqldump -u root -proot rxthinkcmf.laravel13.elevue > /backup/db_$(date +%Y%m%d).sql
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 第 2 步:更新代码
|
||||
@@ -157,17 +161,24 @@ composer install --no-dev --optimize-autoloader # 安装依赖(排除开
|
||||
# -----------------------------------------------------------------------------
|
||||
# 第 3 步:更新数据库(如有迁移脚本)
|
||||
# -----------------------------------------------------------------------------
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue < document/mysql/migration.sql
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue < document/mysql/migration.sql
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 第 4 步:清除缓存
|
||||
# 第 4 步:清除并重建缓存
|
||||
# -----------------------------------------------------------------------------
|
||||
php think clear # 清除 ThinkPHP 运行时缓存(模板、路由、配置等)
|
||||
php artisan cache:clear # 清除应用缓存
|
||||
php artisan config:clear # 清除配置缓存
|
||||
php artisan route:clear # 清除路由缓存
|
||||
php artisan view:clear # 清除编译视图
|
||||
php artisan dict:clear-cache # 清除字典缓存(本项目自定义命令)
|
||||
|
||||
# 生产环境重新构建缓存(可选)
|
||||
php artisan config:cache && php artisan route:cache && php artisan view:cache
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 第 5 步:重启 PHP-FPM(使 OPcache 失效,加载新代码)
|
||||
# -----------------------------------------------------------------------------
|
||||
sudo systemctl restart php8.2-fpm
|
||||
sudo systemctl restart php8.3-fpm
|
||||
```
|
||||
|
||||
### 更新前端
|
||||
@@ -199,10 +210,10 @@ sudo nginx -s reload
|
||||
cp -r /www/api_backup_20260920/* /www/api/
|
||||
|
||||
# 恢复数据库
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue < /backup/db_20260920.sql
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue < /backup/db_20260920.sql
|
||||
|
||||
# 重启 PHP-FPM(清除 OPcache,加载旧代码)
|
||||
sudo systemctl restart php8.2-fpm
|
||||
sudo systemctl restart php8.3-fpm
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 前端回滚(恢复构建产物)
|
||||
|
||||
@@ -4,14 +4,18 @@
|
||||
本节介绍项目的持续集成/持续部署(CI/CD)方案,包括 GitHub Actions 和 GitLab CI 的配置示例,以及自动化测试、构建和部署流程。
|
||||
:::
|
||||
|
||||
:::info 模板说明
|
||||
本项目仓库当前未内置 `.github/workflows` 或 `.gitee/workflows`,以下配置为**通用模板**:按实际代码托管平台(GitHub / Gitee / GitLab)调整后放入对应目录即可使用。
|
||||
:::
|
||||
|
||||
## 流水线架构
|
||||
|
||||
```text
|
||||
代码提交 → 代码检查 → 单元测试 → 构建打包 → 部署上线
|
||||
│ │ │ │ │
|
||||
▼ ▼ ▼ ▼ ▼
|
||||
Git Push ESLint PHPUnit Docker 生产环境
|
||||
PHPStan Vitest Image
|
||||
Git Push Pint PHPUnit Docker 生产环境
|
||||
ESLint (sqlite) Image
|
||||
```
|
||||
|
||||
## GitHub Actions
|
||||
@@ -23,8 +27,9 @@
|
||||
# .github/workflows/backend-ci.yml — 后端持续集成
|
||||
# =============================================================================
|
||||
# 触发条件:push 到 main/develop 分支,或向 main 发起 PR
|
||||
# 执行环境:Ubuntu 最新版 + MySQL 8.0 服务容器
|
||||
# 流程:代码检查 → 静态分析 → 单元测试 → 覆盖率上传
|
||||
# 执行环境:Ubuntu 最新版
|
||||
# 流程:代码风格检查 → 单元测试 → 覆盖率上传
|
||||
# 说明:phpunit.xml 已配置 sqlite :memory: 测试库,无需外部数据库服务
|
||||
# =============================================================================
|
||||
|
||||
name: Backend CI
|
||||
@@ -39,34 +44,16 @@ jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest # 使用 GitHub 托管的最新 Ubuntu 运行器
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# 服务容器(GitHub Actions 自动启动,与运行器共享网络)
|
||||
# -------------------------------------------------------------------------
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.0 # MySQL 8.0 官方镜像
|
||||
env:
|
||||
MYSQL_ROOT_PASSWORD: root # 测试环境密码(仅用于 CI)
|
||||
MYSQL_DATABASE: test_db # 自动创建的测试数据库
|
||||
ports:
|
||||
- 3306:3306 # 暴露端口供测试连接
|
||||
# 健康检查:确保 MySQL 就绪后再执行后续步骤
|
||||
options: >-
|
||||
--health-cmd="mysqladmin ping" # 用 mysqladmin ping 检测
|
||||
--health-interval=10s # 每 10 秒检查一次
|
||||
--health-timeout=5s # 超时时间
|
||||
--health-retries=3 # 重试 3 次后判定失败
|
||||
|
||||
steps:
|
||||
# 拉取代码(checkout@v4 是 GitHub 官方 Action)
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# 安装 PHP 8.2 及所需扩展
|
||||
# 安装 PHP 8.3 及所需扩展
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2 # 第三方 Action,自动安装 PHP
|
||||
with:
|
||||
php-version: '8.2' # PHP 版本
|
||||
extensions: pdo_mysql, gd, redis # 安装的扩展
|
||||
php-version: '8.3' # PHP 版本(Laravel 13 要求)
|
||||
extensions: pdo_mysql, mbstring, gd, bcmath, zip, redis
|
||||
coverage: xdebug # 代码覆盖率工具
|
||||
|
||||
# 安装 Composer 依赖(--no-progress 隐藏进度条,--prefer-dist 下载压缩包更快)
|
||||
@@ -77,19 +64,16 @@ jobs:
|
||||
- name: Prepare Environment
|
||||
run: |
|
||||
cp .env.example .env # 复制环境配置模板
|
||||
php think db:migrate # 执行数据库迁移
|
||||
php artisan key:generate # 生成应用密钥
|
||||
|
||||
# 代码风格检查(PSR-12 标准)
|
||||
# 代码风格检查(Laravel Pint,PSR-12 + Laravel 风格)
|
||||
- name: Code Style Check
|
||||
run: vendor/bin/phpcs --standard=PSR12 app/
|
||||
run: vendor/bin/pint --test
|
||||
|
||||
# 静态分析(level=5 为严格模式,可发现潜在 bug)
|
||||
- name: Static Analysis
|
||||
run: vendor/bin/phpstan analyse app/ --level=5
|
||||
|
||||
# 运行单元测试(--coverage-text 输出文本格式覆盖率报告)
|
||||
# 运行单元测试(composer test = config:clear + artisan test,
|
||||
# phpunit.xml 使用 sqlite :memory:,不依赖 MySQL)
|
||||
- name: Run Tests
|
||||
run: php think test --coverage-text
|
||||
run: composer test -- --coverage-text
|
||||
|
||||
# 上传覆盖率报告到 Codecov(免费的覆盖率追踪平台)
|
||||
- name: Upload Coverage
|
||||
@@ -98,6 +82,10 @@ jobs:
|
||||
file: ./coverage.xml # 覆盖率报告文件
|
||||
```
|
||||
|
||||
:::tip 无外部依赖的测试
|
||||
`phpunit.xml` 将 `DB_CONNECTION` 设为 `sqlite`、`DB_DATABASE` 设为 `:memory:`,单元测试在内存库中运行,CI 无需启动 MySQL 容器。如需对真实 MySQL 做集成测试,再参考下文 GitLab CI 的 services 配置。
|
||||
:::
|
||||
|
||||
### 前端 CI 配置
|
||||
|
||||
```yaml
|
||||
@@ -105,7 +93,7 @@ jobs:
|
||||
# .github/workflows/frontend-ci.yml — 前端持续集成
|
||||
# =============================================================================
|
||||
# 触发条件:仅当 ui/ 目录下的文件变更时触发(避免后端改动触发前端 CI)
|
||||
# 流程:Lint → 类型检查 → 单元测试 → 构建
|
||||
# 流程:Lint → 类型检查 → 构建
|
||||
# =============================================================================
|
||||
|
||||
name: Frontend CI
|
||||
@@ -127,11 +115,11 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# 安装 Node.js 18 并配置 pnpm 缓存
|
||||
# 安装 Node.js 22 并配置 pnpm 缓存
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18' # Node.js 版本
|
||||
node-version: '22' # Node.js 版本(22 LTS;根目录 Vite 7 要求 20.19+/22.12+)
|
||||
cache: 'pnpm' # 启用 pnpm 缓存(加速依赖安装)
|
||||
cache-dependency-path: ui/pnpm-lock.yaml # 缓存依赖的 lockfile 路径
|
||||
|
||||
@@ -144,7 +132,7 @@ jobs:
|
||||
working-directory: ui # 在 ui/ 目录下执行
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
# ESLint 代码风格检查
|
||||
# ESLint 代码风格检查(脚本自带 --fix,会自动修复可修复问题)
|
||||
- name: Lint
|
||||
working-directory: ui
|
||||
run: pnpm lint:eslint
|
||||
@@ -154,17 +142,16 @@ jobs:
|
||||
working-directory: ui
|
||||
run: pnpm type:check
|
||||
|
||||
# 运行单元测试(Vitest)
|
||||
- name: Run Tests
|
||||
working-directory: ui
|
||||
run: pnpm test
|
||||
|
||||
# 生产环境构建(验证构建是否成功)
|
||||
- name: Build
|
||||
working-directory: ui
|
||||
run: pnpm build
|
||||
```
|
||||
|
||||
:::info 前端暂无单元测试脚本
|
||||
`ui/package.json` 未提供 `test` 脚本(如后续引入 Vitest,再补 `pnpm test` 步骤)。
|
||||
:::
|
||||
|
||||
### 自动部署配置
|
||||
|
||||
```yaml
|
||||
@@ -193,6 +180,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# 构建 Docker 镜像(用 git commit SHA 作为版本标签)
|
||||
# 项目自带 Dockerfile 与 docker-compose.yml(含 docker/.env.docker)
|
||||
- name: Build Docker Image
|
||||
run: |
|
||||
docker build -t myapp:${{ github.sha }} . # 用 commit SHA 标记
|
||||
@@ -214,9 +202,9 @@ jobs:
|
||||
key: ${{ secrets.SSH_KEY }} # SSH 私钥
|
||||
script: |
|
||||
cd /opt/myapp # 进入项目目录
|
||||
docker-compose pull # 拉取最新镜像
|
||||
docker-compose up -d # 重建并启动容器
|
||||
php think db:migrate # 执行数据库迁移
|
||||
docker compose --env-file docker/.env.docker pull # 拉取最新镜像
|
||||
docker compose --env-file docker/.env.docker up -d --build
|
||||
# 数据库结构变更:手动执行 document/mysql 下的 SQL 脚本(本项目无 migration)
|
||||
```
|
||||
|
||||
## GitLab CI
|
||||
@@ -236,7 +224,7 @@ stages:
|
||||
|
||||
# 全局变量(所有 job 共享)
|
||||
variables:
|
||||
MYSQL_ROOT_PASSWORD: root # 测试数据库密码
|
||||
MYSQL_ROOT_PASSWORD: root # 测试数据库密码(集成测试用)
|
||||
MYSQL_DATABASE: test_db # 测试数据库名
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -244,20 +232,22 @@ variables:
|
||||
# -----------------------------------------------------------------------------
|
||||
backend:test:
|
||||
stage: test
|
||||
image: php:8.2-cli # PHP 8.2 CLI 镜像
|
||||
image: php:8.3-cli # PHP 8.3 CLI 镜像
|
||||
services:
|
||||
- mysql:8.0 # MySQL 服务容器
|
||||
- mysql:8.0 # MySQL 服务容器(集成测试用;单元测试走 sqlite 内存库)
|
||||
script:
|
||||
# 安装系统依赖(PHP 扩展编译需要)
|
||||
- apt-get update && apt-get install -y libpq-dev libzip-dev
|
||||
# 安装 PHP 扩展
|
||||
- docker-php-ext-install pdo_mysql zip
|
||||
- pecl install redis && docker-php-ext-enable redis
|
||||
# 安装 Composer 依赖
|
||||
- composer install --no-progress
|
||||
# 准备环境并执行测试
|
||||
- cp .env.example .env
|
||||
- php think db:migrate # 数据库迁移
|
||||
- php think test # 运行测试
|
||||
- php artisan key:generate
|
||||
- vendor/bin/pint --test # 代码风格检查
|
||||
- composer test # 运行测试(phpunit.xml 用 sqlite :memory:)
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG} # 按分支名缓存
|
||||
paths:
|
||||
@@ -268,13 +258,13 @@ backend:test:
|
||||
# -----------------------------------------------------------------------------
|
||||
frontend:test:
|
||||
stage: test
|
||||
image: node:18 # Node.js 18 镜像
|
||||
image: node:22 # Node.js 22 镜像
|
||||
script:
|
||||
- cd ui
|
||||
- npm install -g pnpm # 全局安装 pnpm
|
||||
- pnpm install --frozen-lockfile # 安装依赖
|
||||
- pnpm lint:eslint # 代码风格检查
|
||||
- pnpm test # 单元测试
|
||||
- pnpm type:check # TypeScript 类型检查
|
||||
- pnpm build # 生产构建
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
@@ -292,7 +282,7 @@ deploy:production:
|
||||
- docker build -t myapp:$CI_COMMIT_SHA . # 构建镜像
|
||||
- docker push myapp:$CI_COMMIT_SHA # 推送到仓库
|
||||
# SSH 到服务器执行部署
|
||||
- ssh $SERVER_USER@$SERVER_HOST "cd /opt/myapp && docker-compose pull && docker-compose up -d"
|
||||
- ssh $SERVER_USER@$SERVER_HOST "cd /opt/myapp && docker compose --env-file docker/.env.docker up -d --build"
|
||||
environment:
|
||||
name: production
|
||||
url: https://api.example.com
|
||||
|
||||
@@ -1,21 +1,25 @@
|
||||
# 11.3 数据库迁移
|
||||
|
||||
:::tip CLI 迁移工具
|
||||
除了 SQL 脚本导入,项目还提供了 `php think db:migrate` 命令行工具,支持跨数据库自动迁移(MySQL → PostgreSQL 等),自动迁移索引、外键、字段注释、表注释、默认值和排序规则(collation),数据迁移基于主键稳定排序并支持事务回滚,详见 [7.6 数据库迁移工具](/zh/tools/db-migrate.html)。
|
||||
除了 SQL 脚本导入,项目还提供了 `php artisan db:migrate` 命令行工具,支持跨数据库自动迁移(MySQL → PostgreSQL 等),自动迁移索引、外键、字段注释、表注释、默认值和排序规则(collation),数据迁移基于主键稳定排序并支持事务回滚,详见 [7.6 数据库迁移工具](/zh/tools/db-migrate.html)。
|
||||
:::
|
||||
|
||||
:::info 表结构以 SQL 脚本为准
|
||||
本项目 `database/migrations/` 为空,表结构不通过 Laravel 的 `php artisan migrate` 管理,而是由 `document/` 下的 SQL 脚本导入。
|
||||
:::
|
||||
|
||||
## SQL 脚本目录
|
||||
|
||||
```text
|
||||
document/
|
||||
├── mysql/rxthinkcmf.thinkphp6.elevue.sql # MySQL 版本(约 78 万行)
|
||||
├── postgresql/rxthinkcmf.thinkphp6.elevue.sql # PostgreSQL 版本
|
||||
├── sqlserver/rxthinkcmf.thinkphp6.elevue.sql # SQL Server 版本
|
||||
├── oracle/rxthinkcmf.thinkphp6.elevue.sql # Oracle 版本
|
||||
└── sqlite/rxthinkcmf.thinkphp6.elevue.sql # SQLite 版本
|
||||
├── mysql/rxthinkcmf.laravel13.elevue.sql # MySQL 版本(约 216MB)
|
||||
├── postgresql/rxthinkcmf.laravel13.elevue.sql # PostgreSQL 版本
|
||||
├── sqlserver/rxthinkcmf.laravel13.elevue.sql # SQL Server 版本
|
||||
├── oracle/rxthinkcmf.laravel13.elevue.sql # Oracle 版本
|
||||
└── sqlite/rxthinkcmf.laravel13.elevue.sql # SQLite 版本
|
||||
```
|
||||
|
||||
各数据库脚本已针对对应的 SQL 语法做了适配,可直接导入。
|
||||
各数据库脚本已针对对应的 SQL 语法做了适配,可直接导入。表前缀统一为 `laravel_`(与 `.env` 中 `DB_PREFIX` 一致)。
|
||||
|
||||
## 各数据库导入命令
|
||||
|
||||
@@ -23,12 +27,12 @@ document/
|
||||
|
||||
```bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# MySQL 导入(mysql 命行工具)
|
||||
# MySQL 导入(mysql 命令行工具)
|
||||
# -----------------------------------------------------------------------------
|
||||
# -u root -proot → 用户名和密码
|
||||
# rxthinkcmf... → 目标数据库名
|
||||
# < file.sql → 将 SQL 文件作为输入执行
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue < document/mysql/rxthinkcmf.thinkphp6.elevue.sql
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue < document/mysql/rxthinkcmf.laravel13.elevue.sql
|
||||
```
|
||||
|
||||
### PostgreSQL
|
||||
@@ -40,7 +44,7 @@ mysql -u root -proot rxthinkcmf.thinkphp6.elevue < document/mysql/rxthinkcmf.thi
|
||||
# -U postgres → 连接用户
|
||||
# -d ... → 目标数据库
|
||||
# -f file.sql → 执行 SQL 文件
|
||||
psql -U postgres -d rxthinkcmf.thinkphp6.elevue -f document/postgresql/rxthinkcmf.thinkphp6.elevue.sql
|
||||
psql -U postgres -d rxthinkcmf.laravel13.elevue -f document/postgresql/rxthinkcmf.laravel13.elevue.sql
|
||||
```
|
||||
|
||||
### SQL Server
|
||||
@@ -54,7 +58,7 @@ psql -U postgres -d rxthinkcmf.thinkphp6.elevue -f document/postgresql/rxthinkcm
|
||||
# -P root → 密码
|
||||
# -d ... → 目标数据库
|
||||
# -i file.sql → 执行 SQL 文件
|
||||
sqlcmd -S localhost -U sa -P root -d rxthinkcmf.thinkphp6.elevue -i document/sqlserver/rxthinkcmf.thinkphp6.elevue.sql
|
||||
sqlcmd -S localhost -U sa -P root -d rxthinkcmf.laravel13.elevue -i document/sqlserver/rxthinkcmf.laravel13.elevue.sql
|
||||
```
|
||||
|
||||
### Oracle
|
||||
@@ -65,7 +69,7 @@ sqlcmd -S localhost -U sa -P root -d rxthinkcmf.thinkphp6.elevue -i document/sql
|
||||
# -----------------------------------------------------------------------------
|
||||
# root/root@localhost:1521/XE → 用户/密码@主机:端口/服务名
|
||||
# @file.sql → 执行 SQL 文件
|
||||
sqlplus root/root@localhost:1521/XE @document/oracle/rxthinkcmf.thinkphp6.elevue.sql
|
||||
sqlplus root/root@localhost:1521/XE @document/oracle/rxthinkcmf.laravel13.elevue.sql
|
||||
```
|
||||
|
||||
### SQLite
|
||||
@@ -76,11 +80,32 @@ sqlplus root/root@localhost:1521/XE @document/oracle/rxthinkcmf.thinkphp6.elevue
|
||||
# -----------------------------------------------------------------------------
|
||||
# 数据库文件路径 → SQLite 数据库存储在单个文件中
|
||||
# < file.sql → 将 SQL 文件作为输入执行
|
||||
sqlite3 /www/api/runtime/database.sqlite < document/sqlite/rxthinkcmf.thinkphp6.elevue.sql
|
||||
sqlite3 database/database.sqlite < document/sqlite/rxthinkcmf.laravel13.elevue.sql
|
||||
```
|
||||
|
||||
## 跨数据库迁移(CLI)
|
||||
|
||||
在已导入源数据库后,可用 `php artisan db:migrate` 在不同数据库类型间迁移:
|
||||
|
||||
```bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# 跨数据库迁移(MySQL → PostgreSQL 示例)
|
||||
# -----------------------------------------------------------------------------
|
||||
# --src-* / --dst-* → 源库与目标库连接参数(端口省略时按驱动取默认值)
|
||||
# --drop-target-first → 迁移前先删除目标库中的同名表
|
||||
# --batch-size → 批量插入行数(默认 1000)
|
||||
# --tables → 只迁移指定表(逗号分隔),不传则全部
|
||||
# 目标库不存在时自动创建;迁到 PostgreSQL 需先在 php.ini 启用 extension=pdo_pgsql
|
||||
php artisan db:migrate \
|
||||
--src-type=mysql --src-host=127.0.0.1 --src-port=3306 \
|
||||
--src-database=rxthinkcmf.laravel13.elevue --src-username=root --src-password=root \
|
||||
--dst-type=pgsql --dst-host=127.0.0.1 --dst-port=5432 \
|
||||
--dst-database=rxthinkcmf.laravel13.elevue --dst-username=postgres --dst-password=123456
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 每种数据库的主脚本已做语法适配,无需手动转换
|
||||
- 导入前请先创建数据库并配置好用户权限
|
||||
- 详见 [2.4 数据库初始化](/zh/quickstart/database-init.html)
|
||||
- 脚本体积较大(约 216MB),导入耗时较长,建议在内网或本机执行;可先用 `--tables` 只迁移部分表
|
||||
- 详见 [2.5 数据库初始化](/zh/quickstart/database-init.html)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# 11.6 Docker 生产部署
|
||||
|
||||
:::tip 概述
|
||||
本节提供基于 Docker Compose 的生产环境部署方案,包含 **Nginx 反向代理**、**PHP-FPM 应用**、**MySQL 数据库**和 **Redis 缓存**四个服务的容器编排配置。所有脚本均带详细注释,适合快速搭建生产环境,也便于 CI/CD 集成。
|
||||
本节提供基于 Docker Compose 的生产环境部署方案,包含 **Nginx 反向代理**、**PHP-FPM 应用**、**MySQL 数据库**和 **Redis 缓存**四个服务的容器编排配置。所有脚本均带详细注释,适合快速搭建生产环境,也便于 CI/CD 集成。本地快速体验请先阅读 [2.8 Docker 快速体验](/zh/quickstart/docker.html)。
|
||||
:::
|
||||
|
||||
## 架构说明
|
||||
|
||||
```
|
||||
浏览器 → 宿主机:8000 → [Nginx 容器:80] → [PHP-FPM 容器:9000] → ThinkPHP 应用
|
||||
```text
|
||||
浏览器 → 宿主机:8000 → [Nginx 容器:80] → [PHP-FPM 容器:9000] → Laravel 应用
|
||||
↕
|
||||
[MySQL 容器:3306] + [Redis 容器:6379]
|
||||
```
|
||||
@@ -15,7 +15,19 @@
|
||||
- **Nginx**:监听 80 端口,处理 HTTP 请求、URL 重写、静态资源缓存
|
||||
- **PHP-FPM**:监听 9000 端口,执行 PHP 代码
|
||||
- **MySQL**:数据库服务,数据持久化到 Docker 命名卷
|
||||
- **Redis**:缓存服务,数据持久化到 Docker 命名卷
|
||||
- **Redis**:缓存 / 会话 / 队列服务,数据持久化到 Docker 命名卷
|
||||
|
||||
## 与快速体验的差异
|
||||
|
||||
| 项 | 2.8 快速体验 | 本节生产部署 |
|
||||
|----|--------------|--------------|
|
||||
| 启动命令 | `docker compose up -d` | `docker compose --env-file docker/.env.docker up -d --build` |
|
||||
| 密码 | compose 内置默认值(root123 / redis123) | `.env.docker` 中的强密码 |
|
||||
| `APP_DEBUG` | `true` | **`false`** |
|
||||
| `JWT_SECRET` | 占位值或 `.env` 值 | `openssl rand -base64 32` 生成的随机值 |
|
||||
| `CORS_ALLOW_ORIGIN` | `*` | 前端站点具体域名 |
|
||||
| 数据库 / Redis 端口 | 映射到宿主机 | **建议注释掉映射或绑定 127.0.0.1** |
|
||||
| OPcache | `validate_timestamps=1` | 建议改为 `0`(见「性能调优」) |
|
||||
|
||||
## 前置要求
|
||||
|
||||
@@ -24,17 +36,33 @@
|
||||
| Docker | >= 20.10 | 容器运行时 |
|
||||
| Docker Compose | >= 2.0 | 容器编排工具 |
|
||||
| 磁盘空间 | >= 5GB | 镜像 + 数据卷 |
|
||||
| 服务器 | 2 核 / 4 GB 起 | 数据库初始化导入约 226MB |
|
||||
|
||||
## 部署 Checklist
|
||||
|
||||
| # | 步骤 | 说明 |
|
||||
|---|------|------|
|
||||
| 1 | 服务器安装 Docker | `docker compose version` 验证 |
|
||||
| 2 | 获取代码 | `git clone` 或上传代码包 |
|
||||
| 3 | 初始化 `.env` | `composer setup` 或 `cp .env.example .env` + `key:generate`(容器外执行) |
|
||||
| 4 | 定制 `docker/.env.docker` | 强密码、随机 JWT_SECRET、生产域名(见「环境变量配置」) |
|
||||
| 5 | 端口映射调整 | 数据库 / Redis 端口注释掉或绑定 `127.0.0.1` |
|
||||
| 6 | 构建并启动 | `docker compose --env-file docker/.env.docker up -d --build` |
|
||||
| 7 | 验证 | `/up` 健康检查、`/api/captcha` 返回 `code=0` |
|
||||
| 8 | 前端部署 | 见 [11.5 前端部署](/zh/deploy/frontend.html) |
|
||||
| 9 | 监控与备份 | `/up` 挂监控、数据库定时备份,见 [11.9 备份与恢复](/zh/deploy/backup.html) |
|
||||
|
||||
## 文件结构
|
||||
|
||||
```
|
||||
thinkphp6/
|
||||
```text
|
||||
RXThinkCMF_Laravel13_EleVue/
|
||||
├── docker/
|
||||
│ ├── Dockerfile # PHP-FPM 应用镜像定义
|
||||
│ ├── nginx.conf # Nginx 站点配置
|
||||
│ └── .env.docker # Docker 环境变量(密码等敏感信息)
|
||||
├── docker-compose.yml # 容器编排配置(放在项目根目录)
|
||||
├── .env # 应用配置(ThinkPHP 读取)
|
||||
├── .dockerignore # 构建上下文排除(.env、vendor、SQL 等)
|
||||
├── .env # 应用配置(Laravel 读取)
|
||||
└── ...
|
||||
```
|
||||
|
||||
@@ -42,14 +70,14 @@ thinkphp6/
|
||||
|
||||
```dockerfile
|
||||
# =============================================================================
|
||||
# Dockerfile — PHP-FPM 应用镜像
|
||||
# Dockerfile — PHP-FPM 应用镜像(RXThinkCMF Laravel13)
|
||||
# =============================================================================
|
||||
# 基础镜像:PHP 8.2 + FPM(FastCGI 进程管理器)
|
||||
# 构建命令:docker-compose build app
|
||||
# 基础镜像:PHP 8.3 + FPM(FastCGI 进程管理器)
|
||||
# 构建命令:docker compose build app
|
||||
# 运行方式:由 Nginx 容器通过 FastCGI 协议调用本容器的 9000 端口
|
||||
# =============================================================================
|
||||
|
||||
FROM php:8.2-fpm
|
||||
FROM php:8.3-fpm
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 1. 安装系统依赖
|
||||
@@ -69,11 +97,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
# -----------------------------------------------------------------------------
|
||||
# 项目必需扩展(根据 composer.json 和 config/ 推导):
|
||||
# pdo_mysql — MySQL 数据库驱动(config/database.php 使用)
|
||||
# mbstring — 多字节字符串处理(ThinkPHP 框架依赖)
|
||||
# mbstring — 多字节字符串处理(Laravel 框架依赖,composer 平台检查)
|
||||
# gd — 图片处理(验证码生成、图片缩放)
|
||||
# bcmath — 高精度数学运算(phpspreadsheet 依赖)
|
||||
# zip — ZIP 压缩(phpspreadsheet 读写 xlsx 依赖)
|
||||
# redis — Redis 缓存驱动(config/cache.php 使用)
|
||||
# redis — Redis 扩展(phpredis:缓存/会话/队列/JWT 会话均依赖)
|
||||
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install -j$(nproc) \
|
||||
pdo_mysql \
|
||||
@@ -108,20 +136,23 @@ memory_limit = 256M\n\
|
||||
max_execution_time = 60\n\
|
||||
max_input_time = 60\n\
|
||||
\n\
|
||||
; 文件上传(与 .env 中 FILE.MAX_SIZE 配合)\n\
|
||||
; 文件上传(与 .env 中 FILE_MAX_SIZE 配合)\n\
|
||||
upload_max_filesize = 50M\n\
|
||||
post_max_size = 50M\n\
|
||||
max_file_uploads = 20\n\
|
||||
\n\
|
||||
; 时区(与 .env 中 APP.DEFAULT_TIMEZONE 一致)\n\
|
||||
; 时区(与应用时区一致)\n\
|
||||
date.timezone = Asia/Shanghai\n\
|
||||
\n\
|
||||
; OPcache 加速(生产环境必须开启)\n\
|
||||
; OPcache 加速\n\
|
||||
; validate_timestamps=1 + revalidate_freq=0:挂载宿主机代码即时生效(开发友好)\n\
|
||||
; 生产环境建议改为 validate_timestamps=0(见 11.6「性能调优」)\n\
|
||||
opcache.enable = 1\n\
|
||||
opcache.memory_consumption = 256\n\
|
||||
opcache.interned_strings_buffer = 16\n\
|
||||
opcache.max_accelerated_files = 10000\n\
|
||||
opcache.validate_timestamps = 0\n\
|
||||
opcache.validate_timestamps = 1\n\
|
||||
opcache.revalidate_freq = 0\n\
|
||||
opcache.save_comments = 1\n\
|
||||
' >> "$PHP_INI_DIR/php.ini"
|
||||
|
||||
@@ -138,17 +169,24 @@ WORKDIR /var/www/html
|
||||
COPY composer.json composer.lock ./
|
||||
RUN composer install --no-dev --optimize-autoloader --no-interaction
|
||||
|
||||
# 再复制全部项目文件(会覆盖上面的 composer 文件,但内容一致无影响)
|
||||
# 再复制全部项目文件(.env、vendor、node_modules 已被 .dockerignore 排除)
|
||||
COPY . .
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 7. 设置目录权限
|
||||
# 7. 设置 Laravel 可写目录权限
|
||||
# -----------------------------------------------------------------------------
|
||||
# runtime — ThinkPHP 运行时缓存、日志(必须可写)
|
||||
# uploads — 用户上传文件目录(必须可写)
|
||||
RUN mkdir -p runtime uploads \
|
||||
&& chown -R www-data:www-data runtime uploads \
|
||||
&& chmod -R 775 runtime uploads
|
||||
# storage — 日志、缓存、会话、编译视图(必须可写)
|
||||
# bootstrap/cache — 配置/路由/事件缓存(必须可写)
|
||||
# public/uploads — 用户上传文件目录(必须可写)
|
||||
RUN mkdir -p \
|
||||
storage/framework/cache \
|
||||
storage/framework/sessions \
|
||||
storage/framework/views \
|
||||
storage/logs \
|
||||
bootstrap/cache \
|
||||
public/uploads \
|
||||
&& chown -R www-data:www-data storage bootstrap/cache public/uploads \
|
||||
&& chmod -R 775 storage bootstrap/cache public/uploads
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 8. 暴露端口并启动
|
||||
@@ -162,7 +200,7 @@ CMD ["php-fpm"]
|
||||
|
||||
```nginx
|
||||
# =============================================================================
|
||||
# Nginx 配置 — ThinkPHP 6 反向代理
|
||||
# Nginx 配置 — RXThinkCMF Laravel13 反向代理
|
||||
# =============================================================================
|
||||
# 用途:Docker 容器内 Nginx 服务,将 HTTP 请求转发给 PHP-FPM 处理
|
||||
# 挂载方式:docker-compose 中 volumes 映射到 /etc/nginx/conf.d/default.conf
|
||||
@@ -173,28 +211,25 @@ server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
# 网站根目录指向 ThinkPHP 入口目录
|
||||
# 网站根目录指向 Laravel 公开目录
|
||||
# 容器内代码挂载在 /var/www/html,入口文件在 public/index.php
|
||||
root /var/www/html/public;
|
||||
index index.php;
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# URL 重写(ThinkPHP 必需)
|
||||
# URL 重写(Laravel 路由)
|
||||
# -----------------------------------------------------------------
|
||||
# 将所有非真实文件请求转发到 index.php,由 ThinkPHP 路由解析
|
||||
# 例:/api/user/page → /index.php?s=/api/user/page
|
||||
# 真实存在的文件/目录直接返回,其余请求全部交给 public/index.php,
|
||||
# 由 Laravel 路由解析(如 /api/user/page → index.php 处理)
|
||||
location / {
|
||||
if (!-e $request_filename) {
|
||||
rewrite ^(.*)$ /index.php?s=$1 last;
|
||||
}
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# PHP-FPM 处理
|
||||
# PHP-FPM 处理(仅入口 index.php 可执行)
|
||||
# -----------------------------------------------------------------
|
||||
# 所有 .php 请求通过 FastCGI 协议转发给 PHP-FPM 容器
|
||||
# "app" 是 docker-compose 中 PHP-FPM 服务的名称,Docker 内部 DNS 自动解析
|
||||
location ~ \.php$ {
|
||||
location = /index.php {
|
||||
fastcgi_pass app:9000; # 转发到 PHP-FPM 容器的 9000 端口
|
||||
fastcgi_index index.php; # 默认索引文件
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
@@ -205,16 +240,16 @@ server {
|
||||
fastcgi_send_timeout 300;
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# 安全规则
|
||||
# -----------------------------------------------------------------
|
||||
# 禁止访问隐藏文件(如 .env、.git、.htaccess)
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
# 其余 .php 文件(含上传目录、storage 目录)一律 404
|
||||
# 防止恶意文件上传后被执行 —— 只有入口 index.php 能够运行
|
||||
location ~ \.php$ {
|
||||
return 404;
|
||||
}
|
||||
|
||||
# 禁止上传目录执行 PHP(防止恶意文件上传后被执行)
|
||||
location ~ /uploads/.*\.php$ {
|
||||
# -----------------------------------------------------------------
|
||||
# 安全规则:禁止访问隐藏文件(如 .env、.git、.htaccess)
|
||||
# -----------------------------------------------------------------
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
|
||||
@@ -230,7 +265,6 @@ server {
|
||||
# -----------------------------------------------------------------
|
||||
# Gzip 压缩
|
||||
# -----------------------------------------------------------------
|
||||
# 对文本类响应启用压缩,减少传输体积
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
|
||||
gzip_min_length 1024; # 小于 1KB 的响应不压缩(压缩收益低)
|
||||
@@ -242,134 +276,146 @@ server {
|
||||
|
||||
:::tip 与实际文件的关系
|
||||
项目根目录已内置 `docker-compose.yml`,支持两种模式:
|
||||
- **快速体验**:`docker-compose up -d`(使用默认密码 root123 / redis123)
|
||||
- **生产部署**:`docker-compose --env-file docker/.env.docker up -d --build`(使用生产密码)
|
||||
- **快速体验**:`docker compose up -d`(使用默认密码 root123 / redis123)
|
||||
- **生产部署**:`docker compose --env-file docker/.env.docker up -d --build`(使用生产密码)
|
||||
|
||||
下方为生产推荐配置参考,实际文件通过 `${VAR:-默认值}` 语法兼容两种场景。
|
||||
:::
|
||||
|
||||
```yaml
|
||||
# =============================================================================
|
||||
# Docker Compose 生产部署配置
|
||||
# Docker Compose 生产部署配置(RXThinkCMF Laravel13)
|
||||
# =============================================================================
|
||||
# 服务架构:Nginx → PHP-FPM → MySQL + Redis
|
||||
# 启动命令:docker-compose --env-file docker/.env.docker up -d
|
||||
# 停止命令:docker-compose down
|
||||
# 启动命令:docker compose --env-file docker/.env.docker up -d
|
||||
# 停止命令:docker compose down
|
||||
# =============================================================================
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
|
||||
# ===========================================================================
|
||||
# Nginx 反向代理服务
|
||||
# ===========================================================================
|
||||
# 职责:接收外部 HTTP 请求,转发 .php 到 PHP-FPM,直接返回静态资源
|
||||
# 职责:接收外部 HTTP 请求,转发 index.php 到 PHP-FPM,直接返回静态资源
|
||||
# 端口:容器内 80 → 宿主机 8000
|
||||
# ===========================================================================
|
||||
nginx:
|
||||
image: nginx:1.25-alpine # 官方 Nginx 镜像(Alpine 版本,体积小)
|
||||
container_name: rxthinkcmf-nginx # 容器名称,便于 docker logs / docker exec
|
||||
container_name: rxthinkcmf-laravel13-nginx
|
||||
ports:
|
||||
- "8000:80" # 宿主机 8000 → 容器 80
|
||||
volumes:
|
||||
# 挂载 Nginx 站点配置(覆盖默认配置)
|
||||
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||
# 挂载项目代码(与 PHP-FPM 容器共享同一份代码)
|
||||
- ./:/var/www/html:ro # :ro 只读,Nginx 不需要写入代码
|
||||
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro # 站点配置
|
||||
- ./:/var/www/html:ro # 项目代码(只读,与 PHP-FPM 共享同一份)
|
||||
depends_on:
|
||||
- app # 确保 PHP-FPM 先启动
|
||||
networks:
|
||||
- rxthinkcmf-net # 加入内部网络
|
||||
- rxthinkcmf-laravel13-net
|
||||
restart: unless-stopped # 异常退出自动重启
|
||||
|
||||
# ===========================================================================
|
||||
# PHP-FPM 应用服务
|
||||
# ===========================================================================
|
||||
# 职责:执行 ThinkPHP PHP 代码,处理业务逻辑
|
||||
# 端口:9000(FastCGI 协议,仅 Nginx 内部访问)
|
||||
# 职责:执行 Laravel PHP 代码,处理业务逻辑
|
||||
# 端口:9000(FastCGI 协议,仅 Nginx 内部访问,不映射宿主机)
|
||||
# ===========================================================================
|
||||
app:
|
||||
build:
|
||||
context: . # 构建上下文为项目根目录
|
||||
dockerfile: docker/Dockerfile # Dockerfile 路径(相对于 context)
|
||||
container_name: rxthinkcmf-app
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: rxthinkcmf-laravel13-app
|
||||
volumes:
|
||||
# 挂载项目代码(开发/更新时无需重建镜像)
|
||||
- ./:/var/www/html
|
||||
# 上传文件独立持久化卷(容器重建不丢失用户上传)
|
||||
- uploads_data:/opt/data/uploads
|
||||
- ./:/var/www/html # 挂载项目代码(更新时无需重建镜像)
|
||||
environment:
|
||||
- APP_DEBUG=${APP_DEBUG:-false} # 调试模式,默认关闭
|
||||
|
||||
# 数据库:容器内通过服务名 mysql 访问
|
||||
- DB_CONNECTION=mysql
|
||||
- DB_HOST=mysql
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=${MYSQL_DATABASE:-rxthinkcmf.laravel13.elevue}
|
||||
- DB_USERNAME=root
|
||||
- DB_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||||
|
||||
# 缓存 / 会话 / 队列:统一走 Redis
|
||||
- CACHE_STORE=redis
|
||||
- SESSION_DRIVER=redis
|
||||
- QUEUE_CONNECTION=redis
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_PASSWORD=${REDIS_PASSWORD}
|
||||
|
||||
# JWT 密钥 / 文件域名 / 跨域(取自 --env-file)
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
- FILE_DOMAIN_URL=${DOMAIN_URL:-http://localhost:8000}
|
||||
- CORS_ALLOW_ORIGIN=${CORS_ALLOW_ORIGIN:-*}
|
||||
|
||||
depends_on:
|
||||
- mysql # 确保数据库先启动
|
||||
- redis # 确保缓存先启动
|
||||
mysql:
|
||||
condition: service_healthy # 确保数据库就绪(含首次 SQL 导入)
|
||||
redis:
|
||||
condition: service_started
|
||||
networks:
|
||||
- rxthinkcmf-net
|
||||
- rxthinkcmf-laravel13-net
|
||||
restart: unless-stopped
|
||||
|
||||
# ===========================================================================
|
||||
# MySQL 数据库服务
|
||||
# ===========================================================================
|
||||
# 职责:存储业务数据(用户、菜单、字典、文章等)
|
||||
# 端口:3306(可选暴露,用于外部工具连接调试)
|
||||
# ===========================================================================
|
||||
mysql:
|
||||
image: mysql:8.0 # MySQL 8.0 官方镜像
|
||||
container_name: rxthinkcmf-mysql
|
||||
container_name: rxthinkcmf-laravel13-mysql
|
||||
# ports: # 生产环境建议注释掉,不暴露到宿主机
|
||||
# - "3306:3306"
|
||||
environment:
|
||||
# root 用户密码(必须 8 位以上,包含大小写字母和数字)
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
# 启动时自动创建的数据库
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE:-rxthinkcmf.thinkphp6.elevue}
|
||||
# 字符集(支持 emoji 等四字节字符)
|
||||
MYSQL_CHARSET: utf8mb4
|
||||
# 排序规则
|
||||
MYSQL_COLLATION: utf8mb4_general_ci
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # root 用户密码(>=16 位强密码)
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE:-rxthinkcmf.laravel13.elevue}
|
||||
volumes:
|
||||
# 数据持久化(容器重建不丢数据)
|
||||
- mysql_data:/var/lib/mysql
|
||||
# 初始化 SQL(首次启动时自动执行,仅在数据卷为空时生效)
|
||||
- ./document/mysql/rxthinkcmf.thinkphp6.elevue.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||
- mysql_data:/var/lib/mysql # 数据持久化
|
||||
# 初始化 SQL(首次启动自动执行,仅在数据卷为空时生效)
|
||||
- ./document/mysql/rxthinkcmf.laravel13.elevue.sql:/docker-entrypoint-initdb.d/init.sql:ro
|
||||
command:
|
||||
- --character-set-server=utf8mb4
|
||||
- --collation-server=utf8mb4_general_ci
|
||||
- --default-authentication-plugin=mysql_native_password
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
start_period: 60s # 首次导入约 226MB SQL,给足缓冲
|
||||
networks:
|
||||
- rxthinkcmf-net
|
||||
- rxthinkcmf-laravel13-net
|
||||
restart: unless-stopped
|
||||
|
||||
# ===========================================================================
|
||||
# Redis 缓存服务
|
||||
# ===========================================================================
|
||||
# 职责:会话缓存、数据缓存(config/cache.php 配置的驱动)
|
||||
# 端口:6379(可选暴露,用于外部工具连接调试)
|
||||
# 职责:JWT 会话、字典/权限缓存、队列(config/database.php redis 配置)
|
||||
# ===========================================================================
|
||||
redis:
|
||||
image: redis:7-alpine # Redis 7 Alpine 版本(体积小)
|
||||
container_name: rxthinkcmf-redis
|
||||
container_name: rxthinkcmf-laravel13-redis
|
||||
# ports: # 生产环境建议注释掉,不暴露到宿主机
|
||||
# - "6379:6379"
|
||||
command: redis-server --requirepass ${REDIS_PASSWORD} # 设置访问密码
|
||||
volumes:
|
||||
# 数据持久化(RDB 快照文件)
|
||||
- redis_data:/data
|
||||
- redis_data:/data # 数据持久化(RDB 快照)
|
||||
networks:
|
||||
- rxthinkcmf-net
|
||||
- rxthinkcmf-laravel13-net
|
||||
restart: unless-stopped
|
||||
|
||||
# =============================================================================
|
||||
# 命名卷(Named Volumes)
|
||||
# =============================================================================
|
||||
# Docker 管理的持久化存储,容器删除后数据保留
|
||||
# 删除所有数据:docker-compose down -v(-v 参数同时删除命名卷)
|
||||
# 删除所有数据:docker compose down -v(-v 参数同时删除命名卷)
|
||||
# =============================================================================
|
||||
volumes:
|
||||
mysql_data: # MySQL 数据文件
|
||||
redis_data: # Redis RDB 快照文件
|
||||
uploads_data: # 用户上传文件
|
||||
|
||||
# =============================================================================
|
||||
# 内部网络
|
||||
@@ -378,155 +424,207 @@ volumes:
|
||||
# 外部无法直接访问此网络,必须通过 Nginx 的 ports 映射进入
|
||||
# =============================================================================
|
||||
networks:
|
||||
rxthinkcmf-net:
|
||||
rxthinkcmf-laravel13-net:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
## 环境变量配置
|
||||
|
||||
创建 `docker/.env.docker` 文件:
|
||||
创建 / 编辑 `docker/.env.docker` 文件:
|
||||
|
||||
```ini
|
||||
# Docker 环境变量(密码等敏感信息,切勿提交 Git)
|
||||
MYSQL_ROOT_PASSWORD=Your_Strong_Password_2024
|
||||
MYSQL_DATABASE=rxthinkcmf.thinkphp6.elevue
|
||||
REDIS_PASSWORD=Your_Redis_Password_2024
|
||||
|
||||
# 端口(宿主机端口)
|
||||
NGINX_PORT=8000
|
||||
MYSQL_PORT=3306
|
||||
REDIS_PORT=6379
|
||||
|
||||
# MySQL(首次启动自动导入数据库脚本)
|
||||
MYSQL_ROOT_PASSWORD=<16 位以上强密码>
|
||||
MYSQL_DATABASE=rxthinkcmf.laravel13.elevue
|
||||
|
||||
# Redis(与数据库密码不同)
|
||||
REDIS_PASSWORD=<强密码>
|
||||
|
||||
# 应用
|
||||
JWT_SECRET=<openssl rand -base64 32 生成,>= 32 字符>
|
||||
APP_DEBUG=false
|
||||
DOMAIN_URL=https://admin.example.com
|
||||
CORS_ALLOW_ORIGIN=https://www.example.com
|
||||
```
|
||||
|
||||
:::warning 安全提示
|
||||
- `docker/.env.docker` 包含生产密码,**必须加入 `.gitignore`**
|
||||
- 密码至少 16 位,包含大小写字母和数字
|
||||
- JWT 密钥在应用 `.env` 文件中配置,不在此文件中
|
||||
- `docker/.env.docker` 包含生产密码,**必须加入 `.gitignore`,切勿提交到 Git 仓库**
|
||||
- 密码至少 16 位,包含大小写字母和数字,MySQL 与 Redis 密码不同
|
||||
- `JWT_SECRET` 是令牌签名根密钥,泄露等于任意用户令牌可伪造;不同环境使用不同密钥
|
||||
:::
|
||||
|
||||
## 应用 .env 配置
|
||||
|
||||
容器启动前,确保项目根目录 `.env` 文件中以下配置正确:
|
||||
容器启动前,确保项目根目录 `.env` 已初始化(`APP_KEY`、`JWT_SECRET`、`DB_PREFIX`):
|
||||
|
||||
```ini
|
||||
APP_DEBUG = false
|
||||
|
||||
[APP]
|
||||
SHOW_ERROR_MSG = false
|
||||
|
||||
[DATABASE]
|
||||
; 连接地址(Docker 内部使用服务名 "mysql")
|
||||
HOSTNAME = mysql
|
||||
; 密码(与 .env.docker 中 MYSQL_ROOT_PASSWORD 一致)
|
||||
PASSWORD = Your_Strong_Password_2024
|
||||
|
||||
[CACHE]
|
||||
; 连接地址(Docker 内部使用服务名 "redis")
|
||||
REDIS_HOST = redis
|
||||
; 密码(与 .env.docker 中 REDIS_PASSWORD 一致)
|
||||
REDIS_PASSWORD = Your_Redis_Password_2024
|
||||
|
||||
[FILE]
|
||||
; 上传目录(容器内路径,与 docker-compose uploads_data 卷对应)
|
||||
UPLOAD_DIR = /opt/data/uploads
|
||||
APP_KEY= # 留空,composer setup 的 key:generate 生成
|
||||
JWT_SECRET=<32 字符以上随机值> # 应用启动 fail-close 校验
|
||||
DB_PREFIX=laravel_ # 数据库脚本使用 laravel_ 前缀,必须保留
|
||||
```
|
||||
|
||||
:::tip 数据库连接无需修改
|
||||
`docker-compose.yml` 的 `environment` 块已把 `DB_HOST` 覆盖为 `mysql`、`REDIS_HOST` 覆盖为 `redis`(容器环境变量优先级高于 `.env` 文件),本地 `.env` 保持 `127.0.0.1` 即可与手动部署共用同一份配置。
|
||||
:::
|
||||
|
||||
## 启动部署
|
||||
|
||||
```bash
|
||||
# 1. 配置环境变量
|
||||
# 复制模板并修改密码
|
||||
cp docker/.env.docker docker/.env.docker.local
|
||||
vi docker/.env.docker.local # 修改密码
|
||||
vi docker/.env.docker.local # 修改密码、JWT_SECRET、域名
|
||||
|
||||
# 2. 配置应用 .env
|
||||
cp .env.example .env
|
||||
vi .env # 修改数据库、Redis 连接信息
|
||||
php artisan key:generate # 生成 APP_KEY
|
||||
|
||||
# 3. 构建并启动所有服务
|
||||
docker-compose --env-file docker/.env.docker.local up -d --build
|
||||
docker compose --env-file docker/.env.docker.local up -d --build
|
||||
|
||||
# 4. 查看运行状态
|
||||
docker-compose ps
|
||||
# 4. 查看运行状态(首次 mysql 需导入约 226MB SQL,等 healthy)
|
||||
docker compose ps
|
||||
|
||||
# 5. 查看应用日志(确认无报错)
|
||||
docker-compose logs -f app
|
||||
docker compose logs -f app
|
||||
|
||||
# 6. 验证
|
||||
curl https://your-domain/up
|
||||
curl http://localhost:8000/api/captcha # 返回 code=0 即成功
|
||||
```
|
||||
|
||||
## 常用命令
|
||||
### 首次初始化与数据迁移
|
||||
|
||||
- MySQL 仅在**数据卷为空**时执行 `docker-entrypoint-initdb.d` 中的初始化 SQL;
|
||||
- 已有数据卷不会重复导入,更换 SQL 脚本需先 `docker compose down -v`(**会清空数据**);
|
||||
- 从旧环境迁入已有数据:
|
||||
|
||||
```bash
|
||||
# Linux / Git Bash
|
||||
docker compose exec -T mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" rxthinkcmf.laravel13.elevue' < backup.sql
|
||||
|
||||
# Windows CMD(PowerShell 不支持 < 重定向,用 cmd /c 包裹)
|
||||
cmd /c "docker compose exec -T mysql mysql -uroot -p<密码> rxthinkcmf.laravel13.elevue < backup.sql"
|
||||
```
|
||||
|
||||
## 日常运维
|
||||
|
||||
```bash
|
||||
# --------------------------------------------------------------------------
|
||||
# 代码更新
|
||||
# --------------------------------------------------------------------------
|
||||
git pull
|
||||
docker compose --env-file docker/.env.docker build app
|
||||
docker compose --env-file docker/.env.docker up -d app
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 生命周期管理
|
||||
# --------------------------------------------------------------------------
|
||||
# 启动所有服务(后台运行)
|
||||
docker-compose up -d
|
||||
|
||||
# 停止所有服务(保留数据卷)
|
||||
docker-compose down
|
||||
|
||||
# 停止并删除所有数据卷(⚠️ 清空数据库和上传文件)
|
||||
docker-compose down -v
|
||||
|
||||
# 重建镜像并启动(Dockerfile 或 composer.json 变更后)
|
||||
docker-compose up -d --build
|
||||
|
||||
# 重启单个服务
|
||||
docker-compose restart app
|
||||
docker compose up -d # 启动所有服务(后台运行)
|
||||
docker compose down # 停止所有服务(保留数据卷)
|
||||
docker compose down -v # 停止并删除所有数据卷(⚠️ 清空数据库)
|
||||
docker compose restart app # 重启单个服务(修改 .env 后生效)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 日志排查
|
||||
# --------------------------------------------------------------------------
|
||||
# 查看所有服务日志
|
||||
docker-compose logs -f
|
||||
|
||||
# 查看单个服务日志
|
||||
docker-compose logs -f app
|
||||
docker-compose logs -f nginx
|
||||
docker-compose logs -f mysql
|
||||
docker compose logs -f # 所有服务日志
|
||||
docker compose logs -f app # 应用日志
|
||||
docker compose logs -f nginx # Nginx 日志
|
||||
docker compose logs -f mysql # 数据库日志(首次看导入进度)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 进入容器调试
|
||||
# --------------------------------------------------------------------------
|
||||
# 进入 PHP-FPM 容器
|
||||
docker-compose exec app bash
|
||||
|
||||
# 进入 MySQL 容器
|
||||
docker-compose exec mysql bash
|
||||
|
||||
# 在容器内执行 SQL
|
||||
docker-compose exec mysql mysql -uroot -pYour_Strong_Password_2024 rxthinkcmf.thinkphp6.elevue
|
||||
docker compose exec app bash # 进入 PHP-FPM 容器
|
||||
docker compose exec mysql bash # 进入 MySQL 容器
|
||||
docker compose exec mysql mysql -uroot -p'<密码>' rxthinkcmf.laravel13.elevue
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# 数据库操作
|
||||
# --------------------------------------------------------------------------
|
||||
# 导入 SQL 文件
|
||||
docker-compose exec -T mysql mysql -uroot -pYour_Strong_Password_2024 rxthinkcmf.thinkphp6.elevue < document/mysql/rxthinkcmf.thinkphp6.elevue.sql
|
||||
|
||||
# 导出数据库备份
|
||||
docker-compose exec mysql mysqldump -uroot -pYour_Strong_Password_2024 rxthinkcmf.thinkphp6.elevue > backup_$(date +%Y%m%d).sql
|
||||
docker compose exec -T mysql sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" rxthinkcmf.laravel13.elevue' > backup_$(date +%Y%m%d).sql
|
||||
|
||||
# 导入 SQL 文件
|
||||
docker compose exec -T mysql mysql -uroot -p'<密码>' rxthinkcmf.laravel13.elevue < backup.sql
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# ThinkPHP 命令
|
||||
# Laravel Artisan 命令
|
||||
# --------------------------------------------------------------------------
|
||||
# 数据库迁移
|
||||
docker-compose exec app php think db:migrate
|
||||
|
||||
# 清除运行时缓存
|
||||
docker-compose exec app php think clear
|
||||
|
||||
# 查看路由列表
|
||||
docker-compose exec app php think route:list
|
||||
docker compose exec app php artisan config:cache # 缓存配置(生产建议)
|
||||
docker compose exec app php artisan route:cache # 缓存路由
|
||||
docker compose exec app php artisan migrate --force # 执行迁移
|
||||
docker compose exec app php artisan config:clear # 清除配置缓存
|
||||
docker compose exec app php artisan route:list # 查看路由列表
|
||||
```
|
||||
|
||||
## 生产环境建议
|
||||
:::tip 定时任务
|
||||
项目内置 Cron / Daemon 双模式定时任务(见 [6.11 定时任务](/zh/modules/job.html)),容器化部署时在宿主机配置 Crontab 调用 `docker compose exec app php artisan ...`,或单独以 `app` 镜像运行常驻容器执行任务守护命令。
|
||||
:::
|
||||
|
||||
## 性能调优
|
||||
|
||||
### OPcache(生产建议)
|
||||
|
||||
镜像默认 `opcache.validate_timestamps=1`(便于挂载代码即时生效)。生产环境代码不再变动,建议在 `docker/Dockerfile` 中改为:
|
||||
|
||||
```ini
|
||||
opcache.validate_timestamps = 0 # 代码不再重新检查,性能最优
|
||||
```
|
||||
|
||||
修改后重新构建镜像:
|
||||
|
||||
```bash
|
||||
docker compose --env-file docker/.env.docker build app
|
||||
docker compose --env-file docker/.env.docker up -d app
|
||||
```
|
||||
|
||||
:::warning
|
||||
`validate_timestamps=0` 后修改代码必须重启容器(或重新构建)才会生效。
|
||||
:::
|
||||
|
||||
### PHP-FPM
|
||||
|
||||
镜像使用 `php-fpm` 默认动态进程池。并发较高时按 CPU 核数调整 `www.conf` 的 `pm.max_children`(建议 `(内存 - 系统占用) / 单进程内存`),可通过自定义配置挂载覆盖。
|
||||
|
||||
### MySQL / Redis
|
||||
|
||||
- MySQL 数据在命名卷 `mysql_data`,大表查询配合项目索引策略(见 [4.9 数据库设计](/zh/architecture/database-design.html));
|
||||
- Redis 建议设置 `maxmemory` + 淘汰策略防止内存耗尽——注意 **JWT 会话存储在 Redis**,淘汰策略不当会导致用户掉线。
|
||||
|
||||
### 生产环境建议
|
||||
|
||||
| 配置项 | 建议值 | 说明 |
|
||||
|--------|--------|------|
|
||||
| APP_DEBUG | false | 关闭调试模式,防止 SQL/路径泄露 |
|
||||
| APP_DEBUG | false | 关闭调试模式,防止堆栈/路径泄露 |
|
||||
| MYSQL_ROOT_PASSWORD | 强密码(>=16位) | 包含大小写字母和数字 |
|
||||
| REDIS_PASSWORD | 强密码 | 与数据库密码不同 |
|
||||
| JWT.SECRET | 随机字符串(>=32字节) | 在应用 .env 中配置 |
|
||||
| FILE.UPLOAD_DIR | /opt/data/uploads | 使用命名卷持久化 |
|
||||
| JWT_SECRET | 随机字符串(>=32字符) | `openssl rand -base64 32` |
|
||||
| CORS_ALLOW_ORIGIN | 前端具体域名 | 生产禁止 `*` |
|
||||
| 数据库/Redis 端口 | 注释掉映射 | 容器间通信不需要宿主机映射 |
|
||||
| 数据卷 | 持久化挂载 | 避免容器重启丢失数据 |
|
||||
| Nginx SSL | 443 + 证书 | 生产环境必须启用 HTTPS |
|
||||
|
||||
## 安全加固
|
||||
|
||||
| 项 | 措施 |
|
||||
|----|------|
|
||||
| 调试模式 | `APP_DEBUG=false`(true 会泄露异常堆栈、配置信息) |
|
||||
| JWT 密钥 | 随机生成、不同环境不同密钥、严格保密 |
|
||||
| 数据库端口 | 注释 `docker-compose.yml` 中 mysql/redis 的 `ports` 映射,或绑定 `"127.0.0.1:3306:3306"` |
|
||||
| 跨域 | `CORS_ALLOW_ORIGIN` 显式配置前端域名 |
|
||||
| 敏感文件 | `.dockerignore` 已排除 `.env`、SQL 脚本;`nginx.conf` 禁止访问隐藏文件 |
|
||||
| PHP 执行 | Nginx 仅允许入口 `index.php` 执行,上传目录中的 `.php` 一律 404 |
|
||||
| 默认账号 | 首次登录后立即修改 `admin` 默认密码(见 [6.1 用户管理](/zh/modules/user.html)) |
|
||||
|
||||
## SSL 配置(HTTPS)
|
||||
|
||||
生产环境建议在 Nginx 前增加 SSL 终止,修改 `nginx.conf`:
|
||||
@@ -550,7 +648,7 @@ server {
|
||||
}
|
||||
```
|
||||
|
||||
docker-compose.yml 中增加证书挂载:
|
||||
`docker-compose.yml` 中增加证书挂载:
|
||||
|
||||
```yaml
|
||||
nginx:
|
||||
@@ -560,9 +658,39 @@ nginx:
|
||||
- ./ssl/key.pem:/etc/nginx/ssl/key.pem:ro
|
||||
```
|
||||
|
||||
## 备份与恢复
|
||||
|
||||
```bash
|
||||
# 数据库备份(定时任务执行)
|
||||
docker compose exec -T mysql sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" rxthinkcmf.laravel13.elevue' > backup_$(date +%F).sql
|
||||
|
||||
# 数据库恢复
|
||||
docker compose exec -T mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" rxthinkcmf.laravel13.elevue' < backup_2026-10-01.sql
|
||||
|
||||
# 整卷备份(停机快照)
|
||||
docker compose down
|
||||
docker run --rm -v rxthinkcmf-laravel13_mysql_data:/data -v $(pwd):/backup alpine tar czf /backup/mysql_data.tar.gz -C /data .
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
更多方案见 [11.9 备份与恢复](/zh/deploy/backup.html)。
|
||||
|
||||
## 故障排查
|
||||
|
||||
| 症状 | 排查 | 处理 |
|
||||
|------|------|------|
|
||||
| 启动报 dependency failed to start | `docker compose logs mysql` | 首次导入大 SQL 较慢,等待 healthy;密码错误则 `down -v` 后修正重来 |
|
||||
| 页面 502 Bad Gateway | `docker compose ps` | app 未运行 → `docker compose logs app` 定位崩溃原因 |
|
||||
| 页面 404 | `docker compose logs nginx` | 确认 `docker/nginx.conf` 挂载正确、入口在 `public/` 下 |
|
||||
| 500 且无详情 | `docker compose logs app` | 生产 `APP_DEBUG=false` 时错误细节只在日志中 |
|
||||
| 启动即退出,日志报 JWT_SECRET | `.env` 或 `.env.docker` 密钥 < 32 字符 | 重新生成并重启 |
|
||||
| 存储写入失败 | `storage/`、`bootstrap/cache/` 权限 | 镜像已 chown;挂载宿主机时确认目录对容器可写 |
|
||||
| 备份 SQL 中文乱码 | 导出未指定字符集 | `mysqldump --default-character-set=utf8mb4` |
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [后端部署](/zh/deploy/backend.html) — Nginx/Apache 详细配置
|
||||
- [2.8 Docker 快速体验](/zh/quickstart/docker.html) — 本地一键启动
|
||||
- [后端部署](/zh/deploy/backend.html) — Nginx/Apache 非 Docker 详细配置
|
||||
- [前端部署](/zh/deploy/frontend.html) — Vue3 前端部署
|
||||
- [数据库迁移](/zh/deploy/db-migrate.html) — 多数据库迁移工具
|
||||
- [环境变量参考](/zh/appendix/config-reference.html) — 完整配置项说明
|
||||
- [环境变量参考](/zh/quickstart/env-vars.html) — 完整配置项说明
|
||||
|
||||
@@ -8,19 +8,24 @@
|
||||
|
||||
| 组件 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| PHP | 8.2+ | 必需 |
|
||||
| PHP | 8.3+ | 必需(Laravel 13 要求) |
|
||||
| Laravel | 13.x | 后端框架 |
|
||||
| MySQL | 8.0+ | 主数据库(也支持 PostgreSQL、SQL Server、Oracle、SQLite) |
|
||||
| Redis | 6.0+ | 缓存(可选,推荐) |
|
||||
| Redis | 6.0+ | 缓存 / 会话 / 队列 / JWT 会话存储(**必需**,phpredis 扩展) |
|
||||
| Nginx | 1.18+ | Web 服务器 |
|
||||
| Node.js | 22+ | 前端构建 |
|
||||
| Node.js | 18+(建议 22 LTS) | 前端构建(`ui/` 为 Vite 3;根目录资源构建为 Vite 7) |
|
||||
| Composer | 2.x | PHP 依赖 |
|
||||
| pnpm | 12+ | 前端依赖 |
|
||||
| pnpm | 9+ | 前端依赖(`ui/` 目录,含 pnpm-lock.yaml) |
|
||||
|
||||
:::warning Redis 为强依赖
|
||||
本项目 `.env.example` 默认 `SESSION_DRIVER=redis`、`CACHE_STORE=redis`、`QUEUE_CONNECTION=redis`、`REDIS_CLIENT=phpredis`,JWT 双令牌也依赖 Redis。生产环境必须部署 Redis,否则无法登录、无法缓存、队列不可用。
|
||||
:::
|
||||
|
||||
## 服务器配置建议
|
||||
|
||||
| 规模 | CPU | 内存 | 磁盘 | 说明 |
|
||||
|------|-----|------|------|------|
|
||||
| 小型 | 2核 | 4GB | 50GB | 单机部署,日活 < 1000 |
|
||||
| 小型 | 2核 | 4GB | 50GB | 单机部署,日活 < 1000(数据库初始化导入约 226MB,建议 ≥4GB) |
|
||||
| 中型 | 4核 | 8GB | 100GB | 单机部署,日活 1000~10000 |
|
||||
| 大型 | 8核+ | 16GB+ | 200GB+ | 分离部署,日活 > 10000 |
|
||||
|
||||
@@ -33,7 +38,7 @@
|
||||
│ 单台服务器 │
|
||||
│ │
|
||||
│ Nginx + PHP-FPM + MySQL │
|
||||
│ + Redis(可选) │
|
||||
│ + Redis(必需) │
|
||||
│ + 前端静态文件 │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
@@ -47,8 +52,8 @@
|
||||
│ Nginx(前端 + API 代理) │
|
||||
│ PHP-FPM(多进程) │
|
||||
│ MySQL(主库) │
|
||||
│ Redis(缓存) │
|
||||
│ Supervisor(进程管理) │
|
||||
│ Redis(缓存/队列) │
|
||||
│ Supervisor(队列/守护进程) │
|
||||
└─────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -72,8 +77,23 @@
|
||||
|
||||
## 环境变量规划
|
||||
|
||||
| 环境 | APP_DEBUG | CACHE.DRIVER | JWT.SECRET | CORS.ALLOW_ORIGIN |
|
||||
|------|-----------|-------------|------------|-------------------|
|
||||
| 开发 | true | file | 开发密钥 | * |
|
||||
| 测试 | true | file | 测试密钥 | * |
|
||||
| 生产 | false | redis | 强随机密钥 | 指定域名 |
|
||||
本项目 `.env` 为扁平键名(无分段式配置),核心项规划如下:
|
||||
|
||||
| 环境 | APP_DEBUG | APP_ENV | CACHE_STORE / SESSION_DRIVER | JWT_SECRET | CORS_ALLOW_ORIGIN |
|
||||
|------|-----------|---------|------------------------------|------------|-------------------|
|
||||
| 开发 | true | local | redis | 开发密钥 | * |
|
||||
| 测试 | true | testing | redis | 测试密钥 | * |
|
||||
| 生产 | **false** | **production** | redis | **强随机密钥(≥32 字符)** | **指定域名** |
|
||||
|
||||
生成强随机 JWT 密钥:
|
||||
|
||||
```bash
|
||||
php -r "echo bin2hex(random_bytes(32));"
|
||||
```
|
||||
|
||||
:::tip 其它生产必检项
|
||||
- `DB_PREFIX=laravel_` 与 SQL 脚本表前缀一致,不要随意修改
|
||||
- `FILE_DOMAIN_URL` 留空时按当前请求域名补全文件地址;跨域部署时应配置为前端可访问的文件域名
|
||||
- `TRUSTED_PROXIES` 按反向代理层级配置(默认信任 127.0.0.1 / ::1)
|
||||
- 队列常驻进程:`php artisan queue:work`(生产用 Supervisor 托管)
|
||||
:::
|
||||
|
||||
@@ -8,20 +8,20 @@
|
||||
|
||||
| 依赖 | 版本要求 | 说明 |
|
||||
|------|----------|------|
|
||||
| Node.js | >= 18.0 | JavaScript 运行时 |
|
||||
| pnpm | >= 8.0 | 包管理工具 |
|
||||
| Node.js | >= 14.18(建议 18+,实测 22 LTS) | JavaScript 运行时(`ui/` 为 Vite 3) |
|
||||
| pnpm | >= 9.0 | 包管理工具(`ui/pnpm-lock.yaml`) |
|
||||
| Nginx | >= 1.20 | Web 服务器 |
|
||||
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
# 进入前端项目目录
|
||||
# 进入前端项目目录(注意:前端在 ui/ 子目录)
|
||||
cd ui
|
||||
|
||||
# 安装项目依赖(从 pnpm-lock.yaml 精确安装,确保版本一致)
|
||||
pnpm install
|
||||
|
||||
# 执行生产环境构建(Vite 会压缩代码、Tree-shaking、分包)
|
||||
# 执行生产环境构建(Vite 压缩代码、Tree-shaking、分包 + postBuild 后处理)
|
||||
pnpm build
|
||||
```
|
||||
|
||||
@@ -29,12 +29,16 @@ pnpm build
|
||||
|
||||
### 环境变量配置
|
||||
|
||||
构建前可修改环境变量:
|
||||
构建前可修改 `ui/.env.production`:
|
||||
|
||||
```bash
|
||||
# .env.production — 生产环境构建配置
|
||||
VITE_GLOB_API_URL=/api # API 基础路径(Nginx 代理到后端)
|
||||
VITE_GLOB_API_URL_PREFIX= # API 路径前缀(一般留空)
|
||||
# ui/.env.production — 生产环境构建配置
|
||||
VITE_GLOB_API_URL = # API 基础路径(留空表示同源,由 Nginx 代理)
|
||||
VITE_GLOB_API_URL_PREFIX = /api # 接口前缀(后端路由统一在 /api 下)
|
||||
VITE_GLOB_UPLOAD_URL = # 图片上传地址(跨域部署时配置后端域名)
|
||||
VITE_GLOB_IMG_URL = # 图片前缀地址
|
||||
VITE_DROP_CONSOLE = true # 删除 console 调试语句
|
||||
VITE_BUILD_COMPRESS = 'none' # 构建压缩:gzip / brotli / none
|
||||
```
|
||||
|
||||
## Nginx 配置
|
||||
@@ -81,7 +85,7 @@ server {
|
||||
# -----------------------------------------------------------------
|
||||
# API 反向代理
|
||||
# -----------------------------------------------------------------
|
||||
# 将 /api/ 开头的请求转发到后端 ThinkPHP 服务
|
||||
# 将 /api/ 开头的请求转发到后端 Laravel 服务
|
||||
# proxy_pass 末尾的 / 表示替换匹配的路径前缀
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:8000; # 后端服务地址
|
||||
@@ -123,6 +127,7 @@ nginx -s reload
|
||||
| 静态资源 404 | 路径错误 | 检查 `root` 路径是否正确 |
|
||||
| 白屏 | 构建失败或路径错误 | 检查构建日志和 Nginx 错误日志 |
|
||||
| 样式错乱 | 字体文件加载失败 | 检查字体文件路径和 CORS 配置 |
|
||||
| 登录后接口 401 | 跨域部署时 token 未携带 | 检查 `VITE_GLOB_API_URL` 与后端 `CORS_ALLOW_ORIGIN` 是否一致 |
|
||||
|
||||
## 相关文档
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ 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 注解依赖此配置)
|
||||
opcache.save_comments = 1 ; 保留注释(反射文档注释、调试栈追踪依赖此配置)
|
||||
```
|
||||
|
||||
:::warning OPcache 注意事项
|
||||
@@ -33,8 +33,7 @@ opcache.save_comments = 1 ; 保留注释(ThinkPHP 注解依赖
|
||||
```ini
|
||||
; =============================================================================
|
||||
; PHP-FPM 进程池配置
|
||||
; =============================================================================
|
||||
; 配置路径:/etc/php/8.2/fpm/pool.d/www.conf
|
||||
; 配置路径:/etc/php/8.3/fpm/pool.d/www.conf
|
||||
; 根据服务器内存和并发量调整参数
|
||||
; =============================================================================
|
||||
|
||||
@@ -50,35 +49,46 @@ pm.max_requests = 500 ; 单进程最大请求数(达到后重启,
|
||||
|
||||
```bash
|
||||
# 生产环境安装依赖
|
||||
# --no-dev → 排除开发依赖(symfony/var-dumper、think-trace 等)
|
||||
# --no-dev → 排除开发依赖(phpunit/phpunit、laravel/pint 等)
|
||||
# --optimize-autoloader → 优化自动加载器(生成 classmap,减少文件查找)
|
||||
composer install --no-dev --optimize-autoloader
|
||||
```
|
||||
|
||||
### Laravel 缓存命令
|
||||
|
||||
```bash
|
||||
# 生产环境把配置、路由、视图编译进缓存,避免每次请求重新解析
|
||||
php artisan config:cache
|
||||
php artisan route:cache
|
||||
php artisan view:cache
|
||||
```
|
||||
|
||||
## 缓存层
|
||||
|
||||
### 使用 Redis
|
||||
|
||||
```ini
|
||||
; .env — Redis 缓存配置
|
||||
[CACHE]
|
||||
DRIVER = redis ; 缓存驱动改为 redis(默认为 file)
|
||||
REDIS_HOST = 127.0.0.1 ; Redis 服务器地址
|
||||
REDIS_PORT = 6379 ; Redis 端口
|
||||
REDIS_PASSWORD = your_redis_password ; Redis 密码
|
||||
; .env — Redis 缓存配置(本项目默认即为 redis 驱动)
|
||||
CACHE_STORE=redis ; 缓存驱动
|
||||
SESSION_DRIVER=redis ; 会话驱动
|
||||
QUEUE_CONNECTION=redis ; 队列驱动
|
||||
REDIS_CLIENT=phpredis ; Redis PHP 扩展
|
||||
REDIS_HOST=127.0.0.1 ; Redis 服务器地址
|
||||
REDIS_PORT=6379 ; Redis 端口
|
||||
REDIS_PASSWORD=your_redis_password ; Redis 密码
|
||||
```
|
||||
|
||||
:::tip 缓存效果
|
||||
DictService 和 ParamService 采用两级缓存(请求级 + 持久缓存),使用 Redis 后:
|
||||
- 字典查询:首次查库 + 写入 Redis,后续直接读缓存(1小时过期)
|
||||
- 参数查询:同上
|
||||
- 减少 80%+ 的数据库查询
|
||||
- **DictCacheService(字典)**:两级缓存(请求级 + Laravel Cache),使用 Redis 后首次查库并写入 Redis,后续直接读缓存(TTL 3600 秒 / 1 小时),可减少 80%+ 的字典查询
|
||||
- **ParamService(参数)**:仅请求级缓存(数据量小、变更即时生效,不落持久缓存)
|
||||
:::
|
||||
|
||||
## 数据库层
|
||||
|
||||
### 索引优化
|
||||
|
||||
项目 SQL 脚本已内置大量索引(`uk_tenant_*` 唯一索引、`idx_*` 普通索引,覆盖租户隔离、用户名、手机号、状态、分类等高频查询)。**新增业务表或新增查询字段时**,再按需补充索引:
|
||||
|
||||
```sql
|
||||
-- =============================================================================
|
||||
-- 为常用查询字段添加索引(提升查询速度)
|
||||
@@ -87,16 +97,14 @@ DictService 和 ParamService 采用两级缓存(请求级 + 持久缓存),
|
||||
-- 注意:索引会占用额外存储空间,且降低写入速度,只在高频查询字段上创建
|
||||
-- =============================================================================
|
||||
|
||||
-- 用户表:用户名登录查询、租户隔离查询
|
||||
ALTER TABLE think_user ADD INDEX idx_username (username);
|
||||
ALTER TABLE think_user ADD INDEX idx_tenant_id (tenant_id);
|
||||
-- 新增业务表:租户隔离 + 状态筛选(本项目标准索引命名习惯)
|
||||
ALTER TABLE laravel_example ADD INDEX idx_tenant_status (tenant_id, status);
|
||||
|
||||
-- 文章表:状态筛选、分类筛选
|
||||
ALTER TABLE think_article ADD INDEX idx_status (status);
|
||||
ALTER TABLE think_article ADD INDEX idx_category_id (category_id);
|
||||
-- 操作日志表:按时间范围查询(当前 SQL 脚本未建此索引,日志量大时建议补充)
|
||||
ALTER TABLE laravel_operation_log ADD INDEX idx_create_time (create_time);
|
||||
|
||||
-- 操作日志表:按时间范围查询(最频繁的查询模式)
|
||||
ALTER TABLE think_operation_log ADD INDEX idx_create_time (create_time);
|
||||
-- 用户表:平台侧按用户名直查(租户内查询已有 uk_tenant_username 覆盖)
|
||||
ALTER TABLE laravel_user ADD INDEX idx_username (username);
|
||||
```
|
||||
|
||||
### 慢查询日志
|
||||
@@ -145,15 +153,16 @@ location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
|
||||
|
||||
### CDN 加速
|
||||
|
||||
将静态资源(JS/CSS/图片)部署到 CDN,减轻服务器压力。
|
||||
将静态资源(JS/CSS/图片)部署到 CDN,减轻服务器压力。CDN 场景下注意配置 `.env` 的 `TRUSTED_PROXIES` 以获取真实客户端 IP(见 [11.4 后端部署](/zh/deploy/backend.html))。
|
||||
|
||||
## 性能检查清单
|
||||
|
||||
| 检查项 | 生产环境 | 开发环境 |
|
||||
|--------|----------|----------|
|
||||
| OPcache | 启用 | 可选 |
|
||||
| Redis 缓存 | 推荐 | 可选 |
|
||||
| Redis 缓存 | 必需(缓存/会话/队列) | 必需 |
|
||||
| Laravel 缓存(config/route/view) | 缓存(`php artisan *:cache`) | 清除状态(`*:clear`) |
|
||||
| Gzip 压缩 | 启用 | 可选 |
|
||||
| 慢查询日志 | 启用 | 启用 |
|
||||
| Composer 优化 | `--no-dev --optimize` | 默认 |
|
||||
| Composer 优化 | `--no-dev --optimize-autoloader` | 默认 |
|
||||
| 静态资源缓存 | 30天 | 不缓存 |
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
| 项目 | 操作 | 检查命令 |
|
||||
|------|------|----------|
|
||||
| JWT 密钥 | `.env` 中 `JWT.SECRET` 修改为强随机字符串 | `grep JWT.SECRET .env` |
|
||||
| 调试模式 | `.env` 中 `APP_DEBUG = false` | `grep APP_DEBUG .env` |
|
||||
| 错误信息 | `.env` 中 `SHOW_ERROR_MSG = false` | `grep SHOW_ERROR_MSG .env` |
|
||||
| CORS | `.env` 中 `CORS.ALLOW_ORIGIN` 限制为实际域名 | `grep CORS .env` |
|
||||
| JWT 密钥 | `.env` 中 `JWT_SECRET` 修改为强随机字符串(≥32 字符,缺失/过短时服务拒绝签发令牌,fail-close) | `grep JWT_SECRET .env` |
|
||||
| 调试模式 | `.env` 中 `APP_DEBUG=false` | `grep APP_DEBUG .env` |
|
||||
| 运行环境 | `.env` 中 `APP_ENV=production` | `grep APP_ENV .env` |
|
||||
| CORS | `.env` 中 `CORS_ALLOW_ORIGIN` 限制为实际域名 | `grep CORS_ALLOW_ORIGIN .env` |
|
||||
| 数据库密码 | 修改默认 root 密码 | `mysql -u root -p` |
|
||||
| Redis 密码 | 设置 requirepass | `redis-cli CONFIG GET requirepass` |
|
||||
| HTTPS | 启用 SSL 证书 | `curl -I https://your-domain.com` |
|
||||
@@ -76,13 +76,13 @@ server_tokens off;
|
||||
; =============================================================================
|
||||
; php.ini 生产环境安全配置
|
||||
; =============================================================================
|
||||
; 配置路径:/etc/php/8.2/fpm/php.ini
|
||||
; 生效命令:sudo systemctl restart php8.2-fpm
|
||||
; 配置路径:/etc/php/8.3/fpm/php.ini
|
||||
; 生效命令:sudo systemctl restart php8.3-fpm
|
||||
; =============================================================================
|
||||
|
||||
expose_php = Off ; 隐藏 PHP 版本号(防止针对性攻击)
|
||||
display_errors = Off ; 不向浏览器显示错误(防止 SQL/路径泄露)
|
||||
log_errors = On ; 记录错误到日志文件(便于排查)
|
||||
log_errors = On ; 记录错误到日志文件(Laravel 日志在 storage/logs/)
|
||||
allow_url_fopen = Off ; 禁止 fopen 打开远程 URL(防 SSRF)
|
||||
disable_functions = exec,passthru,shell_exec,system,proc_open ; 禁用危险系统函数
|
||||
```
|
||||
@@ -97,18 +97,19 @@ chmod -R 755 /www/api/ # 目录 755,文件自动
|
||||
chown -R www-data:www-data /www/api/ # owner 设为 Web 服务器用户
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 运行时目录(必须可写 — ThinkPHP 缓存、日志、编译模板)
|
||||
# 运行时目录(必须可写 — Laravel 缓存、日志、编译视图)
|
||||
# -----------------------------------------------------------------------------
|
||||
chmod -R 777 /www/api/runtime/ # 777 确保 PHP-FPM 可写入
|
||||
chmod -R 777 /www/api/storage/ # 777 确保 PHP-FPM 可写入
|
||||
chmod -R 777 /www/api/bootstrap/cache/ # 配置/路由缓存写入位置
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 上传目录(必须可写 — 用户上传文件存储位置)
|
||||
# -----------------------------------------------------------------------------
|
||||
chmod -R 755 /opt/data/uploads/ # 目录可写
|
||||
chown -R www-data:www-data /opt/data/uploads/ # owner 设为 Web 服务器用户
|
||||
chmod -R 755 /www/api/public/uploads/ # 目录可写
|
||||
chown -R www-data:www-data /www/api/public/uploads/ # owner 设为 Web 服务器用户
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# .env 文件(仅 owner 可读 — 包含数据库密码等敏感信息)
|
||||
# .env 文件(仅 owner 可读 — 包含数据库密码、JWT 密钥等敏感信息)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 600 = owner 可读写,group/others 无权限
|
||||
chmod 600 /www/api/.env
|
||||
@@ -132,8 +133,8 @@ ALTER USER 'root'@'localhost' IDENTIFIED BY 'strong_password_here';
|
||||
CREATE USER 'rxthinkcmf_app'@'localhost' IDENTIFIED BY 'app_password';
|
||||
|
||||
-- 授权应用用户只能访问项目数据库(最小权限原则)
|
||||
-- rxthinkcmf.thinkphp6.elevue.* → 该项目数据库的所有表
|
||||
GRANT ALL PRIVILEGES ON `rxthinkcmf.thinkphp6.elevue`.* TO 'rxthinkcmf_app'@'localhost';
|
||||
-- rxthinkcmf.laravel13.elevue.* → 该项目数据库的所有表
|
||||
GRANT ALL PRIVILEGES ON `rxthinkcmf.laravel13.elevue`.* TO 'rxthinkcmf_app'@'localhost';
|
||||
FLUSH PRIVILEGES; -- 刷新权限使配置生效
|
||||
|
||||
-- 禁止远程 root 登录(只允许本地连接)
|
||||
@@ -163,6 +164,10 @@ rename-command FLUSHDB "" ; 禁用 FLUSHDB(清空当前数
|
||||
rename-command CONFIG "" ; 禁用 CONFIG(防止运行时修改配置)
|
||||
```
|
||||
|
||||
:::warning Redis 承载关键状态
|
||||
本项目的会话、缓存、队列和 JWT 令牌状态均存储在 Redis 中,Redis 泄露等同于会话泄露。除密码外,还应限制网络访问(安全组 / bind 内网),并避免与其它业务共用实例。
|
||||
:::
|
||||
|
||||
## 安全检查脚本
|
||||
|
||||
```bash
|
||||
@@ -179,11 +184,10 @@ echo "=== 安全检查 ==="
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 APP_DEBUG 是否关闭
|
||||
# -----------------------------------------------------------------------------
|
||||
# grep "APP_DEBUG" .env → 从 .env 文件中提取 APP_DEBUG 行
|
||||
# grep -v "#" → 排除注释行
|
||||
# cut -d= -f2 → 以 = 为分隔符取第 2 部分(值)
|
||||
# tr -d ' ' → 去除空格
|
||||
debug=$(grep "APP_DEBUG" .env | grep -v "#" | cut -d= -f2 | tr -d ' ')
|
||||
# grep "^APP_DEBUG" .env → 从 .env 中取 APP_DEBUG 行(^ 锚定行首,排除注释)
|
||||
# cut -d= -f2 → 以 = 为分隔符取第 2 部分(值)
|
||||
# tr -d ' ' → 去除空格
|
||||
debug=$(grep "^APP_DEBUG" .env | cut -d= -f2 | tr -d ' ')
|
||||
if [ "$debug" = "true" ]; then
|
||||
echo "❌ APP_DEBUG 未关闭(生产环境必须为 false)"
|
||||
else
|
||||
@@ -191,14 +195,12 @@ else
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 JWT 密钥长度
|
||||
# 检查 JWT 密钥长度(本项目 .env 为扁平键名 JWT_SECRET)
|
||||
# -----------------------------------------------------------------------------
|
||||
# sed -n '/\[JWT\]/,/^\[/p' → 提取 .env 中 [JWT] 到下一个 [...] 之间的内容
|
||||
# grep "^SECRET" → 取 SECRET 行
|
||||
# ${#secret} → 获取字符串长度
|
||||
secret=$(sed -n '/\[JWT\]/,/^\[/p' .env | grep "^SECRET" | cut -d= -f2 | tr -d ' ')
|
||||
# ${#secret} → 获取字符串长度
|
||||
secret=$(grep "^JWT_SECRET" .env | cut -d= -f2 | tr -d ' ')
|
||||
if [ ${#secret} -lt 32 ]; then
|
||||
echo "❌ JWT 密钥太短(建议32字节以上,当前 ${#secret} 字符)"
|
||||
echo "❌ JWT 密钥太短(建议 32 字符以上,当前 ${#secret} 字符)"
|
||||
else
|
||||
echo "✓ JWT 密钥长度足够(${#secret} 字符)"
|
||||
fi
|
||||
@@ -206,7 +208,7 @@ fi
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 CORS 是否允许所有来源
|
||||
# -----------------------------------------------------------------------------
|
||||
cors=$(sed -n '/\[CORS\]/,/^\[/p' .env | grep "^ALLOW_ORIGIN" | cut -d= -f2 | tr -d ' ')
|
||||
cors=$(grep "^CORS_ALLOW_ORIGIN" .env | cut -d= -f2 | tr -d ' ')
|
||||
if [ "$cors" = "*" ]; then
|
||||
echo "⚠ CORS 允许所有来源(生产环境建议限制为实际域名)"
|
||||
else
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
:::tip 排查思路
|
||||
遇到问题时,按以下顺序排查:
|
||||
1. 查看 PHP 错误日志(`/var/log/php_errors.log`)
|
||||
2. 查看 Nginx 错误日志(`/var/log/nginx/error.log`)
|
||||
1. 查看应用日志(`storage/logs/laravel.log`,或实时输出 `php artisan pail`)
|
||||
2. 查看 PHP-FPM / Nginx 错误日志(`/var/log/nginx/error.log`)
|
||||
3. 查看浏览器控制台(F12)
|
||||
4. 检查 `.env` 配置是否正确
|
||||
:::
|
||||
@@ -19,29 +19,32 @@ PHP-FPM 未启动或配置错误:
|
||||
# 检查 PHP-FPM 服务状态
|
||||
# -----------------------------------------------------------------------------
|
||||
# status → 显示服务是否正在运行、主进程 PID、内存占用等
|
||||
sudo systemctl status php8.2-fpm
|
||||
sudo systemctl status php8.3-fpm
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 重启 PHP-FPM(最常见的修复方式)
|
||||
# -----------------------------------------------------------------------------
|
||||
# restart → 停止后重新启动,所有正在处理的请求会被中断
|
||||
sudo systemctl restart php8.2-fpm
|
||||
sudo systemctl restart php8.3-fpm
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 实时查看 PHP-FPM 错误日志(Ctrl+C 退出)
|
||||
# -----------------------------------------------------------------------------
|
||||
# -f → follow 模式,持续输出新增日志
|
||||
sudo tail -f /var/log/php8.2-fpm.log
|
||||
sudo tail -f /var/log/php8.3-fpm.log
|
||||
```
|
||||
|
||||
### 500 Internal Server Error
|
||||
|
||||
```bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# 查看 PHP 错误日志(定位 PHP 脚本执行错误)
|
||||
# 查看 Laravel 应用日志(首选 — 记录了异常堆栈)
|
||||
# -----------------------------------------------------------------------------
|
||||
# tail -f → 实时输出新增日志行
|
||||
sudo tail -f /var/log/php_errors.log
|
||||
tail -f /www/api/storage/logs/laravel.log
|
||||
|
||||
# 或使用 Pail 实时查看(开发/排障更友好)
|
||||
cd /www/api && php artisan pail
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 查看 Nginx 错误日志(定位 Nginx 层错误)
|
||||
@@ -49,10 +52,11 @@ sudo tail -f /var/log/php_errors.log
|
||||
sudo tail -f /var/log/nginx/error.log
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查运行时目录权限(500 错误常见原因)
|
||||
# 检查目录权限(500 错误最常见原因)
|
||||
# -----------------------------------------------------------------------------
|
||||
# -la → 显示详细信息(包括隐藏文件)
|
||||
ls -la /www/api/runtime/
|
||||
ls -la /www/api/storage/
|
||||
ls -la /www/api/bootstrap/cache/
|
||||
```
|
||||
|
||||
### 404 Not Found
|
||||
@@ -60,12 +64,12 @@ ls -la /www/api/runtime/
|
||||
Nginx URL 重写配置错误:
|
||||
|
||||
```nginx
|
||||
# 检查 try_files 或 rewrite 规则
|
||||
# 检查 try_files 规则
|
||||
# $uri → 当前请求的文件路径
|
||||
# $uri/ → 当前请求的目录路径
|
||||
# /index.php?s=$uri&$args → 回退到 ThinkPHP 入口,传递原始路径和参数
|
||||
# /index.php?$query_string → 回退到 Laravel 入口,传递原始查询参数
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?s=$uri&$args;
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -97,7 +101,7 @@ mysql -u root -p -e "SELECT user, host FROM mysql.user;"
|
||||
# ON `数据库`.* → 指定数据库的所有表
|
||||
# TO 'root'@'%' → 允许从任意主机连接的 root 用户
|
||||
# IDENTIFIED BY → 设置密码
|
||||
mysql -u root -proot -e "GRANT ALL ON \`rxthinkcmf.thinkphp6.elevue\`.* TO 'root'@'%' IDENTIFIED BY 'root';"
|
||||
mysql -u root -proot -e "GRANT ALL ON \`rxthinkcmf.laravel13.elevue\`.* TO 'root'@'%' IDENTIFIED BY 'root';"
|
||||
mysql -u root -p -e "FLUSH PRIVILEGES;" # 刷新权限使配置生效
|
||||
```
|
||||
|
||||
@@ -112,7 +116,7 @@ sudo systemctl status postgresql
|
||||
# -----------------------------------------------------------------------------
|
||||
# 测试连接(-U 指定用户,-d 指定数据库,-c 执行 SQL)
|
||||
# -----------------------------------------------------------------------------
|
||||
psql -U postgres -d rxthinkcmf.thinkphp6.elevue -c "SELECT 1;"
|
||||
psql -U postgres -d rxthinkcmf.laravel13.elevue -c "SELECT 1;"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查客户端认证配置(pg_hba.conf 控制哪些 IP 可以连接)
|
||||
@@ -132,14 +136,14 @@ sudo systemctl restart postgresql
|
||||
# 检查 SQLite 数据库文件是否存在
|
||||
# -----------------------------------------------------------------------------
|
||||
# -la → 显示文件大小、权限、修改时间
|
||||
ls -la /www/api/runtime/database.sqlite
|
||||
ls -la /www/api/database/database.sqlite
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 修复文件权限(确保 Web 服务器用户可读写)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 664 → owner/group 可读写,others 只读
|
||||
chmod 664 /www/api/runtime/database.sqlite
|
||||
chown www-data:www-data /www/api/runtime/database.sqlite
|
||||
chmod 664 /www/api/database/database.sqlite
|
||||
chown www-data:www-data /www/api/database/database.sqlite
|
||||
```
|
||||
|
||||
### SQL Server 连接失败
|
||||
@@ -169,14 +173,41 @@ php -m | grep pdo_sqlsrv # 查找 pdo_sqlsrv 扩展
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# MySQL:通过 mysql 命令导入 SQL 文件
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue < document/mysql/rxthinkcmf.thinkphp6.elevue.sql
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue < document/mysql/rxthinkcmf.laravel13.elevue.sql
|
||||
|
||||
# PostgreSQL:通过 psql 命令导入 SQL 文件
|
||||
# -U 指定用户,-d 指定数据库,-f 指定 SQL 文件
|
||||
psql -U postgres -d rxthinkcmf.thinkphp6.elevue -f document/postgresql/rxthinkcmf.thinkphp6.elevue.sql
|
||||
psql -U postgres -d rxthinkcmf.laravel13.elevue -f document/postgresql/rxthinkcmf.laravel13.elevue.sql
|
||||
|
||||
# SQLite:通过 sqlite3 命令导入 SQL 文件
|
||||
sqlite3 /www/api/runtime/database.sqlite < document/sqlite/rxthinkcmf.thinkphp6.elevue.sql
|
||||
sqlite3 /www/api/database/database.sqlite < document/sqlite/rxthinkcmf.laravel13.elevue.sql
|
||||
```
|
||||
|
||||
:::info 本项目无 migration 建表
|
||||
`database/migrations/` 为空,表结构只能由 `document/` 下的 SQL 脚本导入,`php artisan migrate` 不会创建业务表。
|
||||
:::
|
||||
|
||||
## Redis 问题
|
||||
|
||||
### Redis 连接失败(登录失败 / 缓存不生效 / 队列不消费)
|
||||
|
||||
```bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 Redis 服务状态
|
||||
# -----------------------------------------------------------------------------
|
||||
sudo systemctl status redis
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 测试连接与密码
|
||||
# -----------------------------------------------------------------------------
|
||||
redis-cli ping # 期望返回 PONG
|
||||
redis-cli -a your_redis_password ping # 设置了 requirepass 时需带密码
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 .env 配置(本项目为扁平键名)
|
||||
# -----------------------------------------------------------------------------
|
||||
grep "^REDIS_" /www/api/.env # REDIS_HOST / REDIS_PORT / REDIS_PASSWORD / REDIS_CLIENT
|
||||
grep "^CACHE_STORE\|^SESSION_DRIVER\|^QUEUE_CONNECTION" /www/api/.env
|
||||
```
|
||||
|
||||
## PHP 问题
|
||||
@@ -188,18 +219,20 @@ sqlite3 /www/api/runtime/database.sqlite < document/sqlite/rxthinkcmf.thinkphp6.
|
||||
# 查看已安装的 PHP 扩展列表
|
||||
# -----------------------------------------------------------------------------
|
||||
php -m # 列出所有已加载的扩展
|
||||
php -m | grep redis # 确认 phpredis 已安装(必需)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 安装缺失的扩展(按数据库类型选择)
|
||||
# -----------------------------------------------------------------------------
|
||||
sudo apt install php8.2-mysql # MySQL 驱动(pdo_mysql)
|
||||
# sudo apt install php8.2-pgsql # PostgreSQL 驱动(取消注释以安装)
|
||||
# sudo apt install php8.2-sqlite3 # SQLite 驱动(取消注释以安装)
|
||||
sudo apt install php8.3-mysql # MySQL 驱动(pdo_mysql)
|
||||
# sudo apt install php8.3-pgsql # PostgreSQL 驱动(取消注释以安装)
|
||||
# sudo apt install php8.3-sqlite3 # SQLite 驱动(取消注释以安装)
|
||||
sudo apt install php8.3-redis # Redis 扩展(缓存/会话/队列必需)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 重启 PHP-FPM 使新扩展生效
|
||||
# -----------------------------------------------------------------------------
|
||||
sudo systemctl restart php8.2-fpm
|
||||
sudo systemctl restart php8.3-fpm
|
||||
```
|
||||
|
||||
### 内存不足
|
||||
@@ -230,16 +263,17 @@ sudo chown -R www-data:www-data /www/api/
|
||||
sudo chmod -R 755 /www/api/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 修复运行时目录(必须可写 — ThinkPHP 缓存、日志、编译模板)
|
||||
# 修复运行时目录(必须可写 — Laravel 缓存、日志、编译视图)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 777 = 所有人可读写执行(仅限运行时目录,不要用于项目根目录)
|
||||
sudo chmod -R 777 /www/api/runtime/
|
||||
sudo chmod -R 777 /www/api/storage/
|
||||
sudo chmod -R 777 /www/api/bootstrap/cache/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 修复上传目录(必须可写 — 用户上传文件存储位置)
|
||||
# -----------------------------------------------------------------------------
|
||||
sudo chmod -R 755 /opt/data/uploads/
|
||||
sudo chown -R www-data:www-data /opt/data/uploads/
|
||||
sudo chmod -R 755 /www/api/public/uploads/
|
||||
sudo chown -R www-data:www-data /www/api/public/uploads/
|
||||
```
|
||||
|
||||
## 业务问题
|
||||
@@ -255,10 +289,9 @@ sudo chown -R www-data:www-data /opt/data/uploads/
|
||||
curl -H "Authorization: Bearer <token>" http://localhost:8000/api/index/getUser
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 JWT 密钥配置
|
||||
# 检查 JWT 密钥配置(缺失或过短会 fail-close,拒绝签发/校验令牌)
|
||||
# -----------------------------------------------------------------------------
|
||||
# 确认 .env 中的 JWT.SECRET 与后端代码一致
|
||||
grep JWT.SECRET .env
|
||||
grep "^JWT_SECRET" /www/api/.env
|
||||
```
|
||||
|
||||
### 403 禁止访问
|
||||
@@ -267,14 +300,14 @@ grep JWT.SECRET .env
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查用户角色分配(用户是否分配了角色)
|
||||
# -----------------------------------------------------------------------------
|
||||
# think_user_role 表存储用户与角色的关联关系
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue -e "SELECT * FROM think_user_role WHERE user_id=1;"
|
||||
# laravel_user_role 表存储用户与角色的关联关系
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue -e "SELECT * FROM laravel_user_role WHERE user_id=1;"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查角色权限(角色是否分配了菜单权限)
|
||||
# -----------------------------------------------------------------------------
|
||||
# think_role_menu 表存储角色与菜单的关联关系
|
||||
mysql -u root -proot rxthinkcmf.thinkphp6.elevue -e "SELECT * FROM think_role_menu WHERE role_id=1;"
|
||||
# laravel_role_menu 表存储角色与菜单的关联关系
|
||||
mysql -u root -proot rxthinkcmf.laravel13.elevue -e "SELECT * FROM laravel_role_menu WHERE role_id=1;"
|
||||
```
|
||||
|
||||
### 文件上传失败
|
||||
@@ -284,7 +317,7 @@ mysql -u root -proot rxthinkcmf.thinkphp6.elevue -e "SELECT * FROM think_role_me
|
||||
# 检查上传目录权限和空间
|
||||
# -----------------------------------------------------------------------------
|
||||
# -la → 显示详细信息(权限、大小、修改时间)
|
||||
ls -la /opt/data/uploads/
|
||||
ls -la /www/api/public/uploads/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 PHP 上传限制配置
|
||||
@@ -293,6 +326,9 @@ ls -la /opt/data/uploads/
|
||||
# grep → 过滤出上传相关的配置项
|
||||
php -i | grep upload_max_filesize # 单文件最大上传大小
|
||||
php -i | grep post_max_size # POST 请求最大大小
|
||||
|
||||
# 同时检查 .env 中的 FILE_MAX_SIZE(MB)与白名单 FILE_EXT
|
||||
grep "^FILE_" /www/api/.env
|
||||
```
|
||||
|
||||
### Token 频繁过期
|
||||
@@ -301,10 +337,10 @@ php -i | grep post_max_size # POST 请求最大大小
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 JWT Token 过期时间配置
|
||||
# -----------------------------------------------------------------------------
|
||||
# grep → 从 .env 文件中提取 ACCESS_TTL 配置值
|
||||
grep JWT.ACCESS_TTL .env
|
||||
# 默认 7200 秒(2 小时),可在 .env 中调整
|
||||
# 如果需要更长的登录状态,增大此值或使用 refresh_token 机制
|
||||
# grep → 从 .env 文件中提取过期时间配置值
|
||||
grep "^JWT_ACCESS_TTL\|^JWT_REFRESH_TTL" /www/api/.env
|
||||
# JWT_ACCESS_TTL 默认 7200 秒(2 小时),JWT_REFRESH_TTL 默认 604800 秒(7 天)
|
||||
# 可在 .env 中调整,改后重启 PHP-FPM 或 php artisan config:clear
|
||||
```
|
||||
|
||||
### 日志中 IP 显示 127.0.0.1
|
||||
@@ -313,11 +349,11 @@ grep JWT.ACCESS_TTL .env
|
||||
|
||||
```bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# 第 1 步:检查 .env 中是否配置了 PROXY_IPS
|
||||
# 第 1 步:检查 .env 中是否配置了受信代理
|
||||
# -----------------------------------------------------------------------------
|
||||
grep PROXY_IPS .env
|
||||
grep "^TRUSTED_PROXIES" /www/api/.env
|
||||
# 如果为空或未配置,添加受信代理 IP(以腾讯云 CDN 为例):
|
||||
# PROXY_IPS = 127.0.0.1,::1,101.226.0.0/15,180.101.0.0/16,182.254.0.0/16
|
||||
# TRUSTED_PROXIES=127.0.0.1,::1,101.226.0.0/15,180.101.0.0/16,182.254.0.0/16
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 第 2 步:检查 Nginx 是否错误覆盖了代理头
|
||||
@@ -330,9 +366,9 @@ grep PROXY_IPS .env
|
||||
grep -r "fastcgi_param.*REMOTE_ADDR\|fastcgi_param.*X_REAL_IP\|fastcgi_param.*X_FORWARDED" /etc/nginx/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 第 3 步:清除缓存并重载
|
||||
# 第 3 步:清除配置缓存并重载
|
||||
# -----------------------------------------------------------------------------
|
||||
rm -rf runtime/*
|
||||
cd /www/api && php artisan config:clear
|
||||
nginx -s reload
|
||||
```
|
||||
|
||||
@@ -356,7 +392,7 @@ sudo systemctl status cron
|
||||
# 手动执行任务(验证命令是否能正常运行)
|
||||
# -----------------------------------------------------------------------------
|
||||
# cd /www/api → 切换到项目目录(crontab 环境变量不完整,需手动 cd)
|
||||
cd /www/api && php think job:run
|
||||
cd /www/api && php artisan job:run
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 查看 cron 执行日志(排查任务是否被触发)
|
||||
@@ -376,9 +412,14 @@ sudo tail -f /var/log/syslog | grep CRON
|
||||
ps aux | grep job:run
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 检查 Daemon 守护进程
|
||||
# 检查 Daemon 守护进程(常驻调度器,与 crontab 二选一即可)
|
||||
# -----------------------------------------------------------------------------
|
||||
ps aux | grep job:daemon
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# 停止守护进程(通过锁文件 storage/app/job_daemon.lock 退出)
|
||||
# -----------------------------------------------------------------------------
|
||||
cd /www/api && php artisan job:daemon --stop
|
||||
```
|
||||
|
||||
## 前端问题
|
||||
@@ -413,7 +454,7 @@ sudo nginx -t
|
||||
# 清理并重新安装依赖(修复依赖冲突或缓存损坏)
|
||||
# -----------------------------------------------------------------------------
|
||||
cd ui
|
||||
rm -rf node_modules pnpm-lock.yaml # 删除依赖目录和锁文件
|
||||
pnpm install # 重新安装所有依赖
|
||||
pnpm build # 重新构建
|
||||
rm -rf node_modules # 删除依赖目录(锁文件 pnpm-lock.yaml 保留以保证版本一致)
|
||||
pnpm install --force # 重新安装所有依赖
|
||||
pnpm build # 重新构建
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user