生产环境严禁运行 composer install,必须在构建阶段完成依赖安装并同步代码包,否则将引发权限错误、环境不一致和敏感信息泄露三类严重问题。

生产环境不能直接运行 composer install,必须在构建阶段完成依赖安装并整体同步代码包。 这不是优化建议,而是避免权限混乱、环境漂移和安全泄露的硬性要求。
为什么生产机上跑 composer install 会出事
看似省事,实则埋三类硬伤:
-
file_put_contents(./composer.json): failed to open stream: Permission denied—— 不是 Composer 报错,是部署用户对vendor/或composer.lock没写权限,排查耗时远超预估 - 本地 PHP 8.2,线上还是 8.1:
Your platform does not meet the requirements直接中断部署,CI 流水线卡死 -
composer.json或.env被 Nginx 错误配置暴露,几秒内数据库密码、API 密钥全进攻击者手里
composer install --no-dev --optimize-autoloader --classmap-authoritative --no-interaction 必须一起用
这五个参数互锁生效,漏一个就可能让服务响应变慢、偶发 500 或自动化挂起:
-
--no-dev:跳过require-dev所有包(phpunit、symfony/debug-bundle),否则它们会进autoload.php,带来类加载变慢 + 潜在调试入口暴露 -
--optimize-autoloader:生成vendor/composer/autoload_classmap.php,把类名直连文件路径,单次类加载从平均 1.2ms 降到 0.05ms;不加它,高并发下 autoload 就是 I/O 瓶颈 -
--classmap-authoritative:替代已废弃的--optimize,强制 autoloader 只查 classmap,不 fallback 到文件扫描——性能更高,但要求所有类必须被收录进 map(PSR-4/0 自动覆盖,files类型需手动确认) -
--no-interaction:防止遇到平台提示(如 “Do you want to store credentials for github.com?”)卡住 CI,尤其 Docker 构建时直接超时失败
装完还得删:vendor/ 里哪些东西必须清理
composer install --no-dev --optimize-autoloader 是底线,但光靠它远远不够。真正该删的是这些:
-
vendor/bin/—— 全部删除(除非你明确需要某个二进制如phinx在线上运行) -
vendor/**/tests/、vendor/**/Tests/、vendor/**/test/、vendor/**/Test/ vendor/**/{.git,.gitignore,.travis.yml,phpunit.xml,phpstan.neon,psalm.xml}-
vendor/**/docs/、vendor/**/examples/、vendor/**/demo/ -
vendor/composer/installed.json—— 含完整包版本与哈希,泄露可辅助攻击者判断组件漏洞
Linux/macOS 下可用:find vendor -path '*/tests' -o -path '*/.git' -o -name 'phpunit.xml' -delete;CI/CD 中更推荐显式 rm -rf vendor/bin/ vendor/**/tests/ vendor/**/docs/ vendor/composer/installed.json,避免 glob 漏删。
Nginx 必须封死的路径,try_files 拦不住
try_files $uri $uri/ /index.php?$query_string 只管路由转发,不管文件下载。真正要靠 location 规则硬隔离:
-
location ~ /\.(env|json|lock|git|hg|svn)$ { deny all; }—— 干掉所有带后缀的配置与元数据文件 -
location ^~ /vendor/ { return 403; }—— 用^~前缀匹配,确保比location ~ \.php$优先,彻底封死源码目录遍历 -
location = /composer.json { return 403; }—— 单独封死根目录下的关键文件(^~对等号不生效,得用=精确匹配)
少写一条,就等于把项目结构、依赖版本甚至部分密钥敞给扫描器。最常被忽略的是 installed.json 和 /vendor/ 的 ^~ 匹配优先级——它一旦被 .php 规则覆盖,/vendor/autoload.php 就可能被直接下载。











