九月 18, 2012

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 轉移至 Nginx

2012 三月全世界的網頁伺服器市佔率圖 from netcraft.com 

上圖可以看出歷久彌新的 Apache 持續雄距首位,有超過 15 年的時間,沒"器"可挑戰它的地位。直至 Nginx 的出現,或許它現在只有 10% ,但從各方評價看來,它絕對是 Apache 有史以來最強大的對手。短短 5 年,它已經爬上第 3 名的位子,從趨勢線上看來,要超越 IIS 也是有很大的機會。

而 Nginx 為什麼短短幾年竄起,絕不是因為『用的人多』。如果是這種原因的話, palm 、 Windows OS 、 x86 CPU 、 PlayStation 到現在會活得好好地,因為它們都曾有超越 50% 的市佔率。

Nginx 被選擇的原因有幾點:
  1. 跨平台: *nix, Mac, Windows 皆可。這那算優點呢!!! 那個網頁伺服器沒跨平台,喔喔~講太早了, IIS 就是不能跨平台,或許這就是它市佔率持續下降的原因,強迫綁 Windows OS ,結果只要 Windows OS 下滑,它就必死無疑了。
  2. 開源的 BSD-like 授權。
  3. 靜態檔案輸出省資源。
  4. 不怕慢速連線。
  5. 比較不怕 DOS 攻擊。
  6. 穩定性高。
簡單講,除了效能,還是效能。而我要的功能, Nginx 都有提供,唯一算得上缺點的,就是因為 Apache 活得比較久,安全性已被磨得比較好了。所以對於我們愛研究的研究生來說,還有什麼理由不切換過去呢? 大概只有「懶」是個原因吧!

目前我們使用 Apache + Django 的方式多是利用 mod_python 的技術。然而這種作法是比較不安全的,把很多事都包給 Apache 去作,那不管是我們程式設計有錯,或是它用的元件有錯,只要出錯那就是管理員等級的錯。不過這個「錯」也不算是 Apache 的錯,是「用 mod_python 」的錯,如果用的是「 mod_fastcgi 」,那安全層級就能拉高了。

所以說來,這次的「升級」是把「 mod_python 」丟掉,改用「 mod_fastcgi 」。那麼我心裡想想,都要換成 Django 自己跑 fcgi mode 了,為什麼不乾脆連前端網頁伺服器也換一下呢! 因為重點已換成 Django 的 fcgi server , Apache 的重點性大減,前端網頁伺服器的功能只剩下靜態檔案輸出、虛擬站台切換、 https 處理等,那我何必跑一個 Huge Apache 呢? Nginx 就是我的新選擇。

安裝很簡單,如果是在 Ubuntu 中,請打:

$ sudo apt-get install nginx

如果是在 Windows 中,請到官網下載 nginx.zip 檔,解開了,就是一個可執行的 nginx 程式。

而我用的方法是下載源始碼自己編譯:

$ wget some_file_link.tgz
$ tar -zxf some_file_link.tgz
$ cd nginx
$ sudo apt-get install libpcre3-dev libssl-dev # 這些是編譯時,須用到的函式庫程式碼
$ sudo apt-get install libxml2-dev libxslt-dev # 這些是編譯時,須用到的函式庫程式碼
$ sudo apt-get install libgd2-xpm-dev libgeoip-dev # 這些是編譯時,須用到的函式庫程式碼
$ ./configure --prefix=/usr/local/nginx --with-debug --with-http_dav_module \
--with-http_addition_module --with-http_geoip_module --with-http_gzip_static_module \
--with-http_image_filter_module --with-http_realip_module --with-http_stub_status_module \
--with-http_ssl_module --with-http_sub_module --with-http_xslt_module \
--with-ipv6 --with-sha1=/usr/include/openssl --with-md5=/usr/include/openssl --with-mail \
--with-mail_ssl_module
$ make
$ sudo make install

這樣 Nginx 就安裝完成了。

接下來,我們作 Django 程式的設定,讓它可以跑在 fcgi mode 上,方法很簡單,原本我們在本機開發時,都是用:

$ python2.7 manage.py runserver 127.0.0.1:8080

讓它跑在 http://127.0.0.1:8080/ 上,現在則改用:

$ cd /home/somewhere
$ su - someuser -c "python2.7 manage.py runfcgi host=localhost port=3033 daemonize=true method=threaded workdir=/home/somewhere pidfile=/home/somewhere/fcgi.pid"

