Nginx下Laravel子目录部署:告别Access Denied!
2025-03-08 20:12:10
Nginx 下 Laravel 子目录部署,告别 Access Denied!
老项目要加新功能了?打算用 Laravel 搞定,本地 XAMPP 配 Apache 跑得飞起,一到线上 Nginx 环境就 Access Denied?别慌,这篇博客帮你捋清楚 Nginx 子目录部署 Laravel 的那些坑。
问题出在哪?
你遇到的问题,简单来说,就是 Nginx 没能正确地将请求转发给 Laravel 的入口文件 index.php
。 默认情况下,Nginx 会尝试查找与 URL 匹配的物理文件或目录。当 Laravel 部署在子目录下时,直接访问 mysite.com/2015
,Nginx 找不到对应的文件或目录,就会拒绝访问。或者,即使找到了 /2015
这个物理目录,你配置的方式,会导致无限循环重定向。
解决方案,安排!
下面给出几种解决思路,总有一款适合你。
方案一:alias
+ try_files
+ 重写规则 (推荐)
这是最常用的方式,也是我最推荐的方式。它的核心思想是:
alias
指定目录: 用alias
指令告诉 Nginx,/2015
这个路径实际上对应服务器上的哪个目录。try_files
尝试匹配: 优先尝试直接访问请求的文件或目录。- 重写规则兜底: 如果找不到文件,就把请求重写到 Laravel 的入口文件
index.php
,并把原始请求路径作为参数传递过去。
配置示例:
server {
listen 80;
server_name am2.aminversiones.com;
root /home/forge/am2.aminversiones.com;
index index.html index.htm index.php;
charset utf-8;
client_max_body_size 300M;
location / {
try_files $uri $uri/ /index.php?q=$uri&$args;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
access_log off;
error_log /var/log/nginx/am2.aminversiones.com-error.log error;
error_page 404 /index.php;
# PHP 解释器配置, 请按照你的环境调整.
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # <-- 这里按需修改
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Remove trailing slash to please routing system.
if (!-d $request_filename) {
rewrite ^/(.+)/$ /$1 permanent;
}
# Laravel 子目录配置
location ^~ /2015 {
alias /home/forge/am2.aminversiones.com/2015/public;
try_files $uri $uri/ @laravel;
location ~* \.php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # <-- 这里按需修改
fastcgi_split_path_info ^(.+\.php)(.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
location @laravel {
rewrite ^/2015/(.*)$ /2015/index.php?/$1 last;
}
location ~ /\.ht {
deny all;
}
}
代码解读:
location ^~ /2015
: 匹配以/2015
开头的请求。^~
表示如果匹配到这个 location,就不再检查其他正则表达式 location。alias /home/forge/am2.aminversiones.com/2015/public;
: 将/2015
开头的请求映射到服务器的/home/forge/am2.aminversiones.com/2015/public
目录。 重要提示: 请确保这个路径正确指向你的 Laravel 项目的public
目录!try_files $uri $uri/ @laravel;
:$uri
:表示当前请求的 URI(不带参数)。$uri/
:尝试在$uri
后面加上/
,看看是不是一个目录。@laravel
:如果前面两个都没找到,就跳转到名为@laravel
的 location。
location @laravel
: 定义一个名为@laravel
的 location。rewrite ^/2015/(.*)$ /2015/index.php?/$1 last;
: 这行是关键!它将/2015/xxx
这样的请求重写为/2015/index.php?/xxx
。^/2015/(.*)$
: 匹配/2015/后所有字符,并将匹配内容存入$1./2015/index.php?/$1
: 重定向的目标地址, 注意?
后面有个/
.last
:停止处理后续 rewrite 指令,并用新的 URI 重新搜索 location。
fastcgi_param SCRIPT_FILENAME $request_filename;
: 在location ~* \.php$
中设置SCRIPT_FILENAME
使用$request_filename
. 这是因为使用 alias 以后,$document_root
变量不会按照预想的方式改变, 因此无法正确传递给 php 解释器文件地址。fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
: 在你的环境,这个路径很可能需要改变。 找到你正确的php-fpm.sock
文件的地址.
修改配置后,别忘了重载 Nginx:
sudo nginx -t # 检查配置文件语法
sudo systemctl reload nginx # 重载配置
方案二:使用 try_files
直接判断
这种方法相对简单,但是需要对try_files
有较深入的理解。
server {
# ... 其他配置 ...
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # <-- 这里按需修改
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# ... 其他配置 ...
location /2015 {
try_files $uri $uri/ /2015/index.php?$query_string;
}
location ~ /\.ht {
deny all;
}
}
原理:
/2015
: 表示匹配所有以/2015
开头的路径。try_files $uri $uri/ /2015/index.php?$query_string
: 如果请求的文件找不到, 则尝试访问/2015/index.php
并将参数传入.
注意: 这种配置相对精简, 但是必须保证/2015
是实际存在目录, Nginx才可以找到/2015/index.php
修改配置后,别忘了重载 Nginx:
sudo nginx -t
sudo systemctl reload nginx
方案三:修改 Laravel 的 index.php
(不推荐)
这种方法不推荐 ,因为它需要修改 Laravel 核心文件,可能导致升级问题。但作为一种思路,也介绍一下。
你可以修改 Laravel 项目 public/index.php
文件,在其中添加代码来处理子目录的路径问题。大致思路是:
- 获取当前请求的 URI。
- 判断 URI 是否以
/2015
开头。 - 如果是,则修改
$request
对象的路径信息,去掉/2015
前缀。
具体代码我就不写了,因为真的不推荐 这种方式。
安全建议
- 隐藏入口文件: 将除了
public
目录之外的所有 Laravel 文件移到 Web 根目录之外,可以提高安全性。 也就是调整服务器设置,修改 root 到public
目录. - 限制文件访问: 确保 Nginx 配置中限制了对敏感文件(如
.env
、.git
)的访问。一般通过设置location ~ /\. { deny all; }
来拒绝访问所有.
开头的文件 - 最小权限原则 确保运行PHP的账户只拥有运行需要的最低权限.
进阶技巧
多项目共存
如果你有多个 Laravel 项目,需要分别部署在不同的子目录下,可以用类似的方法。只需要为每个项目配置一个独立的 location
块,并分别设置 alias
和重写规则即可。 只需要在server 块里增加:
location ^~ /2016 {
alias /home/forge/am2.aminversiones.com/2016/public;
try_files $uri $uri/ @laravel2016;
location ~* \.php$ {
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock; # <-- 这里按需修改
fastcgi_split_path_info ^(.+\.php)(.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
location @laravel2016 {
rewrite ^/2016/(.*)$ /2016/index.php?/$1 last;
}
当然,/2016
需要是实际存在并且放置了Laravel代码的文件夹。
这篇博客从问题分析到解决方案,再到安全建议和进阶技巧,希望能帮到你。 祝你部署顺利!