知识屋:更实用的电脑技术知识网站
所在位置:首页 > 操作系统 > linux

把玩Nginx

发布时间:2012-02-08 12:15:26作者:知识屋

最近在做服务器横向比较的一些资料,其中包括Nginx,也恰好有个朋友在学习部署Nginx,于是深入的把玩了一下Nginx。不过我比较懒...,不太想换到linux环境下,其实Windows下还是有办法搞的,网上资料也很多。要在Windows环境模拟PHP-FPM的话,需要自己动手写个程序监控php-cgi.exe的进程,只要解决这个问题,就能确保Windows环境下的php-cgi.exe的持久运行。
  
 虽然说我一直不太喜欢Nginx,不过不得不佩服,Nginx的Windows版本是静态编译,只有一个EXE文件,没有其他动态库,而Nginx的主要功能和扩展都集成与此,不得不让我等怪癖之辈心生怜爱之心...呃,5MB,Windows版本的Lighttpd都要10MB,还是动态加载扩展。
  
 话说Nginx的Rewrite,搞得我蛋疼了半天,终于摸清门道了,其实问题存在于他默认提供的那个配置文件(默认配置害人啊,真要不得)。
  
 001
 #user  nobody;
 002
 worker_processes  1;
 003
  
 004
 #error_log  logs/error.log;
 005
 #error_log  logs/error.log  notice;
 006
 #error_log  logs/error.log  info;
 007
  
 008
 #pid        logs/nginx.pid;
 009
  
 010
  
 011
 events {
 012
     worker_connections  1024;
 013
 }
 014
  
 015
  
 016
 http {
 017
     include       mime.types;
 018
     default_type  application/octet-stream;
 019
  
 020
     #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
 021
     #                  '$status $body_bytes_sent "$http_referer" '
 022
     #                  '"$http_user_agent" "$http_x_forwarded_for"';
 023
  
 024
     #access_log  logs/access.log  main;
 025
  
 026
     sendfile        on;
 027
     #tcp_nopush     on;
 028
  
 029
     #keepalive_timeout  0;
 030
     keepalive_timeout  65;
 031
  
 032
     #gzip  on;
 033
  
 034
     server {
 035
         listen       9090;
 036
         server_name  localhost;
 037
  
 038
         #charset koi8-r;
 039
  
 040
         #access_log  logs/host.access.log  main;
 041
  
 042
         location / {
 043
             root   html;
 044
             index  index.html index.htm;
 045
         }
 046
  
 047
         #error_page  404              /404.html;
 048
  
 049
         # redirect server error pages to the static page /50x.html
 050
         #
 051
         error_page   500 502 503 504  /50x.html;
 052
         location = /50x.html {
 053
             root   html;
 054
         }
 055
  
 056
         # proxy the PHP scripts to Apache listening on 127.0.0.1:80
 057
         #
 058
         #location ~ .php$ {
 059
         #    proxy_pass   http://127.0.0.1;
 060
         #}
 061
  
 062
         # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
 063
         #
 064
         location ~ .php$ {
 065
             root           html;
 066
             fastcgi_pass   127.0.0.1:9000;
 067
             fastcgi_index  index.php;
 068
             fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
 069
             include        fastcgi_params;
 070
         }
 071
  
 072
         # deny access to .htaccess files, if Apache's document root
 073
         # concurs with nginx's one
 074
         #
 075
         #location ~ /.ht {
 076
         #    deny  all;
 077
         #}
 078
     }
 079
  
 080
  
 081
     # another virtual host using mix of IP-, name-, and port-based configuration
 082
     #
 083
     #server {
 084
     #    listen       8000;
 085
     #    listen       somename:8080;
 086
     #    server_name  somename  alias  another.alias;
 087
  
 088
     #    location / {
 089
     #        root   html;
 090
     #        index  index.html index.htm;
 091
     #    }
 092
     #}
 093
  
 094
  
 095
     # HTTPS server
 096
     #
 097
     #server {
[!--empirenews.page--]分页标题[/!--empirenews.page--] 098
     #    listen       443;
 099
     #    server_name  localhost;
 100
  
 101
     #    ssl                  on;
 102
     #    ssl_certificate      cert.pem;
 103
     #    ssl_certificate_key  cert.key;
 104
  
 105
     #    ssl_session_timeout  5m;
 106
  
 107
     #    ssl_protocols  SSLv2 SSLv3 TLSv1;
 108
     #    ssl_ciphers  HIGH:!aNULL:!MD5;
 109
     #    ssl_prefer_server_ciphers   on;
 110
  
 111
     #    location / {
 112
     #        root   html;
 113
     #        index  index.html index.htm;
 114
     #    }
 115
     #}
 116
  
 117
 }
 这是Nginx默认自带的conf文件,取Server这段,location / {} 默认指向的是html,就是nginx所在目录下的html目录。其实这个默认配置最大的问题,没有声明全局的documentRoot。假如你按照这个配置,再添加一个location,比如:
 1
 location /hello_world {
 2
     if (-f $request_filename) {
 3
         break;
 4
     }
 5
     if (!-e $request_filename) {
 6
         rewrite . /hello_world/index.php last;
 7
     }
 8
 }
 怪事就来了,如果访问不存在的文件,会匹配!-e $request_filename这条规则,即重定向到/hello_world/index.php。
  
 但是,但是,在/hello_world前面是什么呢?如前所述,由于没有全局的DocumentRoot,所以他会自己默认认为DocumentRoot是nginx所在的那个html,比如D:nginxhtml(他是不会找location / {}里面设定的root的),于是重定向的全路径是D:nginxhtmlhello_worldindex.php,于是不断的报404错误,这个问题....(我的版本是1.0.6,不晓得新版本的默认配置是否有作出调整)。
  
 由于对lighttpd已经十分十分熟悉了,两者可以做一个比较(非性能对比,这个文章太多),主要基于配置、管理方面。
  
 lighttpd配置方面,好像写php脚本,大量的[]和{},一个不小心漏一个,就够你流汗半天,咋服务器起不来呢?MD原来是个逗号。
  
 lighttpd配置貌似不支持include的模式,但却支持嵌入lua脚本。比如,如果你想写这种!-e $request_filename的配置,需要自己倒腾一个lua脚本,说他好,也好,用lua,你可以干更多的事情,说不好,也不好,因为其实说明白了,rewrtie的事情就那么多,好端端多一个lua,没事找事。
  
 相比之下,Nginx可以支持include全目录的下的文件,而且他的配置写起来,更容易发现纰漏(分号和逗号,会有很大差异)。而且nginx的配置的内容更加精简,这是件好事。
  
 其实无论lighttpd还是nginx,真的要作为发布服务器使用,首先第一件事,就是...编译,废话。编译完的第一件事,就是从0开始写配置文件。事实上这是确保服务器安全和稳健的必要条件,lighttpd的配置,我都是从第一行开始写起的(当然,部分会粘贴),确保清楚、了解、熟知每一行配置所要做的事情和其背景,不开放和应用无关的任何组件和扩展。如果条件允许,在手动编译的过程,不妨去了解清楚每一个编译的依赖库都是用于什么功能的,比如,我还记得当年很认真的查询过什么叫做stat-cache-fam。
  
 其实我是十分不提倡通过yum或者apt-get的方式安装服务器的关键服务,只是呢,这话,我说了很多年,说了很多次,被视作耳旁风。尤其记得,当年安装公司某服务器的时候,老板走过来,看到configure过程,刷屏一样的字符,惊讶的问道,你装的不是Ubuntu吗?我说是啊。他接着问道:那为啥装个Apache要那么久?其实我挺无语的,当时没多想,只是觉得,终归自己编译的靠谱。结果,3年后,公司的服务器终于爆发大规模的漏洞,安全问题等等。其实,从年前至今,所有爆发的种种问题,可以归结到以下几点:
  
 1、程序员开发程序,缺乏体系、规范,导致服务器被攻击或者被Hack,不是PHP或者Apache的漏洞所致,而是程序员开发的程序缺乏必要的检查。你可以说,是程序员的水平问题,或者说是素质问题。但是还是那句老话,如果站在项目角度看,这个人完成了项目,从功利角度,时间角度,宇宙角度来说,他是ok的。但是因为他老人家的疏忽、一时大意、赶工,什么这个那个的,他的上传文件忘记检查文件类型,于是被上传了一个perl脚本,然后服务器被hack了。我会认为,不要针对人吧,通过人来看事情,最终能说的,就是缺乏开发规范,代码缺乏审核机制。
  
 2、过分倚重开源产品,这个有时候也真是很头疼的问题。倚重于某个开源核心库,还好些。比如wordpress,这种整合性的产品,千万别拿个人博客来这里说事,你该想想,如果一个公司超过20个wordpress的项目,一个版本号存在漏洞,你就慢慢升级吧,这就好像整人一样。尤其最近这一年,好像wordpress的漏洞一直没停过。
  
 3、服务器管理经验不足。看一些国外的文章,常常埋怨:其实Apache本身的性能还是不错的,令人诟病的就是默认配置问题,尤其是linux下的默认配置,好像逗你玩似的。
  
 其实无论是Nginx、Lighttpd、Apache,这些WebServer,都是出色的开源软件,问题不存在选择哪个平台,或者选择什么软件,完全在于使用者。便秘,你不能赖马桶太差了,厕所不够和谐。只是醉翁之意不在酒,你非说鹿是马,大家只好看你的笑话了。
  
 使用Nginx作为WebServer,是比较理想的选择,不过也必须看到他的一些问题:
  
 1、nginx的fastcgi处理的方式,还是不太理想,如Apache或者lighttpd,如果指定了某个目录的rewrite规则,会依照rewrite规则处理,就算你请求的后缀是.php。而nginx的话,如果你指定了location .php以后,凡是请求中包含.php的,都会转交fastcgi来处理。如果文件不存在,会报no file input之类的错误,但是终归来说,对于服务器外部,还是暴露了一个可攻击的入口点。
  
 2、nginx的配置特点是简,超级简,乃至有些弱,虽然允许你if,set,return,break,不过你别想循环嵌套。有点一根筋,不过倒让人很放心,这样的语义分析也简单。不过为了某个问题,可能会让你抓狂,实现起来,也不太优雅,比如上述的例子里面,假如我想限制upload目录里面的.php文件不被执行,你只能这样:
  
 1
 location ~ .php {
 2
         root   D:Developmentwwwroot;
 3
         include         fastcgi_params;
 4
         if ($uri !~ "/upload/") {
 5
                 fastcgi_pass    127.0.0.1:9000;
 6
         }
 7
         fastcgi_index   index.php;
 8
         fastcgi_param   SCRIPT_FILENAME  $document_root$fastcgi_script_name;
 9
 }
 可是就大多数的公司来说,怎么可能通过描述一个upload足够呢?可能存在各种不同的目录,这时候你可能得这样来写:
 01
 location ~ .php {
 02
         root   D:Developmentwwwroot;
 03
         include         fastcgi_params;
 04
         set $is_block 0;
 05
         if ($uri !~ "/upload/") {
 06
                 set $is_block 1;
 07
         }
 08
         if ($uri !~ "/no_php/") {
 09
                 set $is_block 1;
 10
         }
 11
         # |||,这可得无限多啊
 12
         if ($is_block = "1") {
 13
                 fastcgi_pass    127.0.0.1:9000;
 14
         }
 15
         fastcgi_index   index.php;
 16
         fastcgi_param   SCRIPT_FILENAME  $document_root$fastcgi_script_name;
 17
 }
 可能还有更好的写法吧!
 结合他的这两个特点,有以下两点需要注意的:
  
 1、默认的conf,不能设置.php的处理,具体的.php处理应该具体配置到每个vhost的配置文件上。因为有那么多的网站,每个网站都有不同的配置,你可别想在主的conf里面一次性写完,这真的有病。
  
 2、除非像Wordpress这种,到处都是需要被执行的.php文件。使用MVC框架的项目,甚至应该集中允许具体某个、某几个文件是作为php处理的,其他的.php请求,注意,不是不处理,而是通过rewrite到指定的php文件来处理(下载就傻眼了)。
  
 3、对于像wordpress这种,在配置vhost的php处理时,一定要注意,哪些是禁止运行php的地方,进行集中拦截:
  
 01
 location ~ .php {
 02
         root   D:Developmentwwwroot;
 03
         include         fastcgi_params;
 04
         if ($uri ~ "/hello_world/no_php/") {
 05
                 rewrite . /hello_world/index.php break;
 06
         }
 07
         fastcgi_pass    127.0.0.1:9000;
 08
         fastcgi_index   index.php;
 09
         fastcgi_param   SCRIPT_FILENAME  $document_root$fastcgi_script_name;
 10
 }
 暂时想到那么多,嗯
 
摘自 曾建凯的博客
(免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