离线部署中 composer install 报 permission denied,主因是 vendor/ 或 composer.lock 权限/属主错位及脚本执行依赖问题,需清空 vendor、规范打包权限、禁用脚本分步执行、修正文件权限与用户属组。

composer install 时提示 Permission denied 怎么办
离线部署中 composer install 报 Permission denied,大概率不是权限本身没开,而是当前用户对 vendor/ 目录或其子目录(尤其是 vendor/bin/ 下的可执行文件)没有写入或执行权限。常见于:用 root 打包了 vendor,又用普通用户在目标机运行;或 tar 解压时保留了原始 uid/gid,导致非 root 用户无法覆盖或执行。
- 解压前先清空
vendor/,别直接tar -xzf覆盖 —— 用rm -rf vendor && tar -xzf vendor.tar.gz - 确保打包时用
--owner=0:0 --group=0:0(或--numeric-owner),避免 uid/gid 错位 - 如果必须保留
vendor/bin/中的脚本,解压后补一句chmod +x vendor/bin/* 2>/dev/null
为什么 composer install --no-scripts 有时反而更安全
离线环境里,post-install-cmd 或 pre-autoload-dump 这类脚本可能依赖外部命令(比如 php-cs-fixer、npm)、网络(如下载前端资源)、或当前系统路径(如硬编码了 /usr/local/bin)。一旦失败,整个 install 就卡住,且错误堆栈常掩盖真正的权限问题。
- 先跑
composer install --no-scripts --no-plugins,确保依赖能干净落地 - 再单独运行必要脚本,比如
php vendor/bin/phpunit --version看是否可执行 - 若脚本真要改权限,显式加
chmod步骤,比让 composer 自动 chmod 更可控
composer.lock 文件权限不对会触发什么问题
composer.lock 如果是只读(比如打包时设了 444),composer install 在校验 hash 时可能因无法临时重命名或 touch 它而报错,错误信息常是 file_put_contents(./composer.lock): failed to open stream: Permission denied,其实根本没想改它 —— 是 composer 内部逻辑在做原子写入时需要 rename 权限。
- 检查
ls -l composer.lock,确保是644(而非444或600) - 打包前统一运行
chmod 644 composer.lock,别依赖 tar 默认行为 - 如果部署脚本用了
cp -p或rsync -a,它们会保留权限,此时必须显式 chmod
PHP 运行用户和部署用户不一致时的关键点
Web 服务(如 nginx + php-fpm)跑的是 www-data 或 nginx 用户,但你部署用的是 deploy 用户 —— 这时 vendor/ 下的缓存文件(如 vendor/composer/autoload_classmap.php)若由 deploy 生成,www-data 可能无权读取,尤其当 umask 是 077 时。
- 部署完立刻运行
chown -R www-data:www-data vendor/(或对应 web 用户组) - 或者统一用
umask 002启动部署命令,保证新建文件组可读写 - 别依赖
composer dump-autoload --optimize的结果自动适配权限 —— 它只管生成,不管 chmod
事情说清了就结束。最麻烦的从来不是报错信息本身,而是权限问题总混着用户、打包方式、umask、web server 配置一起出现,得一层层剥开看谁动了 inode。










