文件
一個 專案

Caddyfile 概念

本文檔將幫助您詳細了解 HTTP Caddyfile。

  1. 結構
  2. 全域選項
  3. 位址
  4. 匹配器
  5. 佔位符
  6. 程式碼片段
  7. 具名路由
  8. 註解
  9. 環境變數

結構

Caddyfile 的結構可以用視覺方式描述

Caddyfile structure

重點

  • 一個可選的 全域選項區塊 可以是檔案中的第一個項目。

  • 程式碼片段具名路由 可以選擇性地出現在後面。

  • 否則,Caddyfile 的第一行始終是要服務的站點的 位址

  • 所有 指令匹配器 必須 放在站點區塊中。站點區塊之間沒有全域範圍或繼承。

  • 如果只有一個站點區塊,則其大括號 { } 是可選的。

一個 Caddyfile 至少包含一個或多個站點區塊,這些區塊始終以一個或多個站點的 位址 開頭。在位址之前出現的任何指令都會讓解析器感到困惑。

區塊

使用大括號完成區塊的開啟和關閉

... {
	...
}
  • 左大括號 { 必須在其行的末尾,並以空格開頭。

  • 右大括號 } 必須在其自己的行上。

當只有一個站點區塊時,大括號(和縮排)是可選的。這是為了方便快速定義單個站點,例如,這個

localhost

