コンテンツにスキップ

Storefront メンテナンス運用 Runbook

目的

Vendure が停止している場合でも、Cloudflare KV を直接更新して Storefront のメンテナンスモードを切り替える。

通常運用では、Vendure Dashboard のメンテナンスモード画面または Admin GraphQL(maintenanceSettings / updateMaintenanceSettings / rotateMaintenanceBypassToken)を使う。Cloudflare Dashboard / API / CLI の直接操作は、Vendure 停止時または緊急オペレーション時に限定する。

正本

  • Worker binding: MAINTENANCE_KV
  • KV key: storefront:maintenance

値は次の JSON とする。

{
  "enabled": true,
  "bypassToken": "32charhex",
  "updatedAt": "2026-03-11T00:00:00.000Z"
}

事前準備

  • 対象環境の Cloudflare Account ID
  • 対象環境の KV Namespace ID
  • 対象 namespace への read / write が可能な API token
  • 対象環境の *_shared secret に CLOUDFLARE_MAINTENANCE_KV_NAMESPACE_ID が設定済みであること

実行判断と責任

  • 通常時: Vendure Dashboard または Admin GraphQL を優先する
  • 緊急時: Vendure 停止などで通常導線が使えない場合のみ、本 runbook で Cloudflare KV を直接更新する
  • 実行者: システム管理者または緊急対応を任された運用責任者
  • 記録: 切替時刻、対象環境、実施者、確認結果を運用ログへ残す

開始前チェックリスト

  • 対象環境(staging / production)を確認した
  • Cloudflare Account ID / Namespace ID / API token を確認した
  • 既存の bypassToken を維持する前提で作業することを確認した
  • 一般アクセスと回避 URL の両方で確認する準備ができている

namespace はメンテナンス専用ではなく、Storefront 固有のランタイム設定ストアとして運用する。ec project 全体での共通設定が必要になった場合のみ、別の共有 namespace を追加する。

namespace 未作成時は、認証済み環境で次を実行して作成する。

just cloudflare-maintenance-kv-create production
just cloudflare-maintenance-kv-create staging

Cloudflare Dashboard で切り替える

  1. Cloudflare Dashboard を開く
  2. Workers & Pages から対象 Worker を選ぶ
  3. Storage & Databases または KV Namespace 一覧から対象 namespace を開く
  4. storefront:maintenance キーを選択する
  5. JSON の enabled を切り替え、updatedAt を現在時刻へ更新して保存する

定時スケジュール窓の設定

毎日決まった時間帯を定時メンテナンス時間窓として登録すると、enabled: false (手動メンテナンス OFF)のままでも自動的にメンテナンスモードへ切り替えられる。時間帯は Asia/Tokyo で指定する。enabled は全体の有効/無効ではなく手動ONのフラグであり、予約時間は scheduleWindows として別トリガーで効く。

通常運用では Vendure Dashboard の /maintenance-mode にある「毎日の予約時間」から設定する。画面上部の 「手動メンテナンス」が OFF でも、予約時間が設定されている場合は「予約ON」または「予約時間中」と表示される。Cloudflare KV の直接編集は Vendure Dashboard が使えない障害時の復旧手段として扱う。

Storefront runtime は KV の scheduleWindows を UTC ではなく JST の日次時刻として解釈する。たとえば 02:00-04:00 と入力した場合、実際の有効時間は毎日 02:00-04:00 JST であり、Cloudflare Worker の実行地域や操作者の端末 timezone には依存しない。UTC へ換算した値を入れない。

JSON の scheduleWindows に追加する:

