# 🧠 設定モデル Pingclairfile は読み込み時に一度だけコンパイルされ、サーバーが実際に実行する状態になります。そこから 2 つの帰結が生まれ、このプロジェクトの挙動のほとんどを説明します。設定が決められることは最初のリクエストより前に済みます。そして満たせない設定は、リクエスト時に妥協するのではなく、サーバーを停止させます。 ## 🗂️ ファイル構造 ファイルは省略可能な global options ブロックと、それに続く 1 つ以上の site block で構成されます。 ```caddyfile { 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 } ``` - **Global options** はファイル先頭の名前のないブロックに書き、サイト単位ではない状態を設定します。ACME アカウントのメールアドレス、Admin API、自動 HTTPS の挙動、trusted proxies、ホスト名上流の DNS 再解決などです。利用できるオプションは[ディレクティブ一覧](/ja/reference/directives/#global-options)にあります。 - **Site block** はアドレスで名前を付けます。ホスト、ポート、またはその両方です。ポートは独立したディレクティブではなくアドレスの一部なので、両者の一致を保つ場所は 1 か所で済みます。 - **ディレクティブ**は site block 内の文です。引数リストを取るもの、ネストしたブロックを取るもの、両方を取るものがあります。 - **コメント**は `#` から行末までです。 - **空白を含む値は引用符で囲みます。** 時間の長さには単位が必要です。`30s` は 30 秒で、長さが求められる場所に裸の `30` を書くと拒否されます。 ## 🧭 マッチャー マッチャーは、あるディレクティブをどのリクエストに適用するかを選びます。名前付きマッチャーは `@name` で宣言し、名前で参照します。 ```caddyfile example.com { @api path /api/* header @api Cache-Control "no-store" @assets path /assets/* header @assets Cache-Control "public, max-age=31536000, immutable" } ``` `handle` ブロックはルートごとに挙動をまとめ、マッチャーを伴わないフォールバックも書けます。 ```caddyfile example.com { handle /assets/* { file_server ./assets } handle { respond "Page Not Found" 404 } } ``` ## 🧩 スニペットと import スニペットは再利用可能な断片で、`(name) { ... }` として宣言し、`import name` で取り込みます。呼び出し側からブロックを受け取り、スニペット内の `{block}` の位置に挿入することもできます。 ```caddyfile (site) { https://{args[0]} { {block} } } import site example.com { reverse_proxy 127.0.0.1:3000 } ``` import されたファイルで定義されたスニペットは、それより後の import から参照できます。引数リストの中に置かれたプレースホルダーは拒否されます。ディレクティブ木は、挿入後にその行をトークン層のように再解析できないためです。 ## 🛡️ 検証 `pingclair validate` はファイルをコンパイルし、意味的な検査を行います。ディレクティブの引数、マッチャーの構文、証明書と鍵のパス、そして「どの対端がクライアント識別ヘッダーを主張できるか」といったポリシー制約です。 失敗は明示的で、閉じた方向に倒れます。 - **未実装の名前は名前で拒否されます。** 形式が定義する名前はすべて認識され、実装がないものは「機能が存在しない」というメッセージを出します。綴り間違いとして扱われることも、無視されることもありません。それを含む設定は起動しません。 - **満たせないオプションは拒否され、降格しません。** たとえば `encode` に Brotli を指定するとコンパイルエラーになります。プロキシにストリーミングの Brotli エンコーダーがないためで、黙って gzip を配信することはありません。 - **構文が正しくても、存在しないものを参照するファイルは拒否されます。** リポジトリの `examples/full_featured.pingclair` は正しい Caddyfile 構文ですが、依然として拒否されます。そこに書かれた証明書パスが、検査を実行するマシンに存在しないからで、拒否は正しい判断です。 同じ検査は読み込み時にも実行されるため、再読み込みで検証に失敗しても直前の状態は保たれます。 ## 🔁 再読み込み 再読み込みはプロセスを再起動せずに設定を読み直します。信号は `SIGUSR1` です。 ```bash sudo kill -USR1 "$(systemctl show -p MainPID --value pingclair)" ``` `pingclair reload` は Admin API 経由で同じコードに到達し、サーバーがファイルをどう見たかを報告します。グローバルオプションの `admin` が必要です。 `pc service reload` はインストールされたユニットを通してこの信号を送るので、明らかな命令がそのまま動く命令です。答えは終了コードにはありません——`systemctl reload` が報告できるのは信号が届いたことだけです——ユニットの status line とジャーナルにあり、拒否された再読み込みは古い設定を動かしたままにします([issue #66](https://github.com/dorianverlaine/pingclair/issues/66) は、それでも成功を報告していたユニットの版を記録しています)。`trusted_proxies` のように起動時に確立されるプロセス全体のポリシーは再起動後に反映され、リスナーを変える設定も再起動が必要です。