跳到內容

設定模型

Pingclair 在載入 Pingclairfile 時編譯設定,預先完成位址解析與匹配器編譯等工作,供後續請求使用。不支援或無效的設定會在載入時被拒絕。本頁說明 v0.2.2 的設定載入與重載方式。

🗂️ 檔案由全域選項與網站區塊組成

Section titled “🗂️ 檔案由全域選項與網站區塊組成”
{
email admin@example.com
}
example.com {
encode zstd gzip
reverse_proxy 10.0.0.10:8080 10.0.0.11:8080
}
:8080 {
file_server ./public
}
  • 全域選項 寫在檔案最上方一個沒有名稱的區塊裡。它們設定不屬於任何單一網站的事:ACME 帳號的 email、Admin API、自動 HTTPS、受信任的代理,以及主機名稱上游的 DNS 重新解析。指令參考列出了所有全域選項。
  • 網站區塊 以位址命名:主機、連接埠,或兩者皆有。連接埠是位址的一部分,而不是另一個指令,所以位址與監聽器不可能互相矛盾。
  • 指令 是網站區塊內的敘述。有些接受參數,有些接受巢狀區塊,有些兩者都接受。
  • 註解 以 # 開頭,直到該行結尾。
  • 含有空白的值要加引號。 時間長度必須帶單位:30s 是三十秒,在需要時間長度的地方寫一個單獨的 30 會被拒絕。

具名匹配器以 @name 宣告,使用時把名稱寫在指令後面:

example.com {
@api path /api/*
header @api Cache-Control "no-store"
@assets path /assets/*
header @assets Cache-Control "public, max-age=31536000, immutable"
}

handle 區塊把同一條路由的指令放在一起。一個請求只會由一個 handle 區塊回應,而沒有匹配器的 handle 會接住其他區塊沒接到的所有請求:

example.com {
handle /assets/* {
file_server ./assets
}
handle {
respond "Page Not Found" 404
}
}

路由先依指令種類排序,第一條匹配的路由負責回應。redir、handle 與 route 排在 respond 之前,respond 又排在 reverse_proxy、php_fastcgi 與 file_server 之前。相同指令的單一路徑先比較移除尾端 * 後的長度,再將精確路徑排在同名萬用路徑之前,其餘保留檔案順序。多路徑或無路徑的匹配器排在單一路徑之後。

使用互斥的 handle 區塊區分路由,或用 route 保留書寫順序。路徑比較忽略 ASCII 大小寫,並解碼一次百分比編碼;需要區分大小寫時使用 path_regexp。handle、handle_path 與 route 在區塊前只接受 *、以 / 開頭的路徑或 @name,不接受 *.php 這類裸字串。

CHANGELOG · Pingclairfile

片段(snippet)是以 (name) { ... } 宣告、以 import name 插入的可重用設定。呼叫端可以傳入參數與一個區塊;片段在寫著 {block} 的地方接收那個區塊:

(site) {
https://{args[0]} {
{block}
}
}
import site example.com {
reverse_proxy 127.0.0.1:3000
}

在被匯入的檔案中定義的片段,後續的匯入都看得到。指令參數清單內的佔位符會被拒絕:Caddy 在插入片段後會重新讀取那一行,而 Pingclair 的 parser 做不到,因此會拒絕這種寫法並顯示錯誤。

🛡️ 驗證會拒絕伺服器做不到的事

Section titled “🛡️ 驗證會拒絕伺服器做不到的事”

pingclair validate 會編譯檔案,並執行語法以外的檢查:指令參數、匹配器語法、憑證與金鑰檔案是否存在,以及政策限制,例如哪些對端可以設定用戶端身分相關的標頭。

沒通過這些檢查的設定不會執行。判斷失敗與否的規則有三條:

  • 未實作的名稱會被指名拒絕。 Pingclair 認得 Caddyfile 格式定義的每一個名稱。對於沒有實作的名稱,它會回報該功能不存在;絕不會把它當成拼錯的字,也絕不會默默忽略。
  • 不支援的選項會被拒絕。 encode br 是編譯錯誤,因為沒有串流式的 Brotli 編碼器;不會自動改用 gzip。
  • 語法正確但指向不存在的檔案,仍然是錯誤。 伺服器儲存庫中的 examples/full_featured.pingclair 語法正確,但在它所指的憑證路徑不存在的機器上,validate 仍會拒絕它。

伺服器載入檔案時也會執行相同的檢查,重載時也一樣。

🔁 重載在不重啟的情況下替換設定

Section titled “🔁 重載在不重啟的情況下替換設定”

重載會重新讀取檔案、編譯,並在行程持續執行的同時把結果換上去。如果新檔案編譯失敗,先前的設定會繼續提供服務。要求重載有三種方式:

  • pc service reload(或 systemctl reload pingclair)透過已安裝的 unit 送出 SIGUSR1。
  • sudo kill -USR1 "$(systemctl show -p MainPID --value pingclair)" 直接送出同一個訊號。
  • pingclair reload 透過 Admin API 進行,並印出伺服器的判定結果。它需要 admin 全域選項。

systemctl reload 只能回報訊號已送達,所以伺服器的判定結果會出現在 unit 的狀態列與 journal 中。

有些變更無法透過重載套用;這時伺服器會拒絕重載並保留舊設定,而不是只套用其中一部分:

  • 監聽器的變更。 新增、移除或搬移位址,或讓監聽器在明文與 TLS 之間切換,都需要重啟,因為監聽 socket 是在啟動時建立的。Unix 上從空設定啟動可第一次載入明文 HTTP;TLS 與後續拓撲變更仍需重啟。
  • 全域選項。 啟動時就確定的選項(例如 trusted_proxies)作用於整個行程,修改這類政策需要重啟;行程日誌設定可重載。
  • 憑證拓撲。 新增 TLS 主機名稱,或改變網站取得憑證的方式,都需要重啟。

拒絕訊息會指出是哪一項變更,例如 listener topology changed (added: …, removed: …);執行 sudo pc service restart 即可套用。

以服務方式執行說明各種重載結果。