Caddyfile 概念
本文件將協助您詳細了解 HTTP Caddyfile。
結構
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_server
和 reverse_proxy
是指令。指令是網站區塊中一行上的第一個字詞。
在第二個範例中,localhost:9000
是引數,因為它出現在指令後同一行上。
有時指令可以開啟它們自己的區塊。子指令出現在指令區塊中每行的開頭
localhost {
reverse_proxy localhost:9000 localhost:9001 {
lb_policy first
}
}
這裡,lb_policy
是 reverse_proxy
的子指令(它設定用於後端之間的負載平衡政策)。
除非另有說明,否則指令不能用於其他指令區塊中。例如,basicauth
不能用於 file_server
中,因為檔案伺服器不知道如何進行驗證;但你可以在 route
、handle
和 handle_path
區塊中使用指令,因為它們特別設計為將指令分組在一起。
請注意,當 HTTP Caddyfile 被調整時,HTTP 處理常式會根據特定的預設 指令順序 排序,除非在 route
區塊中,因此指令出現的順序並不重要,除了在 route
區塊中。
符號和引號
在解析之前,Caddyfile 會被分析成代幣。空白在 Caddyfile 中很重要,因為代幣是由空白分隔的。
通常,指令會預期一定數量的引數;如果單一引數的值有空白,它會被分析成兩個獨立的代幣
directive abc def
這可能會造成問題並傳回錯誤或意外的行為。
如果 abc def
應該是單一引數的值,它需要被加上引號
directive "abc def"
如果你需要在帶引號的代幣中使用引號,也可以對引號進行跳脫
directive "\"abc def\""
若要避免跳脫引號,可以使用反引號 ` `
來封裝令牌;例如
directive `{"foo": "bar"}`
在引號令牌內,所有其他字元都會被視為字面值,包括空格、標籤和換行符。因此,多行令牌是可行的
directive "first line
second line"
Heredocs 也受支援:
example.com {
respond <<HTML
<html>
<head><title>Foo</title></head>
<body>Foo</body>
</html>
HTML 200
}
開啟 heredoc 標記必須以 <<
開頭,後接任何文字(建議使用大寫字母)。關閉 heredoc 標記必須是相同的文字(在上述範例中,為 HTML
)。開啟標記可以使用 \<<
進行跳脫以防止 heredoc 分析,視需要而定。
關閉標記可以縮排,這會導致每一行文字都移除這麼多的縮排(靈感來自 PHP),這對於在 區塊 內提升可讀性很有幫助,同時也能很好地控制令牌文字中的空白。尾隨換行符也會被移除,但可以在關閉標記前加入額外的空白行來保留它。
其他令牌可以作為指令的引數,緊接在關閉標記之後(例如在上述範例中,狀態碼 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 可以從位址推論出您網站的 scheme、主機和埠。如果位址沒有埠,則 Caddyfile 會選擇與 scheme 相符的埠(如果已指定),否則會假設預設埠 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 處理器 指令 預設套用於所有要求(除非另有說明)。
要求比對器 可用於依據特定條件分類要求。使用比對器,您可以明確指定特定指令套用於哪些要求。
對於支援比對器的指令,指令後的第 1 個參數為比對器代碼。以下是一些範例
root * /var/www # matcher token: *
root /index.html /var/www # matcher token: /index.html
root @post /var/www # matcher token: @post
比對器代碼可以完全省略以比對所有要求;例如,如果下一個參數看起來不像路徑比對器,則不需要提供 *
。
閱讀要求比對器頁面以進一步了解。
佔位符
您可以在 Caddyfile 中使用任何 Caddy 佔位符,但為方便起見,您也可以使用一些等效的簡寫
簡寫 | 取代 |
---|---|
{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.*} |
{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"
}
閱讀 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
註解的雜湊字元 #
不能出現在令牌中間(即它必須前面有空格或出現在行的開頭)。這允許在 URI 或其他值中使用雜湊,而不需要引號。
環境變數
如果您的組態依賴於環境變數,您可以在 Caddyfile 中使用它們
{$ENV}
此形式的環境變數會在 Caddyfile 解析開始之前 替換,因此它們可以擴充為空值(即 ""
)、部分令牌、完整令牌,甚至多個令牌和行。
例如,環境變數 UPSTREAMS="app1:8080 app2:8080 app3:8080"
會擴充為多個 令牌
example.com {
reverse_proxy {$UPSTREAMS}
}
當找不到環境變數時,可以使用 :
作為變數名稱和預設值之間的分隔符號,指定預設值
{$DOMAIN:localhost} {
}
如果您想 延後替換 環境變數直到執行階段,您可以使用 標準 {env.*}
佔位符。請注意,並非所有組態參數都支援這些佔位符,因為模組開發人員需要新增一行程式碼來執行替換。如果它似乎不起作用,請提交問題以請求支援。
例如,如果您已安裝 caddy-dns/cloudflare
外掛程式 並希望組態 DNS 挑戰,您可以像這樣將您的
CLOUDFLARE_API_TOKEN
環境變數傳遞給外掛程式
{
acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
如果您將 Caddy 作為 systemd 服務執行,請參閱 這些說明 以設定服務覆寫來定義您的環境變數。