Caddy,一個用Go實現的Web Server

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

 

這是一個Web Server的時代,apache2與nginx共舞,在追求極致效能的路上,沒有最高,只有更高。但這又是一個追求個人化的時代,有些Web Server並沒有去擠“Performance提升”這一獨木橋,而是有著自己的定位,Caddy就是這樣一個開源Web Server。

Caddy的作者Matt Holt在caddy官網以及FAQ中對caddy的目標闡釋如下: 其他Web Server為Web而設計,Caddy為human設計。功能定位上,與經常充當最前端反向 Proxy的nginx不同,caddy致力於成為一個易用的靜態 檔案Web Server。可以看出Caddy主打易用性,使用配置簡單。並且得益於Go的跨平台特性,caddy很容易的支援了三大主流平台:Windows、 Linux、Mac。在Caddy開發人員文檔中,我們可以看到caddy還可以在Android(linux arm)上運行。caddy目前版本為0.7.1,還不穩定,且後續版本可能變化較大,甚至與前期版本不相容,因此作者目前不推薦caddy在生產環境被 重度使用。

關注caddy,是因為caddy填補了go在通用web server這塊的空白(也許有其他,但我還不知道),同時Web server in go也“響應”了近期Golang去C化的趨勢(Go 1.5中C is gone!),即便caddy作者提到caddy的目標並非如nginx那樣。但未來誰知道呢?一旦Go效能足夠高時,一旦caddy足夠穩定時,自然而 然的就會有人將其用在某些應用的生產環境中替代nginx或apache2了。一套全Go的系統,在部署、營運方面也是有優勢的。

一、安裝和運行caddy

和諸多go應用一樣,我們可以直接從caddy的github.com releases頁中找到最新發行版(目前是0.7.1)的二進位包。這裡使用的是caddy_darwin_amd64.zip。

下載解壓後,進入目錄,直接執行./caddy即可將caddy運行起來。

$caddy
0.0.0.0:2015

在瀏覽器裡訪問localhost:2015,頁面上沒有預期顯示的類似"caddy works!”之類的預設Welcome頁面,而是“404 Not Found"。雖然這說明caddy已經work了,但沒有一個default welcome page畢竟對於caddy beginer來說並不友好。這裡已經向作者提了一個sugguestion issue。

二、caddy原理

Go的net/http標準庫已經提供了http server的實現,大多數場合這個http server都能滿足你的需要,無論是功能還是效能。Caddy實質上也是一個Go web app,它也import net/http,嵌入*http.Server,並通過handler的ServeHTTP方法為每個請求提供服務。caddy使用 http.FileServer作為處理 靜態檔案的基礎。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
}

為了實現風格上的統一,單一網站也最好配置為如下這種格式(代碼內部稱之為    Server Block):

localhost:2015 {
    gzip
    log ./2015.log
}

這樣Caddyfile的設定檔範本樣式類似於下面這樣:

host1:port {
    middleware1
    middleware2 {
        … …
    }
    … …
}

host2:port {
    middleware1
    middleware2 {
        … …
    }
    … …
}
… …

關於middleware,在caddy文檔中有較為詳細的說明和例子。對於caddy這樣一個年輕的開源項目而言,其文檔還算是相對較全的,雖 然現在還不能和nginx、 apache比。

caddy中的middleware就是一個實現了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的函數原型與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))的調用傳遞。

前面說過caddy是基於http.FileServer的靜態檔案Web Server,FileServer總會作為middleware chain的最後一環,如果沒有配置任何middleware,那你的server就是一個靜態檔案server。

三、caddy典型應用

【靜態檔案Server】

caddy的最基礎應用實際就是一個靜態檔案Server,底層由http.FileServer承載,當然caddy封裝了http.FileServer,做了一些攔截處理,最後將w, r傳遞給http.ServeContent去處理檔案資料。

第一次執行./caddy,實際上就啟動了一個靜態檔案Server。但這個server不預設支援你navigate directory。如果你知道website root目錄(如果沒有指定root,則caddy執行的當前路徑會作為website的root路徑)下的檔案名稱,比如foo.txt,你可以在瀏覽器 中輸入:localhost:2015/foo.txt,caddy會執行正確的服務,瀏覽器也會顯示foo.txt的全文。

對於靜態檔案Server,caddy支援在website的root路徑下首先尋找是否有如下四個檔案:

//caddy/middleware/browse/browse.go
var IndexPages = []string{
    "index.html",
    "index.htm",
    "default.html",
    "default.htm",
}

如果查到有其中一個,則優先返回這個檔案內容,這就是靜態網站的首頁。

如果要支援目錄檔案清單瀏覽,則需要為website配置browse middleware,這樣對於無index file的目錄,我們可以看到目錄檔案清單。

localhost:2015 {
    browse
}   

【反向 Proxy】

caddy支援基本的反向 Proxy功能。反向 Proxy配置通過proxy middleware實現。

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(輪詢調度)。

負載平衡同樣是通過proxy middleware實現的。

localhost:2015 {
    log ./2015.log

    proxy / localhost:9001 localhost:9003 {
        policy round_robin
    }
    proxy /bar localhost:9002 localhost:9004 {
        policy least_conn
    }
}

【支援fastcgi代理】

caddy同樣支援fastcgi代理,可以將請求通過fastcgi介面發送給後端的實現fastcgi的server。我們以一個"hello world"的php server為例。

mac os上內建了php-fpm,一個實現了fastcgi的php cgi進程管理器。caddy將請求轉寄給php-fpm監聽的連接埠,後者會啟動php-cgi解譯器,解釋index.php,並將結果返回給caddy。

mac os上的php-fpm預設沒有隨機啟動。我們需要簡單配置一下:

$mkdir phptest
$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

編輯php-fpm.conf,保證下面兩項是非注釋狀態的:

error_log = log/php-fpm.log
listen = 127.0.0.1:9000 

我們通過network socket進行fastcgi通訊。

回到phptest目錄下,執行:

php-fpm -p ~/test/go/caddy/phptest

執行後,php-fpm就會轉入後台執行了。

接下來我們來配置Caddyfile:

localhost:2015 {
    fastcgi / 127.0.0.1:9000 php
    log ./2015.log
}

這裡配置的含義是:將全部請求轉寄到9000連接埠,這裡的php是一個preset(預配置集合),相當於:

ext   .php
split .php
index index.php

我們在phptest目錄下建立一個index.php檔案,內容如下:

<?php echo "Hello World\n"; ?>

好了,現在啟動caddy,並使用瀏覽器訪問localhost:2015試試。你會看到"Hello World"呈現在瀏覽器中。

【git push發布】

對於一些靜態網站,caddy支援git directive,實現在server啟動以及運行時定期git pull你的項目庫,將最新更新pull到server上。

caddy文檔中給出兩個例子:

第一個是一個php網站,定期pull項目庫,實現server更新:

git git@github.com:user/myphpsite {
    key /home/user/.ssh/id_rsa
}
fastcgi / 127.0.0.1:9000 php

第二個是一個hugo支撐的靜態網站,每次pull後,執行hugo命令產生新的靜態頁面:

git github.com/user/site {
    path  ../
    then  hugo –destination=/home/user/hugosite/public
}

注意:git directive並非middleware,而是一個單獨的goroutine實現的。

四、小結

caddy的功能不局限於上面的幾個例子,上面只是幾個最為常見的情境而已。caddy目前還很年輕,應用不多,但知名golang網站 gopheracademy.com(GopherCon組織方)是由Caddy support的。caddy還在積極進化,有興趣的Gopher可持續關注。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.