{
  "enabled": false,
  "bypassToken": "REPLACE_WITH_CURRENT_TOKEN",
  "updatedAt": "2026-03-11T00:00:00.000Z",
  "scheduleWindows": [{ "startHour": 2, "startMinute": 0, "endHour": 4, "endMinute": 0 }]
}
  • startHour/endHour: 0–23(Asia/Tokyo)
  • startMinute/endMinute: 0–59
  • 判定は [start, end) 半開区間(end の時刻は含まない)
  • start === end は空窓(無視)
  • start > end は日跨ぎ窓(例: { "startHour": 23, "startMinute": 0, "endHour": 1, "endMinute": 0 } → 23:00–01:00 JST)
  • 複数窓を指定した場合は、いずれかの窓に入れば有効になる
  • scheduleWindows を削除するか空配列にすると機能が無効化される

スケジュール窓が有効な場合も maintenance_bypass cookie による回避は機能する。 env 強制メンテナンス(STOREFRONT_MAINTENANCE_MODE フラグ)はスケジュール窓よりも優先される。 Storefront の Vite SPA 配信では Worker entrypoint が navigation 配信前に KV を読み、メンテナンス中の通常ページを /maintenance へ redirect する。

スケジュール窓の回帰テスト

JST 判定を変更した場合は、最低限次を実行する。

pnpm -C apps/storefront exec vitest run src/lib/maintenance-state.test.ts src/lib/server-maintenance-guard.test.ts src/worker-entry.test.ts
pnpm -C packages/plugins exec vitest run src/system-integration/maintenance-mode/maintenance-mode.service.test.ts

Storefront 側のテストは JST 変換、[start, end) 境界、日跨ぎ窓、Worker redirect を確認する。Vendure 側のテストは Dashboard / Admin GraphQL から保存した scheduleWindows が手動切替や bypass token rotation で失われないこと、不正な時刻が拒否されることを確認する。

API / CLI で切り替える

有効化

curl -X PUT \
  "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/storage/kv/namespaces/${CLOUDFLARE_MAINTENANCE_KV_NAMESPACE_ID}/values/storefront%3Amaintenance" \
  -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
  -H "Content-Type: text/plain" \
  --data '{"enabled":true,"bypassToken":"REPLACE_WITH_CURRENT_TOKEN","updatedAt":"2026-03-11T00:00:00.000Z"}'

無効化

curl -X PUT \
  "https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/storage/kv/namespaces/${CLOUDFLARE_MAINTENANCE_KV_NAMESPACE_ID}/values/storefront%3Amaintenance" \
  -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
  -H "Content-Type: text/plain" \
  --data '{"enabled":false,"bypassToken":"REPLACE_WITH_CURRENT_TOKEN","updatedAt":"2026-03-11T00:05:00.000Z"}'

確認項目

  • 一般アクセスで /maintenance へ遷移すること
  • 既存の回避 URL が有効なこと
  • Storefront ログに Cloudflare KV 読み取りエラーが出ていないこと

よくある失敗と対処

認証エラーで更新できない

  • Cloudflare API token に対象 namespace の read / write 権限があるか確認する
  • Account ID / Namespace ID が対象環境と一致しているか確認する

更新したのに画面がすぐ切り替わらない

  • KV は eventual consistency のため、短時間の反映遅延があり得る
  • 少し待ってから一般アクセスと回避 URL の両方を再確認する

JSON を保存したら回避 URL が使えなくなった

  • bypassToken を空文字や別形式へ変更していないか確認する
  • 値が不明な場合は新しい形式を推測で入れず、通常導線で確認可能な状態へ戻してから対処する

MAINTENANCE_KV binding 障害時の確認

Sentry に Storefront maintenance KV binding is missing が出た場合は、KV値そのものではなく Worker version に MAINTENANCE_KV binding が付いているか を先に確認する。

  1. 標準の deploy workflow または pnpm exec nx run ritsubi-storefront:cloudflare:deploy* を使って再デプロイする
  2. 最新 deployment の version に MAINTENANCE_KV (kv_namespace) があることを確認する
  3. binding が無い version を手動で promote しない

workers-version-deploy.yml はこの確認を自動で行い、binding が欠けた version の deploy を拒否する。

Cloudflare Access bypass エンドポイント

メンテナンス中でも特定の運用者がサイトへアクセスできるよう、Cloudflare Access で保護された bypass エンドポイントを利用できる。

仕組み

/maintenance/access-bypass エンドポイントは Cloudflare Access で保護する必要がある。 Cloudflare Access が認証を通過したリクエストには Cf-Access-Authenticated-User-EmailCf-Access-Jwt-Assertion ヘッダーが付与され、Worker がこれらを確認して maintenance_bypass cookie を発行する。

重要: env 強制メンテナンス(STOREFRONT_MAINTENANCE_MODE / VITE_PUBLIC_STOREFRONT_MAINTENANCE_MODE フラグ)は意図的にこの bypass を無効化している。env 強制は緊急遮断を意図しており、Access bypass では解除できない。

事前設定: Cloudflare Access ポリシーの設定

  1. Cloudflare Zero Trust ダッシュボードで対象ドメインの Access アプリケーションを作成する。
  2. アプリケーションの保護 URL を https://<storefront-domain>/maintenance/access-bypass* に設定する。
  3. ポリシーで、アクセスを許可するメールアドレスまたはグループを設定する。
  4. Cloudflare Access の JWT 検証設定が有効になっていることを確認する。

Cloudflare Access の設定が正しければ、認証されたリクエストに両ヘッダーが自動付与される。 Access ポリシーが設定されていない場合、エンドポイントは 403 を返す。

  1. Cloudflare Access に登録済みのアカウントでブラウザから以下の URL を開く:
https://<storefront-domain>/maintenance/access-bypass
  1. Cloudflare Access の認証フローを完了する(SAML / OIDC / OTP などポリシーに依存)。
  2. 認証完了後、Worker が KV から bypassToken を読み取り maintenance_bypass cookie を発行する。
  3. ブラウザが自動的にサイトのトップページ(または redirect パラメータで指定したパス)へリダイレクトされる。

特定のページへリダイレクトしたい場合は redirect クエリパラメータを付与する(相対パスのみ):

https://<storefront-domain>/maintenance/access-bypass?redirect=%2Fproducts

トラブルシューティング

症状 原因と対処
403 Forbidden Cloudflare Access ポリシーが設定されていないか、エンドポイントが保護されていない。Access アプリケーション設定を確認する。
404 Not Found KV の bypassToken が未設定または不正な形式(/^[0-9a-zA-Z_-]{8,128}$/ に不適合)。Vendure Dashboard でトークンをローテーションする。
503 Service Unavailable MAINTENANCE_KV binding が欠けているか KV が応答していない。Worker の binding 設定を確認する。
cookie 発行後もメンテナンス画面が表示される bypassToken が KV に保存されているものと一致しているか確認する。cookie が正しく保存されているか DevTools で確認する。

ロールバック

  1. enabledfalse に戻す
  2. updatedAt を更新して保存する
  3. 一般アクセスで通常画面へ戻ることを確認する

注意事項

  • KV は eventual consistency のため、切替が全 POP に反映されるまで短時間の遅延があり得る。
  • bypassToken を空文字や別形式にしない。既存の回避 URL が無効化される。
  • トークンをローテーションしたい場合は Vendure Dashboard を優先し、障害時のみ直接更新する。
  • deploy 経路では apps/storefront/wrangler.toml の placeholder 配置を前提に MAINTENANCE_KV binding を注入しているため、production では top-level table 群、 staging / preview / mock では [env.<target>] より後ろへ移動しない。

連絡・エスカレーション

切替後も復旧しない場合や、binding 障害が疑われる場合は 保守・サポート計画書 に沿って、次を添えて連絡します。

  • 発生日時
  • 対象環境
  • 実施した JSON 更新内容(enabled の切替有無)
  • 一般アクセス / 回避 URL / ログ確認の結果
  • 実施済みのロールバック有無