laravel项目nginx访问异常90%因root未指向public目录或try_files与script_filename配置不匹配;root必须为/var/www/myapp/public,配合try_files $uri $uri/ /index.php?$query_string及fastcgi_param script_filename $realpath_root$fastcgi_script_name。

直接说结论:Laravel 项目在 Nginx 下访问异常(404、502、白屏、暴露 app/ 目录),90% 是因为 root 指向错误或 try_files + SCRIPT_FILENAME 配置不匹配,不是代码问题,也不是 Laravel 版本兼容性问题。
root 必须指向 public/ 目录,不是项目根目录
这是所有问题的起点。Nginx 的 root 值如果设成 /var/www/myapp(项目根),它会尝试把 /css/app.css 解析为 /var/www/myapp/css/app.css——这个路径不存在;更危险的是,用户直接请求 /vendor/autoload.php 会被 Nginx 返回源码,造成敏感信息泄露。
正确做法只有一条:root 必须是项目内 public/ 子目录的绝对路径:
root /var/www/myapp/public;
常见踩坑点:
- 本地开发用 Apache +
.htaccess,迁移到 Nginx 后忘记改root,沿用旧配置 - Docker 中
docker-compose.yml挂载路径是- ./src/:/var/www/html,但 Nginx 配置却写root /var/www/public(真实路径应为/var/www/html/public) - 使用宝塔或面板部署时,误选“网站根目录”为项目根,而非
public/
location / 必须配 try_files $uri $uri/ /index.php?$query_string
没有这行,所有 Laravel 路由都会 404。Nginx 不像 Apache 默认读 .htaccess,它不会自动把非静态请求转发给 index.php。仅靠 location ~ \.php$ 是不够的——那个块只处理以 .php 结尾的请求,而 /users/123 这类路由根本进不去。
关键细节:
- 必须用
$query_string,不是$args或空着。Laravel 11+ 的route()、分页、CSRF 表单都依赖完整参数透传 - 不能写成
return 301 /index.php?$query_string——这是重定向,不是内部重写,会暴露index.php在 URL 中 - 若需支持多语言前缀(如
/zh/about),确保$query_string完整保留,否则app()->getLocale()可能失效
fastcgi_param SCRIPT_FILENAME 必须用 $realpath_root
PHP-FPM 报 “No input file specified” 或 500 错误,十有八九是这里错了。Laravel 部署常用符号链接(比如 current → releases/20260817),$document_root 会解析为软链路径本身,而 $realpath_root 会解析为真实物理路径。
正确写法:
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
其他必要参数不能少:
-
fastcgi_param PATH_INFO $fastcgi_path_info;—— 否则带路径参数的路由(如user/{id}/edit)无法识别 -
fastcgi_split_path_info ^(.+\.php)(/.+)$;—— 配合PATH_INFO使用,尤其在启用 PATH_INFO 模式时 - 别漏掉
include fastcgi_params;,否则SCRIPT_NAME、REQUEST_URI等基础变量为空
Docker 环境下路径映射与服务通信要对齐
Docker 里出问题,基本是路径或网络没对上。典型错误:Nginx 容器挂载了代码到 /var/www/html,但配置写 root /var/www/public;或者 fastcgi_pass 写成 127.0.0.1:9000,却没开 PHP-FPM 的 TCP 监听(默认只监听 Unix socket)。
实操检查项:
- Nginx 配置中的
root必须和docker-compose.yml的 volumes 挂载目标一致,再拼上/public,例如:root /var/www/html/public; -
fastcgi_pass必须指向 PHP-FPM 容器的服务名 + 端口(如app:9000)或正确的 socket 路径(如unix:/var/run/php/php8.2-fpm.sock) - PHP-FPM 容器内必须能读取挂载的代码,即挂载路径(如
/var/www/html)在 PHP 容器里存在且可读 - 不要为了“统一”去改挂载路径(比如把 volumes 改成
- ./src/:/var/www/public),这会让 PHP-FPM 找不到vendor/和app/
最易被忽略的一点:Nginx 和 PHP-FPM 容器必须在同一个 Docker 网络里,fastcgi_pass 中的服务名才能被 DNS 解析。单独运行的容器默认不在同一网络,curl -v http://app:9000 连不通就说明网络未打通。











