ThinkPHP容器化部署成功的关键是public目录定位、runtime权限、Nginx PATH_INFO传递、环境变量注入四点对齐;缺一即导致404、Class not found或Permission denied等典型错误。

ThinkPHP框架版本号从5.x到8.1.0持续迭代,每个版本都强化了路由、验证与容器能力;容器化部署时若忽略public目录定位、runtime权限、Nginx PATH_INFO传递、环境变量注入四点对齐,哪怕镜像构建成功,也会在访问时出现404、Class not found或Permission denied等典型错误。
确认ThinkPHP项目结构是否满足容器化前提
打开项目根目录,检查是否存在public/、app/、config/、vendor/四个核心目录。缺失public目录说明未按标准结构初始化——ThinkPHP 6+默认生成该目录,若手动删过,需执行php think build:public重建。
【public目录必须存在且含index.php】,否则Nginx无论怎么配置root路径都找不到入口文件。
运行ls -l runtime storage,确认两个目录权限为drwxr-xr-x或更宽松;若显示drw-r--r--,说明写权限被禁,容器启动后必然报file_put_contents(/runtime/)失败。
立即学习“PHP免费学习笔记(深入)”;
构建最小可行Docker镜像
方法一:单阶段基础构建(适合调试)
在项目根目录新建Dockerfile,写入:
FROM php:8.2-apache
RUN docker-php-ext-install pdo_mysql opcache
COPY . /var/www/html/
RUN chown -R www-data:www-data /var/www/html/runtime /var/www/html/storage
EXPOSE 80
注意:此方式未执行composer install,若vendor目录为空,启动后会直接报Class 'think\App' not found。
方法二:多阶段构建(推荐生产)
第一步:用builder阶段安装依赖
FROM php:8.2-cli AS builder
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader
第二步:用apache镜像合并代码与依赖
FROM php:8.2-apache
RUN docker-php-ext-install pdo_mysql opcache
COPY --from=builder /app/vendor /var/www/html/vendor
COPY . /var/www/html/
RUN chown -R www-data:www-data /var/www/html/runtime /var/www/html/storage
A2ENMOD rewrite
这一步确保vendor在构建时就完整,避免运行时因权限或网络问题导致autoload失效。
配置Nginx正确转发ThinkPHP请求
第一步:将Nginx的root指令指向/var/www/html/public
这是硬性要求,不是/var/www/html,也不是/var/www。设错会导致所有请求返回404,因为index.php根本不在root搜索路径下。
第二步:在location ~ \.php$块中加入两行关键参数
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
缺任一者,ThinkPHP的Route::rule()定义的带参数路由(如s=api/user)将无法解析,全部退化为首页或404。
第三步:修正SCRIPT_FILENAME拼接逻辑
必须写成fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
禁止使用$realpath_root或漏掉$document_root——前者在容器内常为空,后者会导致PHP-FPM找不到index.php文件。
运行容器并验证关键路径
执行docker run -d -p 8080:80 -v $(pwd)/runtime:/var/www/html/runtime -v $(pwd)/env.docker:/var/www/html/.env:ro --name tp-app your-image-name
其中-v $(pwd)/runtime:/var/www/html/runtime是单独挂载,确保容器内www-data用户能写入;:ro后缀让.env只读,防止运行时被意外覆盖。
访问http://localhost:8080,若看到ThinkPHP欢迎页,说明public定位和Nginx转发成功。
再访问http://localhost:8080/index.php?s=api/test,若返回404而非白屏或错误提示,说明PATH_INFO未传入——立即检查fastcgi_split_path_info和PATH_INFO两行是否遗漏。
最后执行docker exec -it tp-app ls -l /var/www/html/runtime,确认目录下已生成log/、cache/等子目录,证明权限配置生效。



















