Skip to content

About

Cloudflare-native NixOS Binary Cache infrastructure.

Topics

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Repository files navigation

cf-edgeNix — Cloudflare-native NixOS binary cache

Cloudflare-native NixOS binary cache

English | 日本語

cf-edgeNixは独立したプロジェクトであり、Cloudflare社とは提携、推奨、または出資を受けているものではありません。
Cloudflare、Cloudflare Workers、およびR2は、Cloudflare, Inc.の商標です。

cf-edgeNix は Cloudflare Workers に署名付き Nix binary cache 基盤をdeployするプロジェクトです。
R2 が NAR / narinfo の正本、Workers Cache が配信キャッシュ、D1 が build 履歴・latest・rollback root・GC live-set を持つ control plane。narinfo / NAR は Workers Cache → R2 で配信し、D1 を経由しない。KV は quota 状態と任意の nix-cache-info コピーを保持する。

Self-hosted、かつ Cloudflare 内で完結。 自分の Cloudflare アカウントに自分の Worker を deploy する形なので、cache も署名鍵も完全に自分の手元にあり、サードパーティを経由しない。
さらに実体は Cloudflare のエッジ(Workers + R2 + KV + D1 + Workers Cache + Workers Builds)に閉じており、VPS も origin server もコンテナも、GitHub Actions の deploy pipeline も不要。
Cloudflare の外で動くのは、自分の NixOS flake repo に置いた GitHub Actions job が cf-edgeNix を checkout してその scripts/publish.sh を回し、署名済み NAR を build & upload する部分だけ。

flake repo 側に publish ロジックは持たず、.github/templates/publish-cache.yml の workflow テンプレートをそのまま配置するだけで済む。

目標は Cloudflare 無料枠で global な署名付き binary cache を持つ こと。

Deploy

Deploy Button

Deploy to Cloudflare

Required env, Secret

名前 設定場所 用途
ADMIN_TOKEN Worker Secret 管理 API の認証。未設定だと publish などの書き込み操作と定期 GC が動かない。
CF_ANALYTICS_TOKEN Worker Secret R2 使用量を調べる quota Cron 用。未設定だと quota チェックをスキップする。
CF_ACCOUNT_ID wrangler.toml の [vars] quota チェック対象の Cloudflare アカウント ID。
QUOTA_R2_BUCKET_NAME wrangler.toml の [vars] quota チェック対象の R2 バケット名。

NixOS の flake リポジトリで publish workflow を使う場合は、そのリポジトリの GitHub Environment production に次を登録する。ADMIN_TOKEN は Worker に登録した値と同じにする。

名前 種別 用途
CACHE_PRIVATE_KEY Secret Nix binary cache の署名秘密鍵。
ADMIN_TOKEN Secret Worker 管理 API の認証。
R2_ACCESS_KEY_ID / R2_SECRET_ACCESS_KEY Secret R2 S3 API の認証情報。
API_BASE_URL Variable デプロイ済み Worker の URL。
CLOUDFLARE_ACCOUNT_ID Variable Cloudflare アカウント ID。
R2_BUCKET_NAME Variable publish 先の R2 バケット名。

R2・KV・D1 の binding ID の設定や鍵生成は セットアップガイド を参照。

機能

Nix binary cache protocol

  • nix-cache-info(Priority / WantMassQuery 設定可)
  • 署名付き .narinfo(Ed25519 / nix-store --generate-binary-cache-key)
  • zstd 圧縮 NAR を /nar/<file-hash>.nar.zst で配信
  • HTTP Range(bytes=start-end / bytes=start- / bytes=-suffix)に対応し 206 を返す
  • hono/zod-openapi で自動生成された OpenAPI 3.0 スキーマを /api/openapi.json で公開

Control plane (D1)

  • staging → ingest → finalize の 3 段 publish、finalize が 1 つの db.batch() で latest を atomic に更新
  • 決定論的 build_id = sha256(host:system:gitRev:flakeLockHash:toplevelStorePath)[:36] — 再実行は冪等
  • host ごとの build 履歴 + rollback root 登録
  • host ごとの最新 3 世代と pin / rollback root を保持し、narinfo 非公開化から NAR 削除まで 1 時間の猶予を強制する世代 GC

Edge & cost

  • narinfo / NAR は Workers Cache(edge・Worker 手前)→ R2(正本)。404 も短 TTL の negative cache
  • 5 分おきの Cron が Cloudflare GraphQL Analytics から R2 storage / Class A / Class B を読む
  • 月次無料枠 80% で warn、95% で killed。killed 中は read path が 503 を返して課金事故を防ぐ
  • POST /api/quota/reset で手動解除

