歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

把玩Nginx

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

摘自 曾建凱的博客
Copyright © Linux教程網 All Rights Reserved