TL;DR 只想看配置信息请直接拉到文章最后。
之所以再次提出这个问题,是因为老王的一篇博客《如何正确配置Nginx+PHP》。
对于这一篇文章的大部分内容我还是赞同的,尤其是告戒大家不要不求甚解这点。
只不过对于后面的一些解释,以及配置,还是有些不准确的地方,相关需要注意的点,我会在下面列出。
对于有单一入口以及 rewrite 需求的 NGINX + PHP 配置,可以参考之前的一篇文章,虽然的确年久失修,不过还不至于漏洞百出。而本片文章也会再最后,结合我最近了解的一些新东西写一个更精简但兼容性更好的版本供参考。
接着说《如何正确配置 Nginx + PHP》里的问题。
location ~ \.php$
这个配置,对目前流行的 MVC 框架来说,只能解析/foo/bar
这样的路径,但不支持/index.php/foo/bar
这样的路径。所以这个地方需要稍作修改:location ~ \.php($|/) { ... }
。原文location
后面跟的-
也不对,我想应该是作者笔误。location
指令后面可以跟~
,~*
,^~
,=
以及直接跟路径五种方式。至于这些方式有什么区别以及有什么需要注意的地方,我之前提到的文章里有解答。- 解决
cgi.fix_pathinfo
的安全问题使用的方法早就没必要了。其实 PHP 开发组早已帮大家解决此安全问题了,乖乖升级到 >=5.3.9 并使用 FPM 就行(参见bug #55181),你会在 FPM 配置文件里发现security.limit_extensions
设置项,默认值为.php
,意思是默认只有.php
文件会被执行,否则将直接返回Access Denied
。
如上所述,修改之后的配置,以能运行 Symfony2 框架为例子(Laravel 或者 Yii 等单一入口的框架都一样):
server {
server_name ~^(?<project>.*)\.localhost$;
root /var/www/repos/$project/web;
$entry app_dev.php # 如果是 Laravel 或者 Yii2 等其他框架,只用将入口文件改一下就行
index $entry;
location ~ \.php($|/) {
include fastcgi.conf;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
location / {
try_files $uri $uri/ /$entry$is_args?$args;
}
}
去掉注释只有 12 行,还是很清爽了。这里教大家两个似乎网上很少提及的两个小窍门,看到就是赚到哦:
第一个小窍门:注意第 2 行和第 3 行,server_name 也是支持正则的,相信聪明的大家一眼就能看出来是什么意思,这样就可以使用一个 server 配置多个站点,何乐不为呢?不过,建议只在开发机上这么配置,这么说是出于性能的考虑。如果 server_name
使用确切的主机名或者使用通配符,会被 NGINX 分别记录在三张 hash 映射表里(通配符还分为往前匹配和往后匹配,NGINX 使用的是两张表),一个请求到了 NGINX,它会
- 尝试去专门记录确切主机名的 hash 表里查询,有匹配记录便返回对应服务器配置
- 如果 1 没有匹配记录,尝试在记录通配符风格的主机名的 hash 表里查询(往前匹配的优先与往后匹配的),当查到了匹配的记录返回对应服务器配置
- 如果 2 也没有匹配记录,尝试通过正则查找匹配的主机名,注意正则没有使用 hash 表
说了那么多,我其实就想表达:hash 表的速度是很不错的,但正则本来就慢,又用不了 hash 表,所以在生产机上还是建议不要使用正则的方式定义 server_name
了。2017-07-03 补充:生产环境的配置请见文章最后部分。
第二个小窍门:nginx 里也是可以自定义变量的,这里我们将入口文件改成变量,可以方便切换入口文件。不过需要注意的是,自定义变量不是所有地方都支持,这个地方不细说。
嗯,最后再没有节操的补充一句:
希望大家以后不要再拷贝粘贴了,如果实在改不了,那么就请拷贝粘贴本文……
参考:http://nginx.org/en/docs/http/server_names.html
2017-07-03 补充:以 Symfony2+ 项目为例子(Laravel 和 Yii 等单一入口框架类似),下面列出精简又安全的生产环境配置方式:
server {
server_name example.com; # 出于性能考虑,没有特别原因,生产环境 server_name 尽量不要用正则
root /path/to/symfony/web;
index app.php; # Symfony 项目的入口文件一般都是 app.php
# 如果是其他项目比如 wordpress 改成相应的入口文件,比如 index.php,后面出现 app.php 都需要改
location = /app.php { # 这里使用 = 除了性能考虑,还因为我确定 Symfony 生产环境只有这一个入口文件;Laravel 和 Yii 类似,改成相应入口文件即可
# 定死入口文件后,即使 FPM 的 security.limit_extensions 没有做限制也没关系
include fastcgi.conf; # Ubuntu 16 安装 Nginx 后,fastcgi.conf 文件自带解析 SCRIPT_FILENAME
# 用 fastcgi_params 也 OK,单一入口项目可将 SCRIPT_FILENAME 定死为单一入口文件的绝对路径
fastcgi_pass 127.0.0.1:9000; # 换成 unix socket 也行
internal; # 此指令限定只能通过『内部跳转』指令比如 try_files 到此 location,
# 防止用户直接访问 example.com/app.php
# 或者通过 example.com/app.php/foo/bar 的方式访问项目。
# 如允许直接访问,直接去掉即可
}
location ~ \.(html|txt|css|js|jpg|jpeg|gif|png|ico|woff2?|eot|svg|ttf)$ {
expires max; # 静态文件加缓存头,如果要做伪静态,html 可从条件中去掉
}
location ~ \. {
return 404; # 其余任何未知类型文件,以及非 app.php 文件都直接返回 404
}
location / {
try_files $uri $uri/ /app.php$is_args$args;
}
access_log /var/log/nginx/access.example.com.log;
error_log /var/log/nginx/error.example.com.log;
}
再说 NGINX + PHP 配置 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

写作累,服务器还越来越贵
求分担,祝愿好人一生平安
天使打赏人