Operations

  • Bearer 認証付き管理 API(ADMIN_TOKEN)。未設定時は write 系を 403 で拒否
  • Cloudflare Workers Builds が main push で自動 deploy(CI deploy workflow も GitHub Secrets の Cloudflare token も不要)
  • publish ごとに R2 へ manifest を保存し cold-start 復元に使う
  • Drizzle ORM schema / migration は migrations/ 配下

nixos-rebuild から cache を使う

{
  nix.settings = {
    extra-substituters = [ "https://cf-edgenix.<account>.workers.dev" ];
    extra-trusted-public-keys = [ "nix-cache.example.com-1:xxxx=" ];
  };
}

sudo nixos-rebuild switch --flake .#<host> で反映。設定を書き換えず一度だけ試したい場合:

sudo nixos-rebuild switch --flake .#myhost \
  --option extra-substituters "https://cf-edgenix.<account>.workers.dev" \
  --option extra-trusted-public-keys "nix-cache.example.com-1:xxxx="

nixos-rebuild は以下の順で(全て認証なしで)Worker を叩く:

  1. GET /nix-cache-info — セッションごとに 1 回。StoreDir が一致しないと Nix はその cache を拒否する。
  2. GET /<store-hash>.narinfo — store path ごとに 1 回。404 なら次の substituter にフォールバック。
  3. GET /nar/<file-hash>.nar.zst — narinfo がヒットしたときだけ取得。Range で途中再開可能。

疎通確認:

curl -sSf https://cf-edgenix.<account>.workers.dev/nix-cache-info
curl -sSfI https://cf-edgenix.<account>.workers.dev/<store-hash>.narinfo

アーキテクチャ

Read path — narinfo

flowchart LR
    Client[Nix client] --> WC[(Workers Cache<br/>edge)]
    WC -. miss .-> W[Worker]
    W --> R2[(R2: NAR_BUCKET)]
Loading

Workers Cache ヒット時は Worker 自体が起動しない(request collapsing 内蔵)。miss 時は R2 を直接読み、無ければ 404 を返して 60 秒だけ edge にキャッシュする。Worker 起動時の quota 判定は引き続き KV を読む。nix-cache-info は Workers Cache → KV → R2 → 既定値 の順で解決する。

Read path — NAR 本体

flowchart LR
    Client[Nix client] -->|GET/HEAD, Range| WC[(Workers Cache<br/>edge)]
    WC -. miss .-> W[Worker]
    W --> R2[(R2: NAR_BUCKET)]
Loading

Range: bytes=... をエッジまで通す(206 は edge に保存されず常に R2 から streaming)。full 200 は content-addressed かつ immutable として edge にキャッシュされる。miss 時は R2 から buffer せず streaming で返す。

Publish path

flowchart LR
    GHA[GitHub Actions<br/>publish 側 repo] --> P[closure 分類・new のみ NAR 化]
    P -->|POST /api/publish/*| W[Worker]
    P --> R2[(R2)]
    W --> D1[(D1: CONTROL_DB)]
Loading

latest を動かすのは start → ingest × N → R2 upload → finalize の 1 ルートのみ。staging closure を R2 操作より先に登録し、GC と publish の競合を防ぐ。 full closure を分類し、external は manifest のみに記録する。owned のうち new だけ NAR 化する。NAR upload → narinfo upload → D1 確定の順序は scripts/publish.ts の batch 経路で保証し、test/publish/publish-script.test.ts で検証している。

Deploy path

flowchart LR
    Repo[cf-edgeNix repo<br/>push to main] --> CFB[Cloudflare<br/>Workers Builds]
    CFB --> W[Worker]
Loading

GitHub Actions の deploy workflow は持たない。
Workers Builds が push のたびに wrangler d1 migrations apply --remote && wrangler deploy を回す。

ドキュメント

項目 ファイル
初回セットアップ(鍵生成・Cloudflare リソース・deploy・クライアント設定) docs/setup.md
publish フロー / 冪等性 / 公開順序 / トラブルシューティング docs/publish.md
エンドポイント一覧 docs/api.md
Quota kill-switch 運用 docs/quota.md
設計仕様(フル) docs/spec.md
未解決の設計課題 docs/fixme.md
開発・テスト・環境変数リファレンス CONTRIBUTING.md

About

Cloudflare-native NixOS Binary Cache infrastructure.

Topics

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages