laravel文件上传失败主因是web服务器用户对storage/和public/目录无写权限,需修复属主(如www-data)、执行storage:link、解除nginx上传限制、绕过selinux拦截,并验证请求是否抵达控制器。

部署 Laravel 应用后文件上传失败、报错“Permission denied”或返回空路径,本质是 Web 服务器用户(如 www-data、nginx、apache)对 storage/ 和 public/ 目录无写入权限,或上传目录未创建、SELinux/AppArmor 拦截、Nginx 上传限制未放开。
确认并修复 storage/ 目录写入权限
运行 php artisan storage:link 前,必须确保 storage/app/ 及其子目录可被 Web 服务器用户写入。Laravel 默认使用 storage/app/public 作为 public 磁盘根目录,若该路径不可写,store() 会静默失败或抛出异常。
进入项目根目录,执行以下命令(以 Ubuntu/Debian + Apache 为例):
sudo chown -R www-data:www-data storage/ bootstrap/cache/
sudo chmod -R 775 storage/ bootstrap/cache/
【注意:chmod 775 是安全底线,切勿设为 777;若仍报错,请检查父目录 /var/www 是否被 root 锁死】
检查 public/uploads 类自定义上传目录是否存在且可写
若你在 config/filesystems.php 中配置了类似 'admin' 这样的本地磁盘,root 指向 public/uploads,则该目录必须真实存在且由 Web 用户拥有。
执行 mkdir -p public/uploads/images public/uploads/files
再运行 chown -R www-data:www-data public/uploads
这一步漏掉会导致 $file->store('images', 'admin') 直接返回 false 或抛出 "failed to open stream" 错误,控制器中不加 isValid() 判断就会静默跳过。
解除 Nginx 上传大小与超时限制
Nginx 默认限制客户端请求体最大为 1MB,且超时仅 60 秒,大文件上传会直接被 413 Request Entity Too Large 或 504 Gateway Timeout 拦截,根本到不了 Laravel。
在 Nginx server 块内添加三行:
client_max_body_size 20M;
client_body_timeout 300;
client_header_timeout 300;
修改后必须执行 sudo nginx -t && sudo systemctl reload nginx,否则配置不生效。
绕过 SELinux 强制访问控制(仅限 CentOS/RHEL)
在启用了 SELinux 的系统上,即使权限 775、属主正确,Web 进程仍可能因策略限制无法写入 storage/。先确认状态:
sestatus -b | grep httpd_can_network_connect
若输出为 off,则执行:
sudo setsebool -P httpd_can_network_connect on
sudo setsebool -P httpd_can_network_connect_db on
【关键点:-P 参数表示永久生效,不加则重启后还原】
验证上传是否真正抵达 Laravel 控制器
第一步:在控制器 upload 方法开头插入日志:
Log::info('Upload request received', ['files' => $request->allFiles(), 'hasFile' => $request->hasFile('avatar')]);
第二步:上传一个极小的测试文件(如 1KB txt),查看 storage/logs/laravel.log。
若日志中 files 为空或 hasFile 为 false,说明问题出在 Nginx 层或表单 enctype 缺失;若日志有内容但 store() 失败,才需回溯权限与磁盘配置。











