vendor目录安装后不可写,根本原因是Composer按系统umask和运行用户属主生成文件(如umask 002得775/664),而非自身赋权;常见诱因包括sudo安装致属主为root、CI缓存污染、Docker UID不一致;应优先用umask控制初始权限,再辅以chmod -R u+rwX,g+rwX加固。

composer install 本身不设置目录读写权限,它只按系统默认规则创建文件;所谓“设置权限”,本质是控制安装过程的上下文(umask、用户、挂载方式)或安装后手动加固。
为什么 vendor 目录安装后不可写?
根本原因不是 Composer 没“赋权”,而是它生成的文件权限继承自当前 shell 的 umask 和运行用户的属主。比如 umask 022 下,新目录默认 755、文件 644——Web 服务器用户(如 www-data)就无法往 vendor/ 写日志或缓存,报 failed to open stream: Permission denied。
- 常见诱因:用
sudo composer install导致vendor/属主变成root - CI 环境中缓存污染,
composer.lock或~/.composer/cache被 runner 以外的用户写入 - Docker 容器内 UID 与宿主机不一致,文件在宿主机上显示为
nobody:nogroup
用 umask 控制 install 时的初始权限
这是最轻量、最稳定的方式——让文件从诞生那一刻起就有合理权限,避免后期暴力 chmod -R。
- 开发机或组共享环境:运行
umask 002后再执行composer install,新目录默认775、文件664,组成员可协作 - 生产环境谨慎用
umask 000(目录777、文件666),除非你明确需要所有 bin 脚本可执行且接受安全风险 - CI 脚本里建议显式设 umask:
sh -c "umask 002 && composer install",避免依赖 runner 默认值
install 后用 chmod -R 加固 vendor 目录
如果已装完但权限不对,用 chmod 补救比改 umask 更直接,但要注意 X(大写)和 x(小写)的区别:
- 安全递归设权:
chmod -R u+rwX,g+rwX vendor/——X只给目录和已有执行位的文件加执行权,不会误给 .php 文件加x - 别用
chmod -R 755 vendor/:它把所有文件都设成可执行,PHP opcache 可能拒绝加载,CI 扫描工具会告警 - 若需特定包子目录可写(如
vendor/acme/sdk/cache),单独处理:chmod -R 775 vendor/acme/sdk/cache
CI 和 Docker 中权限错配怎么修
这两个环境出问题,90% 是属主(owner)不对,而不是权限数字不够。
- GitHub Actions 报
Permission denied:先跑ls -ld vendor/ composer.lock $(composer config --global cache-dir),任一第三列不是$RUNNER_USER就得修:sudo chown -R $USER:$USER vendor/ composer.lock和sudo chown -R $USER:$USER $(composer config --global cache-dir) - Docker 构建阶段:用多阶段镜像,在 builder 阶段装依赖,
COPY --chown=www-data:www-data --from=builder /app/vendor /app/vendor - 本地开发容器:启动时加
-u $(id -u):$(id -g),确保容器内生成的文件属主匹配宿主机
真正卡住人的从来不是 chmod 命令敲得对不对,而是没分清:这个权限该由谁在哪个环节定——是 install 时、COPY 时,还是 runtime 时?搞反了顺序,后面全是补丁。


















