软链接本身没问题,出问题的永远是权限、路径解析或web服务器配置。linux/macos需用ln -s手动重建public/storage指向../storage/app/public,windows下生成的mklink绝对路径在homestead中不可用;web用户须对storage/app/public及其父目录有x权限,可用namei -l逐级检查;nginx需显式配置location ^~ /storage/并用alias指定绝对物理路径。

软链接本身没问题,出问题的永远是权限、路径解析或 Web 服务器配置这三个环节中的至少一个。
public/storage 软链接指向错误或根本不存在
执行 ls -la public/storage,如果输出是 public/storage -> ../storage/app/public,说明链接存在且路径相对正确;如果报 No such file or directory,说明链接没建或被误删。别直接重跑 php artisan storage:link —— 它在 Windows 下生成的是 mklink 绝对路径,在 Homestead 或 Docker 中根本不可用。此时应进 public 目录手动重建:
rm storage ln -s ../storage/app/public storage
Linux/macOS 环境必须用 ln -s,不能依赖 Artisan 命令自动生成。
Web 用户无法读取 storage/app/public 目录
即使软链接看着正常,sudo -u www-data ls storage/app/public 报 Permission denied 就说明权限链断了。关键不是“目录有没有 r 权限”,而是“Web 用户(如 www-data)是否能逐级进入该路径”。用 namei -l storage/app/public 查每一层的属主和权限:
-
storage目录属主是root,但www-data不在同组 → 补组或改属组:sudo chgrp -R www-data storage -
storage/app/public权限是750→ 改为755(目录需 x 权限才能 cd 进入) - 父目录(如项目根)权限太严(如
750)→www-data连项目根都进不去,更别说子目录
nginx 配置导致 /storage/ 路径被代理或拦截
如果你用了反向代理(比如 location /api/ { proxy_pass ... }),而图片 URL 是 /storage/avatar.jpg,Nginx 可能因 location 匹配顺序把它错当成接口请求转发出去,返回 404。常见错误配置:
location / {
proxy_pass http://upstream;
}
这个 location / 会匹配所有请求,包括 /storage/xxx。修复方式是显式声明静态资源路径:
location ^~ /storage/ {
alias /path/to/your/project/storage/app/public/;
expires 1y;
add_header Cache-Control "public, immutable";
}
注意:alias 结尾有无 / 影响路径拼接;^~ 确保它优先于正则匹配;alias 路径必须是绝对物理路径,不能是相对路径或软链接目标。
Windows + Homestead/Vagrant 环境下软链接跨系统失效
Windows 主机上执行 php artisan storage:link,生成的是 Windows 风格的 mklink /D 符号链接,Vagrant 共享目录里 Linux 内核根本识别不了。现象是:ls -la public/storage 显示链接存在,但 cat public/storage/test.txt 报错或返回空。解决方法只有两个:
- 在 Homestead 内部(vagrant ssh 后)重新运行
php artisan storage:link - 或手动删掉 Windows 创建的链接,再用
ln -s在 Homestead 里重建
别指望“一次生成、处处可用”——软链接不是文件内容,它是操作系统级别的路径解析机制,跨平台时必须按目标环境重建。











