Nginx 配置 Laravel 必须将 root 指向 public 目录,如 /var/www/myapp/public;PHP location 块需含 try_files $uri /index.php?$query_string;静态资源需独立 location 并加缓存头;必须 deny 所有敏感文件(如 .env、.log)访问。

root 路径必须指向 public 目录
直接把 Laravel 项目根目录丢给 Nginx,index.php 会暴露、路由 404、静态资源 403——根本原因是没让 Nginx 从 public/ 入口开始服务。
正确做法是把 root 指向项目内的 public 子目录,不是项目根目录。比如项目在 /var/www/myapp,那 root 必须是 /var/www/myapp/public。
-
root /var/www/myapp/public;✅ -
root /var/www/myapp;❌(会导致/index.php可被直接访问,且重写失效) - 如果用符号链接部署,确保
public是真实路径或已启用follow_symlinks
location ~ \.php$ 块里必须加 try_files
不加 try_files 的常见后果:任意带 .php 后缀的恶意路径(如 /anything.php/xxx)都可能触发 PHP 解析,造成安全风险;更实际的问题是 Laravel 的单入口机制被绕过,index.php 不一定被执行。
标准写法是强制所有 PHP 请求先落到 index.php,由框架统一处理路由:
location ~ \.php$ {
try_files $uri /index.php?$query_string;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
-
try_files $uri /index.php?$query_string;是关键,缺了它,URL 重写和安全兜底就没了 -
$realpath_root比$document_root更可靠,能正确解析符号链接后的实际路径 - 别用
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;—— 在 symlink 场景下会出错
静态资源要跳过 PHP 处理,但得保留缓存头
Laravel 的 public/ 下有 JS、CSS、图片等,Nginx 如果没明确拦截,可能误交给 PHP-FPM,导致返回源码或 500。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
同时,这些文件默认没加缓存控制,每次请求都走磁盘,拖慢首屏。
- 用
location ^~ /或具体前缀(如location ~* \.(js|css|png|jpg|gif|ico)$)匹配静态资源 - 里面必须包含
try_files $uri =404;,防止路径穿透 - 加上
expires 1y;和add_header Cache-Control "public, immutable";提升复用率 - 注意:不要对
storage/app/public/的软链资源漏配——它们也得走同样规则,否则 404
rewrite 规则不能只靠 try_files,还得防 .env 泄露
try_files $uri $uri/ /index.php?$query_string; 看似够用,但它不阻止用户直接请求 .env、composer.json 这类敏感文件——Nginx 默认会尝试返回它们的明文内容。
必须显式禁止访问以点开头的文件:
location ~ /\.(env|log|conf|ini|lock|json|xml|yml|yaml|git|svn|htaccess|htpasswd) {
deny all;
}
- 这条规则要放在
server块顶层,早于其他location匹配,否则可能被覆盖 - 别只拦
.env——Laravel 日志(storage/logs/*.log)也可能被直接访问,需配合location ^~ /storage/logs/单独 deny - 如果用了
php_flag[allow_url_fopen]类配置,更要检查是否无意放行了远程文件读取
最麻烦的往往不是写错哪一行,而是某处少了个 /、某个 root 指错了层级、或者 .env 权限设成了 644 还没加 deny 规则——这些地方一漏,线上就等于裸奔。










