nginx.conf 优化版 (for PHP)

nginx.conf 优化版 (for PHP)

Chris Yue No Comment
Posts

通过一下午对 NGINX 的官方文档的研究和不断的尝试,对之前的 nginx.conf 做了蛮大的修改(请参见之前的文章《PHP 全局变量 PATH_INFO 与 NGINX 的配置》《让 symfony 运行在 NGINX 上的完美配置》不靠谱的百度空间已经把我之前的文章完全删除了,不过也无所谓,有了这篇文章后,之前写的也没太多价值了),下面将对优化后的版本进行详细的解释。

2016-1-10 更新:请跳转至此参考更“现代”的配置方式

因为 symfony 框架的 webserver 配置要求算是目前比较典型的 PHP 配置要求,所以还以它举例子:

server {
  set $project_root /path/to/project;

  server_name test.localhost;
  root $project_root/web; # www 根目录

  index index.php;

  # ^~ 是往前普通匹配,这里表示 /sf/ 开头的 uri
  # 在 prod 环境下其实这个可以不用配置
  location ^~ /sf/ {
    # alias 用来替换原本的 root 路径 
    alias $project_root/lib/vendor/symfony/data/web/sf/;
    # 由于 /sf/ 下都是静态文件所以设置为最大过期时间
    expires max;
  }

  # ~ 是正则匹配,这里匹配php文件
  location ~ ^/(index|frontend_dev)\.php($|\/) { # 只有在这里列出来的 PHP 脚本才能执行,防止 nginx 的上传文件漏洞
    # 交给 php-cgi 处理
    fastcgi_pass 127.0.0.1:9000;
    # 此文件里面还需另外设置,后面单独说明
    include fastcgi_params; 
  }

  # 这里正则匹配所有有扩展名的文件
  # 如果规定只静态文件有扩展名,那么等于匹配静态文件
  location ~ \.\w+ {
    # 做运维的会发现常有人恶意企图抓取
    # .db,.mdb,.sql,.xml 等数据文件
    # 导致大量404访问
    # php 大部分大型框架在一个请求过来以后
    # 都会做若干初始化工作
    # 所以如果不做特殊处理,php 会消耗大量资源去处理
    # 这种本来 nginx 直接给 404 就可以处理的事情
    expires max;
    # 但这里也有一个缺点
    # 必须规定好所有的动态页面的 uri 必须没有扩展名
    # 也就是说使用此配置
    # 将不能做类似伪静态的事情了
    # (比如动态生成.html结尾的页面)
  }

  # 上面规则都无法匹配的uri,都会执行此规则
  location / { 
    # 直接 rewrite 到根目录下 index.php
    # 因为不是 30X 跳转,所以 path_info 变量并不会改变
    rewrite .* /index.php last;
  }
}

另外 fastcgi_params 文件需要添加的规则为:

# 以下配置都是为了正确获得 php 的一些全局变量
# 许多 php 框架都需要这些变量来处理路由
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;

这一次配置的最重要的收获是 Nginx 的 location 配置原来是有一定的规则会去影响他的顺序的。location 与后面的 URI 之间的匹配方式有

  1. = 绝对匹配,比如 location = / 那就只能匹配首页,这也是效率最好的匹配
  2. ^~ 开头部分匹配,比如 location ^~ /sf/
  3. ~ 或者 ~* 正则匹配,比如 location ~ \.\w+~* 是不区分大小写的正则匹配
  4. 无任何符号 部分匹配,比如 location / 匹配任何 uri

匹配的优先顺序就是上面列表的顺序,所以无论把规则 location = / 写在最前还是最后,都会优先执行这条规则的匹配。

有的时候会出现同一个 URI 会同时匹配同一种类型的不同规则的情况,比如上面的配置中 /index.php 这条 uri 既匹配 .php 又匹配 .\w+,那么这两条规则谁在前面就执行谁的规则。

如果只是测试环境,不用考虑太多性能以及安全问题,配置还能更简单:

server {
  set $project_root /path/to/project;

  server_name test.localhost;
  root $project_root/web;

  index index.php;

  location ^~ /sf/ {
    alias $project_root/lib/vendor/symfony/data/web/sf/;
    expires max;
  }

  location ~ \.php($|\/) { 
    fastcgi_pass 127.0.0.1:9000;
    include fastcgi_params; 
  }

  location / { 
    # 尝试处理$uri,不行再处理$uri/
    # 还不行再处理/index.php
    # 这是nginx官方推荐用来替换
    # if (!-f $request_filename) { rewrite ... }
    # 的方法
    try_files $uri $uri/ /index.php$uri?$args;
  }
}

参考资料:

  1. Nginx Pitfalls
  2. Nginx HttpCoreModule

nginx.conf 优化版 (for PHP) by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

微信赞赏码

如果觉得文章还不错,就请扫码鼓励一下作者吧
天使打赏人

发表评论

+ 17 = 26