コンテンツにスキップ

静的サイトを配信する

ファイルの配信は Pingclair の仕事のもう半分です。このページは rootfile_server から始めて、圧縮、キャッシュヘッダー、部分取得、シングルページ アプリケーションに必要なフォールバックまで組み立て、各段階でサーバーが実際に何を 返すかを示します。

  • Pingclair が導入され動いていること(インストール)。実験中は サービスを停止します: sudo pc service stop
  • 配信するディレクトリ。例では /srv/site を使います。
http://:8080 {
root * /srv/site
file_server
}
ターミナルウィンドウ
sudo cp Pingclairfile /etc/Pingclair/Pingclairfile
sudo pingclair validate /etc/Pingclair/Pingclairfile
sudo systemctl restart pingclair
curl -i http://localhost:8080/
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Last-Modified: Tue, 22 Sep 2026 04:37:54 GMT
ETag: "5e-6ab20622"
Accept-Ranges: bytes

root * はすべてのリクエストに対するサイトのルートを設定し、file_server が そこから配信します。存在しないパスは 404 を返します。

http://:8080 {
root * /srv/site
encode zstd gzip
file_server
}

引数は優先順です。同じ 36 KB のテキストファイルを 3 種類の Accept-Encoding で 要求した、この構成での実測:

zstd 200 65 bytes content-encoding: zstd
gzip 200 301 bytes content-encoding: gzip
identity 200 36000 bytes (no content-encoding)

Brotli はプロキシ応答には実装されておらず、要求すると静かな降格ではなく コンパイルエラーになります。

Error: ❌ Configuration Error: Compile error: Unsupported feature: `encode br`: Brotli is not implemented for proxied responses; use `encode zstd gzip`

メッセージが代替を示します。サーバーが果たせないことを要求する設定は、そもそも 実行されません。

file_server はすでに条件付きリクエストに応答します。上の ETagLast-Modified は、クライアントが If-None-MatchIf-Modified-Since で返す 値です。保持期間はあなたが決めるもので、それが真になるパスに置きます。

http://:8080 {
root * /srv/site
encode zstd gzip
header Cache-Control "public, max-age=60"
@assets path /assets/*
header @assets Cache-Control "public, max-age=31536000, immutable"
file_server
}

実測: ページは Cache-Control: public, max-age=60/assets/*public, max-age=31536000, immutable。immutable が正直なのは、ファイル名が内容と ともに変わる場合だけです。だからビルドツールは名前にハッシュを足します。

部分取得に設定は要りません。先頭 10 バイトを求めたクライアントはそれを受け取り ます。

HTTP/1.1 206 Partial Content
Content-Length: 10
Content-Range: bytes 0-9/36000

🧭 シングルページアプリケーション

Section titled “🧭 シングルページアプリケーション”

ブラウザ側でルーティングするアプリケーションは、未知のパスすべてで入り口の 文書を返す必要があります。実在するファイルはそのまま配信されます。

http://:8080 {
root * /srv/site
try_files {path} /index.html
file_server
}

実測: /assets/big.txt は自分の内容で 200 を返し続け、/some/spa/routeindex.html200 を返します。try_files の行が無いと、2 番目は 404 です。

file_server browse は index ファイルの無いディレクトリの一覧を表示します。

http://:8080 {
root * /srv/site
file_server browse
}

一覧は項目名を並べるので、/assets/Index of の見出しとともに big.txt を 表示します。そのように読ませたいディレクトリでなければ browse は付けません。

⚠️ ドットファイルは他のファイルと同じように配信されます。上の構成で .hidden200 を返しました。.git.env、エディタのバックアップがインターネットに出る のはこの経路です。除外するには、ファイルサーバーが動く前に応答します。

http://:8080 {
root * /srv/site
@hidden path /.*
respond @hidden "Not found" 404
file_server
}

実測: /.hidden404//assets/big.txt200 のまま。403 ではなく 404 なのは意図的です。403 はファイルの存在を肯定してしまいます。

  • Unsupported feature: 'encode br' Brotli は名前を挙げて拒否されます。 encode zstd gzip を使います。
  • Unknown directive 'file_server: …' そのオプションは存在せず、validate は黙って無視せず拒否した綴りを示します。
  • ページではなくディレクトリ一覧が出る。 そのディレクトリに index.html が ありません。望んだ結果か、ファイルの置き忘れです。
  • アプリケーションが扱うルートで 404 シングルページのフォールバックが ありません: try_files {path} /index.html
  • 再読み込みしても新しいページが出ない。 再読み込みが適用するのはポリシーで、 新しいリスナーではありません。ファイルはリクエストごとに読まれるので、ファイル 追加は即時で、リスナーの移動はそうではありません (サービスとして動かす)。