Files
rxthinkcmf-wiki/RXThinkCMF_Laravel13_NaiveVue/zh/deploy/docker.md
T
2026-10-11 19:06:33 +08:00

697 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 11.6 Docker 生产部署
:::tip 概述
本节提供基于 Docker Compose 的生产环境部署方案,包含 **Nginx 反向代理**、**PHP-FPM 应用**、**MySQL 数据库**和 **Redis 缓存**四个服务的容器编排配置。所有脚本均带详细注释,适合快速搭建生产环境,也便于 CI/CD 集成。本地快速体验请先阅读 [2.8 Docker 快速体验](/zh/quickstart/docker.html)。
:::
## 架构说明
```text
浏览器 → 宿主机:8000 → [Nginx 容器:80] → [PHP-FPM 容器:9000] → Laravel 应用
↕
[MySQL 容器:3306] + [Redis 容器:6379]
```
- **Nginx**:监听 80 端口,处理 HTTP 请求、URL 重写、静态资源缓存
- **PHP-FPM**:监听 9000 端口,执行 PHP 代码
- **MySQL**:数据库服务,数据持久化到 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`(见「性能调优」) |
## 前置要求
| 依赖 | 版本要求 | 说明 |
|------|----------|------|
| 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) |
## 文件结构
```text
RXThinkCMF_Laravel13_NaiveVue/
├── docker/
│ ├── Dockerfile # PHP-FPM 应用镜像定义
│ ├── nginx.conf # Nginx 站点配置
│ └── .env.docker # Docker 环境变量(密码等敏感信息)
├── docker-compose.yml # 容器编排配置(放在项目根目录)
├── .dockerignore # 构建上下文排除(.env、vendor、SQL 等)
├── .env # 应用配置(Laravel 读取)
└── ...
```
## Dockerfile
```dockerfile
# =============================================================================
# Dockerfile — PHP-FPM 应用镜像(RXThinkCMF Laravel13)
# =============================================================================
# 基础镜像:PHP 8.3 + FPM(FastCGI 进程管理器)
# 构建命令:docker compose build app
# 运行方式:由 Nginx 容器通过 FastCGI 协议调用本容器的 9000 端口
# =============================================================================
FROM php:8.3-fpm
# -----------------------------------------------------------------------------
# 1. 安装系统依赖
# -----------------------------------------------------------------------------
# PHP 扩展编译需要的 C 库和工具,安装后清理 apt 缓存减小镜像体积
RUN apt-get update && apt-get install -y --no-install-recommends \
libpng-dev \ # GD 扩展 — PNG 支持
libjpeg-dev \ # GD 扩展 — JPEG 支持
libfreetype6-dev \ # GD 扩展 — 字体渲染(验证码依赖)
libzip-dev \ # zip 扩展依赖
zip \ # Composer 安装依赖包时可能用到
unzip \ # Composer 解压依赖包
&& rm -rf /var/lib/apt/lists/* # 清理 apt 缓存,减小镜像体积
# -----------------------------------------------------------------------------
# 2. 安装 PHP 扩展
# -----------------------------------------------------------------------------
# 项目必需扩展(根据 composer.json 和 config/ 推导):
# pdo_mysql — MySQL 数据库驱动(config/database.php 使用)
# mbstring — 多字节字符串处理(Laravel 框架依赖,composer 平台检查)
# gd — 图片处理(验证码生成、图片缩放)
# bcmath — 高精度数学运算(phpspreadsheet 依赖)
# zip — ZIP 压缩(phpspreadsheet 读写 xlsx 依赖)
# redis — Redis 扩展(phpredis:缓存/会话/队列/JWT 会话均依赖)
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
mbstring \
gd \
bcmath \
zip \
&& pecl install redis \
&& docker-php-ext-enable redis
# -----------------------------------------------------------------------------
# 3. 安装 Composer
# -----------------------------------------------------------------------------
# 从官方镜像复制 composer 二进制文件,避免重复安装
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# -----------------------------------------------------------------------------
# 4. 配置 PHP 生产环境参数
# -----------------------------------------------------------------------------
# 使用 php.ini-production 作为基础,追加项目所需配置
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
# 生产环境追加配置:内存、超时、上传、时区、OPcache 等
RUN echo '\n\
; ====== 生产环境追加配置(Docker 自动生成) ====== \n\
\n\
; 关闭错误显示,防止敏感信息泄露到前端\ndisplay_errors = Off\n\
error_reporting = E_ALL & ~E_NOTICE & ~E_DEPRECATED\n\
\n\
; 内存与超时\n\
memory_limit = 256M\n\
max_execution_time = 60\n\
max_input_time = 60\n\
\n\
; 文件上传(与 .env 中 FILE_MAX_SIZE 配合)\n\
upload_max_filesize = 50M\n\
post_max_size = 50M\n\
max_file_uploads = 20\n\
\n\
; 时区(与应用时区一致)\n\
date.timezone = Asia/Shanghai\n\
\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 = 1\n\
opcache.revalidate_freq = 0\n\
opcache.save_comments = 1\n\
' >> "$PHP_INI_DIR/php.ini"
# -----------------------------------------------------------------------------
# 5. 设置工作目录
# -----------------------------------------------------------------------------
WORKDIR /var/www/html
# -----------------------------------------------------------------------------
# 6. 复制项目文件并安装依赖
# -----------------------------------------------------------------------------
# 先复制 composer 文件,利用 Docker 层缓存 ——
# 只要 composer.json / composer.lock 没变就不重新安装依赖
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-interaction
# 再复制全部项目文件(.env、vendor、node_modules 已被 .dockerignore 排除)
COPY . .
# -----------------------------------------------------------------------------
# 7. 设置 Laravel 可写目录权限
# -----------------------------------------------------------------------------
# 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. 暴露端口并启动
# -----------------------------------------------------------------------------
# 9000 是 PHP-FPM 的 FastCGI 监听端口,Nginx 通过此端口转发请求
EXPOSE 9000
CMD ["php-fpm"]
```
## Nginx 配置
```nginx
# =============================================================================
# Nginx 配置 — RXThinkCMF Laravel13 反向代理
# =============================================================================
# 用途:Docker 容器内 Nginx 服务,将 HTTP 请求转发给 PHP-FPM 处理
# 挂载方式:docker-compose 中 volumes 映射到 /etc/nginx/conf.d/default.conf
# =============================================================================
server {
# 监听容器内 80 端口(宿主机通过 docker-compose ports 映射到 8000)
listen 80;
server_name localhost;
# 网站根目录指向 Laravel 公开目录
# 容器内代码挂载在 /var/www/html,入口文件在 public/index.php
root /var/www/html/public;
index index.php;
# -----------------------------------------------------------------
# URL 重写(Laravel 路由)
# -----------------------------------------------------------------
# 真实存在的文件/目录直接返回,其余请求全部交给 public/index.php,
# 由 Laravel 路由解析(如 /api/user/page → index.php 处理)
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# -----------------------------------------------------------------
# PHP-FPM 处理(仅入口 index.php 可执行)
# -----------------------------------------------------------------
# "app" 是 docker-compose 中 PHP-FPM 服务的名称,Docker 内部 DNS 自动解析
location = /index.php {
fastcgi_pass app:9000; # 转发到 PHP-FPM 容器的 9000 端口
fastcgi_index index.php; # 默认索引文件
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; # 引入标准 FastCGI 参数
# 超时设置(秒),防止长请求被 Nginx 提前断开
fastcgi_read_timeout 300;
fastcgi_send_timeout 300;
}
# 其余 .php 文件(含上传目录、storage 目录)一律 404
# 防止恶意文件上传后被执行 —— 只有入口 index.php 能够运行
location ~ \.php$ {
return 404;
}
# -----------------------------------------------------------------
# 安全规则:禁止访问隐藏文件(如 .env、.git、.htaccess)
# -----------------------------------------------------------------
location ~ /\. {
deny all;
}
# -----------------------------------------------------------------
# 静态资源缓存
# -----------------------------------------------------------------
# 常见静态文件类型设置 30 天浏览器缓存,减少重复请求
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# -----------------------------------------------------------------
# Gzip 压缩
# -----------------------------------------------------------------
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
gzip_min_length 1024; # 小于 1KB 的响应不压缩(压缩收益低)
gzip_comp_level 5; # 压缩级别 1-9,5 为性能与压缩率的平衡点
}
```
## docker-compose.yml
:::tip 与实际文件的关系
项目根目录已内置 `docker-compose.yml`,支持两种模式:
- **快速体验**:`docker compose up -d`(使用默认密码 root123 / redis123)
- **生产部署**:`docker compose --env-file docker/.env.docker up -d --build`(使用生产密码)
下方为生产推荐配置参考,实际文件通过 `${VAR:-默认值}` 语法兼容两种场景。
:::
```yaml
# =============================================================================
# Docker Compose 生产部署配置(RXThinkCMF Laravel13)
# =============================================================================
# 服务架构:Nginx → PHP-FPM → MySQL + Redis
# 启动命令:docker compose --env-file docker/.env.docker up -d
# 停止命令:docker compose down
# =============================================================================
services:
# ===========================================================================
# Nginx 反向代理服务
# ===========================================================================
# 职责:接收外部 HTTP 请求,转发 index.php 到 PHP-FPM,直接返回静态资源
# 端口:容器内 80 → 宿主机 8000
# ===========================================================================
nginx:
image: nginx:1.25-alpine # 官方 Nginx 镜像(Alpine 版本,体积小)
container_name: rxthinkcmf-laravel13-nginx
ports:
- "8000:80" # 宿主机 8000 → 容器 80
volumes:
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro # 站点配置
- ./:/var/www/html:ro # 项目代码(只读,与 PHP-FPM 共享同一份)
depends_on:
- app # 确保 PHP-FPM 先启动
networks:
- rxthinkcmf-laravel13-net
restart: unless-stopped # 异常退出自动重启
# ===========================================================================
# PHP-FPM 应用服务
# ===========================================================================
# 职责:执行 Laravel PHP 代码,处理业务逻辑
# 端口:9000(FastCGI 协议,仅 Nginx 内部访问,不映射宿主机)
# ===========================================================================
app:
build:
context: . # 构建上下文为项目根目录
dockerfile: docker/Dockerfile
container_name: rxthinkcmf-laravel13-app
volumes:
- ./:/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.naivevue}
- 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://admin.laravel13.naivevue}
- CORS_ALLOW_ORIGIN=${CORS_ALLOW_ORIGIN:-*}
depends_on:
mysql:
condition: service_healthy # 确保数据库就绪(含首次 SQL 导入)
redis:
condition: service_started
networks:
- rxthinkcmf-laravel13-net
restart: unless-stopped
# ===========================================================================
# MySQL 数据库服务
# ===========================================================================
# 职责:存储业务数据(用户、菜单、字典、文章等)
# ===========================================================================
mysql:
image: mysql:8.0 # MySQL 8.0 官方镜像
container_name: rxthinkcmf-laravel13-mysql
# ports: # 生产环境建议注释掉,不暴露到宿主机
# - "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} # root 用户密码(>=16 位强密码)
MYSQL_DATABASE: ${MYSQL_DATABASE:-rxthinkcmf.laravel13.naivevue}
volumes:
- mysql_data:/var/lib/mysql # 数据持久化
# 初始化 SQL(首次启动自动执行,仅在数据卷为空时生效)
- ./document/mysql/rxthinkcmf.laravel13.naivevue.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-laravel13-net
restart: unless-stopped
# ===========================================================================
# Redis 缓存服务
# ===========================================================================
# 职责:JWT 会话、字典/权限缓存、队列(config/database.php redis 配置)
# ===========================================================================
redis:
image: redis:7-alpine # Redis 7 Alpine 版本(体积小)
container_name: rxthinkcmf-laravel13-redis
# ports: # 生产环境建议注释掉,不暴露到宿主机
# - "6379:6379"
command: redis-server --requirepass ${REDIS_PASSWORD} # 设置访问密码
volumes:
- redis_data:/data # 数据持久化(RDB 快照)
networks:
- rxthinkcmf-laravel13-net
restart: unless-stopped
# =============================================================================
# 命名卷(Named Volumes)
# =============================================================================
# Docker 管理的持久化存储,容器删除后数据保留
# 删除所有数据:docker compose down -v(-v 参数同时删除命名卷)
# =============================================================================
volumes:
mysql_data: # MySQL 数据文件
redis_data: # Redis RDB 快照文件
# =============================================================================
# 内部网络
# =============================================================================
# 所有服务通过此网络互通,容器间使用服务名(如 "mysql")作为主机名
# 外部无法直接访问此网络,必须通过 Nginx 的 ports 映射进入
# =============================================================================
networks:
rxthinkcmf-laravel13-net:
driver: bridge
```
## 环境变量配置
创建 / 编辑 `docker/.env.docker` 文件:
```ini
# Docker 环境变量(密码等敏感信息,切勿提交 Git)
# 端口(宿主机端口)
NGINX_PORT=8000
MYSQL_PORT=3306
REDIS_PORT=6379
# MySQL(首次启动自动导入数据库脚本)
MYSQL_ROOT_PASSWORD=<16 位以上强密码>
MYSQL_DATABASE=rxthinkcmf.laravel13.naivevue
# 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`,切勿提交到 Git 仓库**
- 密码至少 16 位,包含大小写字母和数字,MySQL 与 Redis 密码不同
- `JWT_SECRET` 是令牌签名根密钥,泄露等于任意用户令牌可伪造;不同环境使用不同密钥
:::
## 应用 .env 配置
容器启动前,确保项目根目录 `.env` 已初始化(`APP_KEY`、`JWT_SECRET`、`DB_PREFIX`):
```ini
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 # 修改密码、JWT_SECRET、域名
# 2. 配置应用 .env
cp .env.example .env
php artisan key:generate # 生成 APP_KEY
# 3. 构建并启动所有服务
docker compose --env-file docker/.env.docker.local up -d --build
# 4. 查看运行状态(首次 mysql 需导入约 226MB SQL,等 healthy)
docker compose ps
# 5. 查看应用日志(确认无报错)
docker compose logs -f app
# 6. 验证
curl https://your-domain/up
curl http://admin.laravel13.naivevue/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.naivevue' < backup.sql
# Windows CMD(PowerShell 不支持 < 重定向,用 cmd /c 包裹)
cmd /c "docker compose exec -T mysql mysql -uroot -p<密码> rxthinkcmf.laravel13.naivevue < 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 # 停止并删除所有数据卷(⚠️ 清空数据库)
docker compose restart app # 重启单个服务(修改 .env 后生效)
# --------------------------------------------------------------------------
# 日志排查
# --------------------------------------------------------------------------
docker compose logs -f # 所有服务日志
docker compose logs -f app # 应用日志
docker compose logs -f nginx # Nginx 日志
docker compose logs -f mysql # 数据库日志(首次看导入进度)
# --------------------------------------------------------------------------
# 进入容器调试
# --------------------------------------------------------------------------
docker compose exec app bash # 进入 PHP-FPM 容器
docker compose exec mysql bash # 进入 MySQL 容器
docker compose exec mysql mysql -uroot -p'<密码>' rxthinkcmf.laravel13.naivevue
# --------------------------------------------------------------------------
# 数据库操作
# --------------------------------------------------------------------------
# 导出数据库备份
docker compose exec -T mysql sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" rxthinkcmf.laravel13.naivevue' > backup_$(date +%Y%m%d).sql
# 导入 SQL 文件
docker compose exec -T mysql mysql -uroot -p'<密码>' rxthinkcmf.laravel13.naivevue < backup.sql
# --------------------------------------------------------------------------
# Laravel Artisan 命令
# --------------------------------------------------------------------------
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 | 关闭调试模式,防止堆栈/路径泄露 |
| MYSQL_ROOT_PASSWORD | 强密码(>=16位) | 包含大小写字母和数字 |
| REDIS_PASSWORD | 强密码 | 与数据库密码不同 |
| 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`:
```nginx
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# ... 其余配置不变 ...
}
# HTTP 跳转 HTTPS
server {
listen 80;
server_name api.example.com;
return 301 https://$server_name$request_uri;
}
```
`docker-compose.yml` 中增加证书挂载:
```yaml
nginx:
volumes:
- ./docker/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- ./ssl/cert.pem:/etc/nginx/ssl/cert.pem:ro
- ./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.naivevue' > backup_$(date +%F).sql
# 数据库恢复
docker compose exec -T mysql sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" rxthinkcmf.laravel13.naivevue' < 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` |
## 相关文档
- [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/quickstart/env-vars.html) — 完整配置项说明