ThinkPHP容器启动失败主因是runtime目录权限问题,需构建时设www-data属主、运行时指定用户、分离挂载并校验php-fpm配置;依赖应分层安装且禁用dev包;nginx须正确传递PATH_INFO;扩展需统一CLI/FPM配置;日志排查优先于前端观察。

ThinkPHP 应用启动报 file_put_contents(/runtime/...) 权限拒绝
容器里跑 ThinkPHP 最常卡在这一步:日志、缓存、模板编译全写不进 runtime 目录。根本不是代码问题,是容器用户和宿主机权限没对齐。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 构建镜像时用
RUN mkdir -p /var/www/runtime && chown -R www-data:www-data /var/www/runtime,别等运行时再改 - 如果用
docker run启动,加-u www-data参数,确保 PHP 进程以正确用户身份运行 - 宿主机挂载
runtime目录时,避免直接挂载整个项目目录(如-v ./app:/var/www),改用只读挂载 + 单独可写挂载:-v ./app:/var/www:ro -v ./runtime:/var/www/runtime - 检查
php-fpm.conf里的user和group是否与容器内实际用户一致(常见坑:镜像用www-data,但你自定义了用户却没同步改 fpm 配置)
Dockerfile 中该不该 COPY composer.lock 再 composer install
应该,而且必须在 COPY . /var/www 之前做。否则每次代码变更都会重装全部依赖,镜像层失效,构建变慢,还容易因 Composer 缓存不一致导致线上行为和本地不一致。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 分层 COPY:
COPY composer.json composer.lock ./→RUN composer install --no-dev --optimize-autoloader→COPY . . - 务必加
--no-dev,生产镜像不需要phpunit或faker这类开发依赖 - 如果项目用了 ThinkPHP 的
vendor/bin/think命令,确认composer install后的bin目录权限可执行(某些基础镜像默认 umask 会屏蔽 x 权限) - 不推荐在容器启动时用
entrypoint跑composer install—— 构建阶段就该确定依赖状态
nginx 配置里为什么 try_files $uri $uri/ /index.php?$query_string 不生效
ThinkPHP 的 URL 路由依赖正确的 PATH_INFO 传递,而默认 nginx 配置常把 $fastcgi_script_name 当作脚本路径,导致 $_SERVER['PATH_INFO'] 为空,Route::rule() 全部 fallback 到首页或 404。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 在
location ~ \.php$块中显式设置:fastcgi_split_path_info ^(.+\.php)(/.+)$;和fastcgi_param PATH_INFO $fastcgi_path_info; - 确认
fastcgi_param SCRIPT_FILENAME指向的是绝对路径,比如/var/www/public/index.php,而不是相对路径或变量拼接错误 - ThinkPHP 6+ 默认开启
app_host和url_domain_deploy,若容器外有反代(如 Traefik/Nginx),需在.env中设APP_URL=http://your-domain.com,否则生成的 URL 会漏协议或域名
如何让 phpinfo() 显示的扩展和本地开发环境一致
很多团队在 Docker 里发现 pdo_mysql、redis、opcache 缺失,不是没装,是装错位置或没启用。PHP CLI 和 FPM 加载的 php.ini 文件可能不同,扩展配置文件(docker-php-ext-* 生成的 .ini)也可能被覆盖。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 用
docker exec -it your-app php -m查 CLI 模块,用curl http://localhost/phpinfo.php | grep -A5 "Loaded Configuration File"看 FPM 实际加载的 ini 路径 - 安装扩展后,确认对应
.ini文件存在于/usr/local/etc/php/conf.d/下(官方 PHP 镜像约定路径),且内容形如extension=redis.so - 禁用 opcache 的开发模式?别删扩展,改
opcache.enable=0就行;但上线前务必开,否则 ThinkPHP 的模板编译和路由缓存性能损失明显 - 如果用了 Swoole,注意它和 FPM 互斥 —— 容器里只能选一种运行模式,Swoole 需单独启
php think swoole,不能走 nginx + php-fpm 流程
最麻烦的往往不是构建失败,而是日志里没报错、页面空白、路由 404 却查不到原因——这时候得进容器看 php-fpm.log 和 nginx error.log,而不是只盯浏览器控制台。



















