Caddy 一個用Go實現(xiàn)的Web Server
這是一個Web Server的時代,apache2與nginx共舞,在追求極致性能的路上,沒有最高,只有更高。但這又是一個追求個性化的時代,有些Web Server并沒有去擠“Performance提升”這一獨木橋,而是有著自己的定位,Caddy就是這樣一個開源Web Server。
Caddy的作者Matt Holt在caddy官網(wǎng)以及FAQ中對caddy的目標闡釋如下: 其他Web Server為Web而設計,Caddy為human設計。功能定位上,與經(jīng)常充當最前端反向代理的nginx不同,caddy致力于成為一個易用的靜態(tài) 文件Web Server。可以看出Caddy主打易用性,使用配置簡單。并且得益于Go的跨平臺特性,caddy很容易的支持了三大主流平臺:Windows、 Linux、Mac。在Caddy開發(fā)者文檔中,我們可以看到caddy還可以在Android(linux arm)上運行。caddy目前版本為0.7.1,還不穩(wěn)定,且后續(xù)版本可能變化較大,甚至與前期版本不兼容,因此作者目前不推薦caddy在生產(chǎn)環(huán)境被 重度使用。
關注caddy,是因為caddy填補了go在通用web server這塊的空白(也許有其他,但我還不知道),同時Web server in go也“響應”了近期Golang去C化的趨勢(Go 1.5中C is gone!),即便caddy作者提到caddy的目標并非如nginx那樣。但未來誰知道呢?一旦Go性能足夠高時,一旦caddy足夠穩(wěn)定時,自然而 然的就會有人將其用在某些應用的生產(chǎn)環(huán)境中替代nginx或apache2了。一套全Go的系統(tǒng),在部署、運維方面也是有優(yōu)勢的。
一、安裝和運行caddy
和諸多go應用一樣,我們可以直接從caddy的github.com releases頁中找到最新發(fā)布版(目前是0.7.1)的二進制包。這里使用的是caddy_darwin_amd64.zip。
下載解壓后,進入目錄,直接執(zhí)行./caddy即可將caddy運行起來。
$caddy
0.0.0.0:2015
在瀏覽器里訪問localhost:2015,頁面上沒有預期顯示的類似"caddy works!”之類的默認Welcome頁面,而是“404 Not Found"。雖然這說明caddy已經(jīng)work了,但沒有一個default welcome page畢竟對于caddy beginer來說并不友好。這里已經(jīng)向作者提了一個sugguestion issue。
二、caddy原理
Go的net/http標準庫已經(jīng)提供了http server的實現(xiàn),大多數(shù)場合這個http server都能滿足你的需要,無論是功能還是性能。Caddy實質(zhì)上也是一個Go web app,它也import net/http,嵌入*http.Server,并通過handler的ServeHTTP方法為每個請求提供服務。caddy使用 http.FileServer作為處理 靜態(tài)文件的基礎。caddy的誘人之處在于其middleware,將諸多middleware串成一個middleware chain以提供了靈活的web服務。另外caddy中的middleware還可以獨立于caddy之外使用。
caddy從當前目錄的Caddyfile(默認)文件中讀取配置,當然你也可以通過-conf指定配置文件路徑。Caddyfile的配置格式 的確非常easy,這也符合caddy的目標。
Caddyfile總是以站點的Addr開始的。
單一站點的Caddyfile樣例如下:
//Caddyfile localhost:2015 gzip log ./2015.log
Caddy也支持配置多個站點,類似virtualhost的 配置(80端口多路復用):
//Caddyfile foo.com:80 { log ./foo.log gzip } bar.com:80 { log ./bar.log gzip }
為了實現(xiàn)風格上的統(tǒng)一,單一站點也最好配置為如下這種格式(代碼內(nèi)部稱之為 Server Block):
localhost:2015 { gzip log ./2015.log }
這樣Caddyfile的配置文件模板樣式類似于下面這樣:
host1:port { middleware1 middleware2 { … … } … … } host2:port { middleware1 middleware2 { … … } … … } … …
關于middleware,在caddy文檔中有較為詳細的說明和例子。對于caddy這樣一個年輕的開源項目而言,其文檔還算是相對較全的,雖 然現(xiàn)在還不能和nginx、 apache比。
caddy中的middleware就是一個實現(xiàn)了middleware.Handler接口的struct,例如gzip這個 middleware:
// middleware.go type Middleware func(Handler) Handler type Handler interface { ServeHTTP(http.ResponseWriter, *http.Request) (int, error) } // gzip/gzip.go type Gzip struct { Next middleware.Handler } func (g Gzip) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") { return g.Next.ServeHTTP(w, r) } …. … gz := gzipResponseWriter{Writer: gzipWriter, ResponseWriter: w} // Any response in forward middleware will now be compressed status, err := g.Next.ServeHTTP(gz, r) … … }
middleware.Handler的函數(shù)原型與http.Handler的不同,不能直接作為http.Server的Handler使用。caddy使用了下面這個idiomatic go pattern:
type appHandler func(http.ResponseWriter, *http.Request) (int, error)
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if status, err := fn(w, r); err != nil { http.Error(w, err.Error(), status) } }
當然這個pattern有很多變種,但思路大致類似。一個middleware chain大致就是handler1(handler2(handler3))的調(diào)用傳遞。
前面說過caddy是基于http.FileServer的靜態(tài)文件Web Server,F(xiàn)ileServer總會作為middleware chain的最后一環(huán),如果沒有配置任何middleware,那你的server就是一個靜態(tài)文件server。
三、caddy典型應用
【靜態(tài)文件Server】
caddy的最基礎應用實際就是一個靜態(tài)文件Server,底層由http.FileServer承載,當然caddy封裝了http.FileServer,做了一些攔截處理,最后將w, r傳遞給http.ServeContent去處理文件數(shù)據(jù)。
第一次執(zhí)行./caddy,實際上就啟動了一個靜態(tài)文件Server。但這個server不默認支持你navigate directory。如果你知道website root目錄(如果沒有指定root,則caddy執(zhí)行的當前路徑會作為website的root路徑)下的文件名,比如foo.txt,你可以在瀏覽器 中輸入:localhost:2015/foo.txt,caddy會執(zhí)行正確的服務,瀏覽器也會顯示foo.txt的全文。
對于靜態(tài)文件Server,caddy支持在website的root路徑下首先查找是否有如下四個文件:
//caddy/middleware/browse/browse.go var IndexPages = []string{ "index.html", "index.htm", "default.html", "default.htm", }
如果查到有其中一個,則優(yōu)先返回這個文件內(nèi)容,這就是靜態(tài)站點的首頁。
如果要支持目錄文件列表瀏覽,則需要為website配置browse middleware,這樣對于無index file的目錄,我們可以看到目錄文件列表。
localhost:2015 { browse }
【反向代理】
caddy支持基本的反向代理功能。反向代理配置通過proxy middleware實現(xiàn)。
localhost:2015 { log ./2015.log proxy /foo localhost:9001 proxy /bar localhost:9002 }
當你訪問localhost:2015/foo時,實際上訪問的是9001端口的服務程序;
當你訪問localhost:2015/bar時,實際上訪問的是9002端口的服務程序。
【負載均衡】
Caddy支持負載均衡配置,并支持三種負載均衡算法:random(隨機)、least_conn(最少連接)以及round_robin(輪詢調(diào)度)。
負載均衡同樣是通過proxy middleware實現(xiàn)的。
localhost:2015 { log ./2015.log proxy / localhost:9001 localhost:9003 { policy round_robin } proxy /bar localhost:9002 localhost:9004 { policy least_conn } }
【支持fastcgi代理】
caddy同樣支持
mac os上自帶了php-fpm,一個實現(xiàn)了fastcgi的php cgi進程管理器。caddy將請求轉(zhuǎn)發(fā)給php-fpm監(jiān)聽的端口,后者會啟動php-cgi解釋器,解釋index.php,并將結(jié)果返回給caddy。 mac os上的php-fpm默認沒有隨機啟動。我們需要簡單配置一下: $mkdir phptest 編輯php-fpm.conf,保證下面兩項是非注釋狀態(tài)的: error_log = log/php-fpm.log 我們通過network socket進行fastcgi通信。 回到phptest目錄下,執(zhí)行: php-fpm -p ~/test/go/caddy/phptest 執(zhí)行后,php-fpm就會轉(zhuǎn)入后臺執(zhí)行了。 接下來我們來配置Caddyfile: 這里配置的含義是:將全部請求轉(zhuǎn)發(fā)到9000端口,這里的php是一個preset(預配置集合),相當于: 我們在phptest目錄下創(chuàng)建一個index.php文件,內(nèi)容如下: <?php echo "Hello World\n"; ?> 好了,現(xiàn)在啟動caddy,并使用瀏覽器訪問localhost:2015試試。你會看到"Hello World"呈現(xiàn)在瀏覽器中。 【git push發(fā)布】 對于一些靜態(tài)站點,caddy支持git directive,實現(xiàn)在server啟動以及運行時定期git pull你的項目庫,將最新更新pull到server上。 caddy文檔中給出兩個例子: 第一個是一個php站點,定期pull項目庫,實現(xiàn)server更新: 第二個是一個hugo支撐的靜態(tài)站點,每次pull后,執(zhí)行hugo命令生成新的靜態(tài)頁面: 注意:git directive并非middleware,而是一個單獨的goroutine實現(xiàn)的。 四、小結(jié) caddy的功能不局限于上面的幾個例子,上面只是幾個最為常見的場景而已。caddy目前還很年輕,應用不多,但知名golang網(wǎng)站 gopheracademy.com(GopherCon組織方)是由Caddy support的。caddy還在積極進化,有興趣的Gopher可持續(xù)關注。
$mkdir -p phptest/etc
$mkdir -p phptest/log
$cd phptest
$sudo cp /private/etc/php-fpm.conf.default ./etc
$cd ./etc
$sudo chown tony php-fpm.conf.default
$mv php-fpm.conf.default php-fpm.conf
listen = 127.0.0.1:9000
localhost:2015 {
fastcgi / 127.0.0.1:9000 php
log ./2015.log
}
ext .php
split .php
index index.php
git git@github.com:user/myphpsite {
key /home/user/.ssh/id_rsa
}
fastcgi / 127.0.0.1:9000 php
git github.com/user/site {
path ../
then hugo –destination=/home/user/hugosite/public
}
相關文章
完美解決IIS和APACHE的301重定向(帶參數(shù))
感覺BAIDU spider對404的重定向似乎無動于衷,于是近日干脆對原失效的鏈接重新設置301重定向。2010-11-11WINPE3.0集成RAID陣列卡驅(qū)動的實現(xiàn)方法
這篇文章主要介紹了WINPE3.0集成RAID陣列卡驅(qū)動的實現(xiàn)方法,需要的朋友可以參考下2016-07-07