文件
一個 專案,由 ZeroSSL 出品

Caddyfile 支援

Caddy 模組透過其命名空間在 原生 JSON 配置 中自動新增,當它們被 註冊 時,使其既可用又附帶文件。這使得 Caddyfile 支援成為純粹可選的功能,但它經常被偏好 Caddyfile 的使用者所要求。

Unmarshaler(解組器)

要為您的模組新增 Caddyfile 支援,只需實作 caddyfile.Unmarshaler 介面。您可以透過解析 token 的方式來選擇您的模組所擁有的 Caddyfile 語法。

解組器的工作很簡單,就是設定您的模組類型,例如透過使用傳遞給它的 caddyfile.Dispenser 來填充其欄位。例如,一個名為 Gizmo 的模組類型可能具有以下方法

// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
//
// gizmo <name> [<option>]
//
func (g *Gizmo) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next() // consume directive name

	if !d.Args(&g.Name) {
		// not enough args
		return d.ArgErr()
	}
	if d.NextArg() {
		// optional arg
		g.Option = d.Val()
	}
	if d.NextArg() {
		// too many args
		return d.ArgErr()
	}

	return nil
}

最好在方法的 godoc 註解中記錄語法。有關解析 Caddyfile 的更多資訊,請參閱 caddyfile 套件的 godoc

可以使用簡單的 d.Next() 呼叫來消耗/跳過指令名稱 token。

請務必使用 d.NextArg()d.RemainingArgs() 檢查是否缺少和/或過多的參數。對於簡單的「無效案例」訊息,請使用 d.ArgErr(),或使用 d.Errf("some message") 來製作有用的錯誤訊息,其中包含問題的解釋(理想情況下,還有建議的解決方案)。

您也應該新增一個 介面保護,以確保介面得到正確滿足

var _ caddyfile.Unmarshaler = (*Gizmo)(nil)

區塊

若要接受比單行更多的配置,您可能希望允許帶有子指令的區塊。這可以使用 d.NextBlock() 並迭代直到返回原始巢狀層級來完成

for nesting := d.Nesting(); d.NextBlock(nesting); {
	switch d.Val() {
		case "sub_directive_1":
		// ...
		case "sub_directive_2":
		// ...
	}
}

只要迴圈的每次迭代都消耗整個區段(行或區塊),那麼這就是處理區塊的優雅方法。

HTTP 指令

HTTP Caddyfile 是 Caddy 的預設 Caddyfile 適配器語法(或「伺服器類型」)。它是可擴展的,這表示您可以 註冊 您自己的模組「頂層」指令

func init() {
	httpcaddyfile.RegisterDirective("gizmo", parseCaddyfile)
}

如果您的指令只返回單個 HTTP 處理器(很常見),您可能會發現 RegisterHandlerDirective 更容易

func init() {
	httpcaddyfile.RegisterHandlerDirective("gizmo", parseCaddyfileHandler)
}

基本概念是,您與指令關聯的 解析函數 會傳回一個或多個 ConfigValue 值。(或者,如果使用 RegisterHandlerDirective,它只會直接傳回已填充的 caddyhttp.MiddlewareHandler 值。)每個配置值都與一個 「類別」 相關聯,這有助於 HTTP Caddyfile 適配器了解它可以用於最終 JSON 配置的哪個部分。所有配置值都會被轉儲到一個堆疊中,適配器在建構最終 JSON 配置時會從中提取。

這種設計允許您的指令傳回任何已識別類別的任何配置值,這表示它可以影響 HTTP Caddyfile 適配器具有指定類別的配置的任何部分。

如果您已經實作了 UnmarshalCaddyfile() 方法,那麼您的解析函數可以像以下一樣簡單

// parseCaddyfileHandler unmarshals tokens from h into a new middleware handler value.
func parseCaddyfileHandler(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
	var g Gizmo
	err := g.UnmarshalCaddyfile(h.Dispenser)
	return g, err
}

有關如何使用 httpcaddyfile.Helper 類型的更多資訊,請參閱 httpcaddyfile 套件 godoc

處理器順序

所有傳回 HTTP 中介軟體/處理器值的指令都需要以正確的順序評估。例如,設定網站根目錄的處理器必須在存取根目錄的處理器之前執行,以便它知道目錄路徑是什麼。

HTTP Caddyfile 對於標準指令具有硬編碼的順序。這確保了使用者不需要了解其網路伺服器最常用功能的實作細節,並使他們更容易編寫正確的配置。單個硬編碼列表也防止了 Caddyfile 可擴展性的不確定性。

當您註冊新的處理器指令時,必須將其添加到該列表才能使用(在 route 區塊之外)。 這可以使用以下三種方法之一完成

  • (推薦)外掛程式作者可以在註冊指令後在 init() 中呼叫 httpcaddyfile.RegisterDirectiveOrder,以將指令插入到相對於另一個 標準指令 的順序中。這樣做,使用者可以直接在其站點中使用該指令,而無需額外設定。例如,若要將您的指令 gizmo 插入到在 header 處理器之後評估

    httpcaddyfile.RegisterDirectiveOrder("gizmo", httpcaddyfile.After, "header")
    
  • 使用者可以新增 order 全域選項 來修改其 Caddyfile 的標準順序。例如:order gizmo before respond 將插入一個新的指令 gizmo,以便在 respond 處理器之前評估。然後可以正常使用該指令。

  • 使用者可以將指令放在 route 區塊 中。由於 route 區塊中的指令不會重新排序,因此在 route 區塊中使用的指令不需要出現在列表中。

如果您選擇後兩種選項之一,請為您的使用者記錄關於列表中哪個位置是您的指令正確排序位置的建議,以便他們可以正確使用它。

類別

下表描述了 HTTP Caddyfile 適配器識別的每個類別及其導出的類型

類別名稱 預期類型 描述
bind []string 伺服器監聽器綁定位址
route caddyhttp.Route HTTP 處理器路由
error_route *caddyhttp.Subroute HTTP 錯誤處理路由
tls.connection_policy *caddytls.ConnectionPolicy TLS 連線策略
tls.cert_issuer certmagic.Issuer TLS 憑證簽發者
tls.cert_loader caddytls.CertificateLoader TLS 憑證載入器

伺服器類型

在結構上,Caddyfile 是一種簡單的格式,因此可以有不同類型的 Caddyfile 格式(有時稱為「伺服器類型」)以滿足不同的需求。

預設的 Caddyfile 格式是 HTTP Caddyfile,您可能對此很熟悉。此格式主要配置 http 應用程式,同時僅可能在 Caddy 配置結構的其他部分(例如,tls 應用程式以載入和自動化憑證)中加入一些配置。

若要配置 HTTP 以外的應用程式,您可能需要實作您自己的配置適配器,該適配器使用 您自己的伺服器類型。Caddyfile 適配器實際上會為您解析輸入,並為您提供伺服器區塊和選項的列表,而您的適配器則有責任理解該結構並將其轉換為 JSON 配置。