reverse_proxy /api/* localhost:9001
file_server

等同於

localhost {
	reverse_proxy /api/* localhost:9001
	file_server
}

當您只有一個站點區塊時;這是一個偏好問題。

要使用相同的 Caddyfile 配置多個站點,您必須在每個站點周圍使用大括號以分隔它們的配置

example1.com {
	root * /www/example.com
	file_server
}

example2.com {
	reverse_proxy localhost:9000
}

如果請求與多個站點區塊匹配,則選擇具有最特定匹配位址的站點區塊。請求不會級聯到其他站點區塊。

指令

指令 是功能性關鍵字,用於自訂站點的服務方式。它們必須出現在站點區塊中。例如,一個完整的文件伺服器配置可能如下所示

localhost {
	file_server
}

或反向代理

localhost {
	reverse_proxy localhost:9000
}

在這些範例中,file_serverreverse_proxy 是指令。指令是站點區塊中一行的第一個單字。

在第二個範例中,localhost:9000 是一個引數,因為它出現在指令後的同一行上。

有時指令可以開啟它們自己的區塊。子指令 出現在指令區塊內每行的開頭

localhost {
	reverse_proxy localhost:9000 localhost:9001 {
		lb_policy first
	}
}

在這裡,lb_policyreverse_proxy 的子指令(它設定後端之間使用的負載平衡策略)。

除非另有說明,否則指令不能在其他指令區塊內使用。 例如,basic_auth 不能在 file_server 內使用,因為文件伺服器不知道如何進行身份驗證;但是您可以在 routehandlehandle_path 區塊中使用指令,因為它們專門設計用於將指令組合在一起。

請注意,當 HTTP Caddyfile 被改編時,HTTP 處理程序指令會根據特定的預設 指令順序 排序,除非在 route 區塊中,因此指令的出現順序無關緊要,除非在 route 區塊中。

Token 和引號

Caddyfile 在被解析之前會被詞法分析為 token。空格在 Caddyfile 中很重要,因為 token 由空格分隔。

通常,指令期望一定數量的引數;如果單個引數的值包含空格,它將被詞法分析為兩個單獨的 token

directive abc def

這可能會產生問題並返回錯誤或意外行為。

如果 abc def 應該是單個引數的值,則需要用引號括起來

directive "abc def"

如果您需要在帶引號的 token 中也使用引號,則可以轉義引號

directive "\"abc def\""

為了避免轉義引號,您可以改用反引號 ` ` 括住 token;例如

directive `{"foo": "bar"}`

在帶引號的 token 內,所有其他字元都被視為字面值,包括空格、Tab 鍵和換行符。因此,可以有多行 token

directive "first line
	second line"

Heredoc 也被支援:

example.com {
	respond <<HTML
		<html>
		  <head><title>Foo</title></head>
		  <body>Foo</body>
		</html>
		HTML 200
}

開頭的 heredoc 標記必須以 << 開頭,後跟任何文字(建議使用大寫字母)。結尾的 heredoc 標記必須是相同的文字(在上面的範例中,為 HTML)。如果需要,可以使用 \<< 轉義開頭標記以防止 heredoc 解析。

結尾標記可以縮排,這會導致每一行文字都剝離那麼多的縮排(靈感來自 PHP),這對於 區塊 內的易讀性很好,同時可以很好地控制 token 文字中的空格。尾隨換行符也會被剝離,但可以通過在結尾標記之前新增一個額外的空行來保留。

其他 token 可以跟在結尾標記後面,作為指令的引數(例如在上面的範例中,狀態碼 200)。

全域選項

Caddyfile 可以選擇性地以一個特殊的區塊開頭,該區塊沒有鍵,稱為 全域選項區塊

{
	...
}

如果存在,它必須是配置中的第一個區塊。

它用於設定全域應用或不特定於任何一個站點的選項。在其中,只能設定全域選項;您不能在其中使用常規站點指令。

例如,要啟用 debug 全域選項,該選項通常用於產生詳細日誌以進行故障排除

{
	debug
}

閱讀全域選項頁面 以了解更多資訊。

位址

位址始終出現在站點區塊的頂部,並且通常是 Caddyfile 中的第一個項目。

以下是有效位址的範例

位址 效果
example.com HTTPS 與託管的 公開信任憑證
*.example.com HTTPS 與託管的 萬用字元公開信任憑證
localhost HTTPS 與託管的 本地信任憑證
http:// HTTP 捕捉所有,受 http_port 影響
https:// HTTPS 捕捉所有,受 https_port 影響
http://example.com 顯式 HTTP,帶有 Host 匹配器
example.com:443 HTTPS 由於匹配 https_port 預設值
:443 HTTPS 捕捉所有,由於匹配 https_port 預設值
:8080 非標準端口上的 HTTP,沒有 Host 匹配器
localhost:8080 非標準端口上的 HTTPS,由於具有有效的網域
https://example.com:443 HTTPS,但 https://:443 都是多餘的
127.0.0.1 HTTPS,帶有本地信任的 IP 憑證
http://127.0.0.1 HTTP,帶有 IP 位址 Host 匹配器(拒絕 localhost

從位址,Caddy 可以潛在地推斷您站點的方案、主機和端口。如果位址沒有端口,Caddyfile 將選擇與指定的方案匹配的端口,或者將假定預設端口 443。

如果您指定主機名,則只會接受具有匹配 Host 標頭的請求。換句話說,如果站點位址是 localhost,則 Caddy 將不匹配對 127.0.0.1 的請求。

可以使用萬用字元 (*),但僅用於表示主機名的一個標籤。例如,*.example.com 匹配 foo.example.com 但不匹配 foo.bar.example.com,並且 * 匹配 localhost 但不匹配 example.com。有關實際範例,請參閱 萬用字元憑證模式

要捕捉所有主機,請省略位址的主機部分,例如,僅僅 https://。當使用 隨需 TLS 時,這很有用,當您事先不知道網域時。

如果多個站點共享相同的定義,您可以將它們全部列在一起,以空格和逗號分隔(至少需要一個空格)。以下三個範例是等效的

# Comma separated site addresses
localhost:8080, example.com, www.example.com {
	...
}

# Space separated site addresses
localhost:8080 example.com www.example.com {
	...
}

# Comma and new-line separated site addresses
localhost:8080,
example.com,
www.example.com {
	...
}

位址必須是唯一的;您不能多次指定相同的位址。

佔位符 不能 在位址中使用,但您可以在其中使用 Caddyfile 樣式的 環境變數

{$DOMAIN:localhost} {
	...
}

預設情況下,站點會綁定到所有網路介面。如果您希望覆蓋此行為,請使用 bind 指令default_bind 全域選項 來執行此操作。

匹配器

HTTP 處理程序 指令 預設應用於所有請求(除非另有說明)。

請求匹配器 可用於根據給定標準對請求進行分類。使用匹配器,您可以準確指定特定指令應用於哪些請求。

對於支援匹配器的指令,指令後的第一個引數是匹配器 token。以下是一些範例

root *           /var/www  # matcher token: *
root /index.html /var/www  # matcher token: /index.html
root @post       /var/www  # matcher token: @post

可以完全省略匹配器 token 以匹配所有請求;例如,如果下一個引數看起來不像路徑匹配器,則不需要給出 *

閱讀請求匹配器頁面 以了解更多資訊。

佔位符

佔位符 是一種將動態值注入到靜態配置中的簡單方法。它們可以用作指令和子指令的引數。

佔位符兩側以大括號 { } 為界,並包含內部的識別符,例如:{foo.bar}。開頭的佔位符大括號可以轉義 \{like.this} 以防止替換。佔位符識別符通常使用點命名空間,以避免跨模組衝突。

哪些佔位符可用取決於上下文。並非所有佔位符都在配置的所有部分中可用。例如,HTTP 應用程式設定僅在與處理 HTTP 請求相關的配置區域中可用的佔位符(即在 HTTP 處理程序 指令匹配器 中,但不在 tls 配置 中)。某些指令或匹配器也可能設定它們自己的佔位符,這些佔位符可以被隨後的任何內容使用。某些佔位符 是全域可用的

您可以在 Caddyfile 中使用任何佔位符,但為了方便起見,您也可以使用其中一些等效的簡寫,這些簡寫在解析 Caddyfile 時會展開

簡寫 替換為
{cookie.*} {http.request.cookie.*}
{client_ip} {http.vars.client_ip}
{dir} {http.request.uri.path.dir}
{err.*} {http.error.*}
{file_match.*} {http.matchers.file.*}
{file.base} {http.request.uri.path.file.base}
{file.ext} {http.request.uri.path.file.ext}
{file} {http.request.uri.path.file}
{header.*} {http.request.header.*}
{host} {http.request.host}
{hostport} {http.request.hostport}
{labels.*} {http.request.host.labels.*}
{method} {http.request.method}
{path.*} {http.request.uri.path.*}
{path} {http.request.uri.path}
{port} {http.request.port}
{query.*} {http.request.uri.query.*}
{query} {http.request.uri.query}
{re.*} {http.regexp.*}
{remote_host} {http.request.remote.host}
{remote_port} {http.request.remote.port}
{remote} {http.request.remote}
{rp.*} {http.reverse_proxy.*}
{resp.*} {http.intercept.*}
{scheme} {http.request.scheme}
{tls_cipher} {http.request.tls.cipher_suite}
{tls_client_certificate_der_base64} {http.request.tls.client.certificate_der_base64}
{tls_client_certificate_pem} {http.request.tls.client.certificate_pem}
{tls_client_fingerprint} {http.request.tls.client.fingerprint}
{tls_client_issuer} {http.request.tls.client.issuer}
{tls_client_serial} {http.request.tls.client.serial}
{tls_client_subject} {http.request.tls.client.subject}
{tls_version} {http.request.tls.version}
{upstream_hostport} {http.reverse_proxy.upstream.hostport}
{uri} {http.request.uri}
{vars.*} {http.vars.*}

並非所有配置欄位都支援佔位符,但大多數在您期望的地方都支援。對佔位符的支援需要已明確新增到這些欄位。外掛程式作者可以閱讀本文,以了解如何在他們自己的模組中新增對佔位符的支援。

程式碼片段

您可以通過給予它們一個括在括號中的名稱來定義稱為程式碼片段的特殊區塊

(logging) {
	log {
		output file /var/log/caddy.log
		format json
	}
}

然後您可以使用特殊的 import 指令在任何需要的地方重複使用它

example.com {
	import logging
}

www.example.com {
	import logging
}

import 指令也可用於在其位置包含其他檔案。如果引數與定義的程式碼片段不匹配,它將嘗試作為檔案。它還支援 glob 以導入多個檔案。作為一種特殊情況,它可以出現在 Caddyfile 中的任何位置(除了作為另一個指令的引數),包括站點區塊之外

{
	email admin@example.com
}

import sites/*

您可以將引數傳遞給導入的配置(程式碼片段或檔案),並像這樣使用它們

(snippet) {
	respond "Yahaha! You found {args[0]}!"
}

a.example.com {
	import snippet "Example A"
}

b.example.com {
	import snippet "Example B"
}

⚠️ 實驗性 | v2.9.x+

您還可以將可選區塊傳遞給導入的程式碼片段,並按如下方式使用它們。

(snippet) {
	{block}
	respond "OK"
}

a.example.com {
	import snippet {
		header +foo bar
	}
}

b.example.com {
	import snippet {
		header +bar foo
	}
}

閱讀 import 指令頁面 以了解更多資訊。

具名路由

⚠️ 實驗性

具名路由使用類似於 程式碼片段 的語法;它們是在站點區塊外部定義的特殊區塊,以 &( 為前綴,並以 ) 結尾,名稱在中間。

&(app-proxy) {
	reverse_proxy app-01:8080 app-02:8080 app-03:8080
}

然後您可以在任何站點中重複使用此具名路由

example.com {
	invoke app-proxy
}

www.example.com {
	invoke app-proxy
}

如果許多不同的站點需要相同的路由,或者如果需要多個不同的匹配器條件來調用相同的路由,這尤其有用,可以減少記憶體使用量。

閱讀 invoke 指令頁面 以了解更多資訊。

註解

註解以 # 開頭,並持續到行尾

# Comments can start a line
directive  # or go at the end

用於註解的井字號字元 # 不能出現在 token 的中間(即它必須以空格開頭或出現在行的開頭)。這允許在 URI 或其他值中使用井字號,而無需引號。

環境變數

如果您的配置依賴於環境變數,您可以在 Caddyfile 中使用它們

{$ENV}

此形式的環境變數在 Caddyfile 解析開始之前 被替換,因此它們可以展開為空值(即 "")、部分 token、完整 token,甚至多個 token 和行。

例如,環境變數 UPSTREAMS="app1:8080 app2:8080 app3:8080" 將展開為多個 token

example.com {
	reverse_proxy {$UPSTREAMS}
}

當找不到環境變數時,可以使用 : 作為變數名稱和預設值之間的分隔符來指定預設值

{$DOMAIN:localhost} {

}

如果您想延遲環境變數的替換直到運行時,您可以使用 標準 {env.*} 佔位符。請注意,並非所有配置參數都支援這些佔位符,因為模組開發人員需要新增一行程式碼來執行替換。如果它似乎不起作用,請提交 issue 以請求對其的支援。

例如,如果您已安裝 caddy-dns/cloudflare 外掛程式 並希望配置 DNS 挑戰,您可以將您的 CLOUDFLARE_API_TOKEN 環境變數傳遞給外掛程式,如下所示

{
	acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}

如果您以 systemd 服務運行 Caddy,請參閱 這些說明,以設定服務覆蓋以定義您的環境變數。