把玩Nginx
发布时间:2014-09-05 16:34:50作者:知识屋
最近在做服务器横向比较的一些资料,其中包括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 {
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:/nginx/html(他是不会找location / {}里面设定的root的),于是重定向的全路径是D:/nginx/html/hello_world/index.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://Development//wwwroot;
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://Development//wwwroot;
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://Development//wwwroot;
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
}
暂时想到那么多,嗯
摘自 曾建凯的博客 (免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)