最近在做服務器橫向比較的一些資料,其中包括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
}
暫時想到那麼多,嗯
摘自 曾建凱的博客