這樣 django 會在 127.0.0.1:3033 中,幫我們開一個 someuser 帳號權限的 fcgi server , daemonize=true 則表示指令打完後,它就背景處理了,想要把這個 fcgi server 殺掉,就去看看 /home/somewhere/fcgi.pid 的內容,裡面的編號就是系統行程編號, kill 那個編號就能關 fcgi server 了。

同時殺掉 fcgi server ,再馬上啟動它的指令可參考如下:

$ su - someuser -c "kill `cat /home/somewhere/fcgi.pid` && python2.7 manage.py runfcgi host=localhost port=3033 daemonize=true method=threaded workdir=/home/somewhere pidfile=/home/somewhere/fcgi.pid"

請注意在這個階段,你用瀏覽器去看 http://127.0.0.1:3033/ 是沒反應的,因為它現在跑的是 FastCGI 協定,不是 http 協定。瀏覽器無法跟 Django FastCGI 溝通。

接下來,我們再到 nginx.conf 去設定。Nginx 與 FastCGI Server 互動原理如下:
圖來自陈辉的博客
先由 Nginx 與瀏覽器互動,得到 GET, POST 等變數後,整理成 fastcgi 協定的變數,然後用 Socket 或 Port 方式傳遞給 FastCGI Server ,接下來就是 FastCGI 去驅動程式去處理,完成後拋回。

以下是 nginx.conf 的設定範例:

user www-data; # 子行程用的是 www-data 帳號
worker_processes 4; # 常駐 4 個子行程
pid /var/run/nginx.pid; # 紀錄母行程的編號
http {
    server_tokens off; # 網頁上不顯示伺服器版本編號
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 30;
    types_hash_max_size 2048;
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    gzip on;
    gzip_disable "msie6";
    server {
        listen 80;
        server_name www.whatever-you-want.com.tw;
        root /var/www;
        index index.html;
        access_log /var/log/nginx/TW-access.log;
        error_log /var/log/nginx/TW-error.log;
    }
    server {
        listen 443;
        server_name www.whatever-you-want.com;
        keepalive_timeout 60;
        ssl on;
        ssl_certificate /etc/ssl/hoamon.info/hoamon.info.crt;
        ssl_certificate_key /etc/ssl/hoamon.info/hoamon.info.key;
        location "/" {
            fastcgi_pass_header Authorization;
            fastcgi_intercept_errors off;
            fastcgi_pass 127.0.0.1:3033;
            fastcgi_param PATH_INFO                          $fastcgi_script_name;
            fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
            fastcgi_param  SERVER_SOFTWARE       nginx;
            fastcgi_param  QUERY_STRING                $query_string;
            fastcgi_param  REQUEST_METHOD         $request_method;
            fastcgi_param  CONTENT_TYPE                $content_type;
            fastcgi_param  CONTENT_LENGTH          $content_length;
            fastcgi_param  SCRIPT_FILENAME           $document_root$fastcgi_script_name;
            fastcgi_param  REQUEST_URI                     $request_uri;
            fastcgi_param  DOCUMENT_URI                 $document_uri;
            fastcgi_param  DOCUMENT_ROOT            $document_root;
            fastcgi_param  SERVER_PROTOCOL         $server_protocol;
            fastcgi_param  REMOTE_ADDR                 $remote_addr;
            fastcgi_param  REMOTE_PORT                  $remote_port;
            fastcgi_param  SERVER_ADDR                  $server_addr;
            fastcgi_param  SERVER_PORT                    $server_port;
            fastcgi_param  SERVER_NAME                  $server_name;
        }
        location "/media" {
            autoindex on;
            root /home/somewhere/media;
        }
        access_log  /var/log/nginx/whatever-you-want.access_log;
        error_log   /var/log/nginx/whatever-you-want.error_log;
    }
}

上面有兩個虛擬站台,一個是給 www.whatever-you-want.com.tw ,一個是給 www.whatever-you-want.com 。

www.whatever-you-want.com.tw 只是單純的靜態網站,預設首頁是 http://www.whatever-you-want.com.tw/index.html ,而它的硬碟位置在 /var/www/index.html 。

而使用者若是瀏覽 https://www.whatever-you-want.com/media 的連結,則 Nginx 會給它 /home/somewhere/media 資料夾內的所有檔案。除了 /media/.* 外,其他的連結都會用 3033 port 送到 Django FastCGI Server 處理。

而使用 https 的方法,只須要設定 3 個變數值: ssl , ssl_certificate , ssl_certificate_key 即可。

設定完成後,用指令開啟 Nginx :

$ /usr/local/nginx/sbin/nginx

重新載入:

$ /usr/local/nginx/sbin/nginx -s reload

關閉:

$ /usr/local/nginx/sbin/nginx -s stop

這樣 Nginx 伺服器就建立完成了。

在新架構下,可以由系統管理員獨立控管 Nginx 網頁伺服器的開啟、關閉,而讓程式設計師,自行作 FastCGI Server 的管理,程設師自己作程式更新、套用,避免給予過多的權限。畢竟這兩者的知識領域是有別的,少有人兩邊都作得很好。

=== 以下可能是 *nix(含 Mac) 專用(因為我不知道 Windows 能不能作 unix:socket 的指定) ===

如果我們一台機器有多個 django-base 的虛擬站台,那麼一個 django-base project 就要花一個 port ,這對於系統管理員及程式設計師而言,容易有搞亂的可能性,畢竟 "網址" <=> "port" <=> "django-base project" 的過程當中,是文字對應數字,再對應文字,難以記在人的腦中(也可能是我的記性比不上平均值吧!)。

所以我建議使用 Unix Socket 方式作對應。程式設計師把 socket 開在程式庫的 root 資料夾中,並取名為 django.socket 。再將 django.socket 權限設為 770 ,然後系統管理員把這個 django.socket 擁有群組設為 www-data 。

程式專案在 /home/someproject/ ,設定範例如下:

$ cd /home/someproject && /usr/bin/python2.7 manage.py runfcgi socket=`pwd`/django.socket method=threaded workdir=`pwd` pidfile=`pwd`/pid daemonize=true

上面程式設計師跑起一個 django-base 專案,並將 socket 開在 /home/someproject/django.socket 。

然後系統管理員作權限設定(也可以用 visudo 指給程式設計師作權限設定):

$ sudo chgrp www-data /home/someproject/django.socket
$ sudo chmod 770 /home/someproject/django.socket

系統管理員再把 nginx.conf 原本的 fastcgi_pass 127.0.0.1:3033 設定改如下:

        fastcgi_pass unix:/home/someproject/django.socket;

改成這樣的設定方式,對程式設計師來說,永遠是把 socket 開在同一個專案資料夾中,並命名為 django.socket ,而系統管理員也知道一定是專案資料夾下的 django.socket 。少了數字 port 的對應記憶,減少錯誤的機率。

四月 25, 2011

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 使用「公認機構簽核公錀」所發生的不知名問題

How to get a free HTTPS web certification authority by StartSSL.com 一文中,我申請了 A.hoamon.info 的公錀簽核,也正確地跑在 https 上,在使用瀏覽器觀看時,完全沒有問題。然而在 hg 軟體上,卻會發生 SSL: Server certificate verify failed. 的錯誤訊息,從 Mercurial on Windows vs Linux, spot the problem 一文中,作者解釋是 Windows 的 ssl 版本太舊的原因,但照他的解決方案處理,我的 hg 軟體卻是報 URLError. 錯誤。

後來在檢查 apache.conf 時發現,這台機器有三個 https 站台,一個是用 A.hoamn.info 的公錀,另外兩個 B, C 站台卻都是用 whatever.hoamon.info 的公錀。而 B, C 站台的設定檔寫得比 A.hoamon.info 站台還前面。所以試著調動 A.hoamon.info 到 B, C 站台設定的前面,結果 hg 軟體就正常了。

問題是解決了,但我反而混亂了。印象中, https 協定中,公錀是在 IP 層(或表現層,我不確定)就發送至使用者的瀏覽器,既然沒到應用層,則網頁伺服器就不知道該拿那一個虛擬站台的公錀給使用者,於是它總是拿第一個看到的公錀(也就是寫在最前面的),所以這篇教學文章,才會寫到:「…一個 Apache ,也只能架一個 SSL 站,用一個站名。除非妳跑很多份 Apache ,各自跑在不 同的 IP 或不同的 TCP 埠上,才能在同一臺伺服 器上,跑好幾個 SSL 站。」

實際上,在 Windows XP 的 IE, Safari 上觀看 A, B, C 三個站台,也的確都是拿到 A.hoamon.info 的公錀。但在 Chrome, Firefox 上,卻是看到 A 用 A.hoamon.info ,但 B, C 用的是 whatever.hoamon.info 的公錀。


這我頭大了,為什麼跟基本原理不一樣??? 還是因為某些瀏覽器有「重拿公錀的機制」存在???

十一月 21, 2009

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 莫明奇妙的 _ 網域名稱錯誤: 只發生在 IE 上

嚴格地說,這也不是 IE 的錯, IE 只是遵守規範而已。但是因為 Firefox 的容錯能力,讓我們一時以為是 IE 太爛了。

問題是這樣的:

我學弟使用 Windows 加 apache 配置一個測試網站給業主使用時,一直面臨 IE 不能登入,但 Firefox 卻正常的問題,而該網站在 django development server 運作時,卻又沒有問題。他搞了非常久,大概有一個月吧!

我幫他 debug 時,一開始,我就把問題縮小在 IE 瀏覽這 apache 上的測試網站時,它不會紀錄 Cookies,沒用 Cookies ,那怎麼保持認證連線呢! 只是那時候,我也是找不出為什麼那該死的 IE 就是沒法使用 Cookies ,而優秀的 Firefox 就可以呢! 然後,我使用了 Ubuntu Linux 配置這個測試網站結果發現它可以讓 IE 正常運作,所以我們當時只能歸納這問題,一定是他的 XP 出了狀況。

結果前兩天,他要把測試網站放到業主的機器上去 run 時,還是出了相同的問題,然而這次不一樣的是那個機器有兩個 django-based site ,但一個正常,一個不正常。這就有點說不過去了。

於是,這次我請教了 Google 大神,問它: django cookie session problem ie ,而它回我: http://code.djangoproject.com/ticket/7264#comment:3

這原來是 _ 的錯,因為學弟習慣將測試網址設成 test_XXX.YYY.ZZZ ,而我習慣設成 XXXtest.YYY.ZZZ ,因為我知道在買網址時只可以買英數字加連字詞(-)的,所以我不會在網域名稱中放入 _ ,也就是這個習慣讓我在 Ubuntu Linux 中架的測試網站是可以讓 IE 正常使用,但學弟架在 Windows 上的測試網址卻包含了 _ ,讓 IE 勇於拒絕他的要求了。

這同時也解釋了為什麼在 django development server 運作時, IE 可以正常的現象,因為它會使用 http://127.0.0.1:8000/ 作瀏覽網址。

哈哈,真不曉得該怪 IE ,還是得怪 Firefox 呢! 不過,話說回來,要是早點問 Google 大神,這問題就不會拖一個月了。

二月 11, 2009

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 把 Mercurial 用 mod_python 裝在 Apache 中

實際上, Mercurial 這種分散式版本控制器是不太需要架個 Web Server 來 Run 的,尤其是我多半都是獨自在寫程式,但架了個 Web Server 後,我會比較方便在多台個人電腦中轉移陣地,且這也多了一種備份的機制。

不過,目前已有人將 hg 成功移植成 GAE 版(hg-repos.appspot.com),現在只待作者把說明文件完成,我就會將跑在 apache 上的部份儲存庫再移至 GAE 去。

廢話不多說,透過 mod_python 來跑 HTTPS 版的 Mercurial 儲存庫方式如下:

一、 下載 modpython_gateway.py ,載點何處? Google 比較快且安全。下載後放到 /raid1/A2B2/www/HG/ (可自行更換其他資料夾) ,也就是在 apache.conf 中所設定 PythonPath 。此檔案內容不用修改。

二、 設定如何執行 modpython_gateway.py ,一樣在 /raid1/A2B2/www/HG/ 下,新增一個 hgwebdir.py ,其內容如下:


import os
os.environ["HGENCODING"] = "UTF-8"

from mercurial.hgweb.hgweb_mod import hgweb
from mercurial.hgweb.hgwebdir_mod import hgwebdir
from mercurial.hgweb.request import wsgiapplication

def make_web_app():
return hgwebdir("/raid1/A2B2/www/HG/hgweb.config")

def test(environ, start_response):
toto = wsgiapplication(make_web_app)
return toto (environ, start_response)


三、 設定你的檔案庫位置,一樣在 /raid1/A2B2/www/HG 下新增一個 hgweb.config 其內容如下:

[paths]
/trachg = /raid1/A2B2/www/trac/hg

[collections]
#我把 /raid1/A2B2/www/HG/product soft link 到 /product
#這樣在連結上,才會是用 /product/product1 來觀看 product1 儲存庫。
/PathDoesNotMatter = /product/

[web]
style = gitweb
allow_archive = bz2 gz zip


四、 apache.conf 設定如下:

<virtualhost *:443>
--ServerSignature Off
--ServerName hg.yoursite.name
--DocumentRoot /raid1/A2B2/www/HG/tmp
--RewriteEngine On
--RewriteRule ^/(.*) /DoesNotMatter/$1
--<Location />
----PythonPath "sys.path + [ '/raid1/A2B2/www/HG' ]"
----#PythonDebug On #Uncomment this ligne if you got a problem and need debug information
----SetHandler mod_python
----PythonHandler modpython_gateway::handler
----#PythonOption SCRIPT_NAME /repo
----PythonOption wsgi.application hgwebdir::test
----AuthType Basic
----AuthName "Mercurial Repository"
----AuthUserFile /raid1/A2B2/www/auth_users
----Require valid-user
--</Location>
--LogLevel warn
--ErrorLog /var/log/apache2/hg_error.log
--CustomLog /var/log/apache2/hg_access.log combined
--SSLEngine On
--SSLCertificateFile /etc/apache2/ssl/apache.pem
</virtualhost>

五、 重啟 apache

你就會在 https://hg.yoursite.name/ 中,看到 trachg 、 product/product1 、 product/XXXproduct ... 的儲存庫了。

二月 9, 2009

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» 難道我真的是 Windows 白癡! 搞個 https 憑證花了一個上午還是沒成功

照著這位仁兄的筆記: http://blog.roodo.com/myroodo/archives/4219557.html ,就是會在最後一個指令

> openssl ca -config openssl.cnf -days 3650 -cert ssl/ca.crt -keyfile ssl/ca.key -in ssl/server.csr -out ssl/server.crt

出現

I am unable to access the ssl
ewcerts directory
ssl
ewcerts: Invalid argument

查了相當多的地方,也找不出原因。後來想想,這不過是個憑證,它是一種資料,所以它應該與平台無關,且之前我在 Linux 上作了那麼多的憑證,也沒遇過機器重灌,憑證得重作的現象,所以它應與當時製作的平台也無關,索性在 Ubuntu 上打了三個指令,作出憑證,再送到 Windows 去用。

您猜猜,這麼著了?

It's Work~

一月 21, 2009

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» Trac + Mercurial on Apache 的亂碼問題

這個問題搞了我很久。

用 trac 內帶的 tracd 來跑, changelog 部份的中文就是正常的,但跑在 apache 上時,它就亂了,而且只亂 changelog 部份,程式碼的 diff 結果及 raw 格式都沒事。

看了很久的 mercurial-plugin-0.11 程式碼,看來看去覺得這應該是 mercurial 的錯,不過為什麼我在 shell 中用沒事,或是用 tracd 跑也沒問題,但它跑在 apache 上就錯了呢???

hg 在讀 changelog 的部份,它是用 mercurial.changelog.changelog 函式來處理,但裡面有一個 read() 被 mercurial-plugin 拿來用了,而這個 read 函式在解讀字串時,要叫用 util.tolocal() 來處理編碼,只要沒設定 os.environ['HGENCODING'] 的話,它就會預設為 ascii ,這就是造成 changelog 亂碼問題的地方。

以前,我只須在 /etc/python2.5/sitecustomize.py 設定 sys.setdefaultencoding('utf8') 就行了,現在還得加上 os.environ['HGENCODING'] = 'utf-8' 。

我還是不太懂 os 及 sys 的差別是什麼?

十二月 4, 2007

hoamon's sandbox
hoamon
hoamon's sandbox is about »

tag cloud

» apache2 + ssl on ubuntu 7.04

和 Fedora 的設定方式稍有不同。

1. 產生認證檔案
sudo mkdir /etc/apache2/ssl
sudo make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /etc/apache2/ssl/apache.pem

2. 修改設定檔案 /etc/apache2/sites-available/ssl
NameVirtualHost *:443
<virtualhost *:443>
  ServerAdmin webmaster@localhost
  ...
  ...
  SSLEngine On
  SSLCertificateFile /etc/apache2/ssl/apache.pem
</virtualhost>

3. 重新啟動 Apache 伺服器
sudo /etc/init.d/apache2 restart

八月 17, 2006
» HTTPD Installation Quick-Note

快速簡記:如何在 Debian 上佈署 LAMP 環境 (Linux/ Apache/ MySQL/ PHP)
,其中包含如何快速建立 https 加密伺服環境。

—LAMP Setup

biggo.com.tw

A Django site.