根本原因是php-fpm用户(如www-data)不属于vendor目录所属用户组,导致无权访问;须确保该用户能读取文件且目录有x权限,推荐用usermod加组配合chmod -r g+rx vendor/或acl方案。

PHP-FPM 读不了 vendor/ 的根本原因不是“没权限”,而是“不属于它”
报错 Class 'Monolog\Logger' not found 或 Nginx 返回 500 且 PHP-FPM 日志里有 failed to open stream: Permission denied,90% 不是 chmod 没设对,而是 PHP-FPM worker 进程的用户(比如 www-data)压根没权限进入 vendor/ 目录——因为目录属主是部署用户(如 deploy),而 www-data 不在该用户组里。
关键点:vendor/ 目录必须满足两个条件:目录要有 x 权限(否则无法 chdir 进入),且 PHP-FPM 用户必须能读取其中所有 .php 文件(r)和执行 autoload 静态映射(不需要 x)。
- 别用
chmod -R 755 vendor/—— 它会让vendor/bin/下的脚本变成可执行但可写,CI/CD 或安全扫描会直接拒绝 - 正确做法是让
www-data成为部署用户组成员:sudo usermod -a -G deploy www-data,然后chmod -R g+rX vendor/(X只给目录加x,不误开文件) - 如果不能改组策略(如多租户环境),就用 ACL:
sudo setfacl -R -m u:www-data:r-X vendor/,再加默认 ACL 确保新文件继承:sudo setfacl -d -m u:www-data:r-X vendor/
composer install 后必须立刻修复 vendor/ 权限,不能靠 umask
umask 只控制新建文件的默认权限,但 Composer 安装过程里大量依赖包自带 post-install-cmd 脚本(比如 Laravel 的 storage:link、Symfony 的 cache:warmup),它们会在 vendor/ 内创建 symlink 或可写目录,完全绕过 umask。
所以哪怕你运行前设了 umask 0022,安装完也得手动加固:
- 所有文件设为只读:
find vendor/ -type f -exec chmod 644 {} \; - 所有目录设为
755(含vendor/bin/):find vendor/ -type d -exec chmod 755 {} \; - 单独处理
vendor/bin/下的可执行文件:chmod 755 vendor/bin/*(注意:不是775,避免组内任意人修改) - 检查
vendor/composer/installed.json是否是644,不是666(某些旧版包会漏掉权限清理)
PHP-FPM pool 配置里 user/group 错了,autoload.php 就永远加载失败
错误配置示例:user = www-data + group = www-data,但项目文件属主是 deploy:deploy,且 www-data 不在 deploy 组 —— 此时 PHP-FPM 进程连 vendor/autoload.php 的首行 <?php 都读不到,更别说后续类了。
验证方式很简单:
- 进 PHP-FPM 容器或服务器,用
sudo -u www-data ls -l vendor/autoload.php,看是否报Permission denied - 确认
/var/www/html(或你的项目根目录)的父目录(如/var/www)也有x权限:ls -ld /var/www,否则www-data根本进不去子目录 - 不要把
root设成 PHP-FPM 的user,哪怕临时测试也不行 ——opcache会缓存 root 权限下生成的 opcode,切换回www-data后可能因文件所有权冲突导致 cache 失效或 segfault
Docker 环境下 vendor/ 权限问题更隐蔽,得从构建阶段掐断
很多人在 Docker 中跑 docker-compose exec app composer install,结果容器里 PHP-FPM 进程还是读不了 vendor/ —— 因为宿主机挂载的代码目录(./src:/var/www/html)权限被 Linux 默认的 UID/GID 映射机制破坏了。
解决路径只有两条:
- 构建镜像时就在
Dockerfile里完成安装:RUN chown -R www-data:www-data /var/www/html && su www-data -c "composer install --no-dev --optimize-autoloader",确保整个vendor/从诞生起就归www-data所有 - 如果必须挂载源码,就用
user:指定容器启动 UID:user: "33:33"(www-data在 Debian/Ubuntu 的 UID 是 33),并确保宿主机对应目录属主 UID 也是 33,或提前chown -R 33:33 ./src - 绝对不要在运行中的容器里用
sudo composer install—— 它会把vendor/归属变成root,PHP-FPM 进程拿不到,且下次重建容器又得重来
最常被跳过的一步:改完 PHP-FPM 的 user/group 或文件归属后,必须重启服务(sudo systemctl restart php8.3-fpm),否则进程仍以旧身份运行。opcache 缓存也不会自动刷新,得手动 opcache_reset() 或重启 FPM。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











