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
- 対象環境の
*_sharedsecret に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 で切り替える¶
- Cloudflare Dashboard を開く
Workers & Pagesから対象 Worker を選ぶStorage & Databasesまたは KV Namespace 一覧から対象 namespace を開くstorefront:maintenanceキーを選択する- 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 が付いているか を先に確認する。
- 標準の deploy workflow または
pnpm exec nx run ritsubi-storefront:cloudflare:deploy*を使って再デプロイする - 最新 deployment の version に
MAINTENANCE_KV(kv_namespace) があることを確認する - 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-Email と
Cf-Access-Jwt-Assertion ヘッダーが付与され、Worker がこれらを確認して maintenance_bypass cookie を発行する。
重要: env 強制メンテナンス(STOREFRONT_MAINTENANCE_MODE / VITE_PUBLIC_STOREFRONT_MAINTENANCE_MODE フラグ)は意図的にこの bypass を無効化している。env 強制は緊急遮断を意図しており、Access bypass では解除できない。
事前設定: Cloudflare Access ポリシーの設定¶
- Cloudflare Zero Trust ダッシュボードで対象ドメインの Access アプリケーションを作成する。
- アプリケーションの保護 URL を
https://<storefront-domain>/maintenance/access-bypass*に設定する。 - ポリシーで、アクセスを許可するメールアドレスまたはグループを設定する。
- Cloudflare Access の JWT 検証設定が有効になっていることを確認する。
Cloudflare Access の設定が正しければ、認証されたリクエストに両ヘッダーが自動付与される。 Access ポリシーが設定されていない場合、エンドポイントは 403 を返す。
bypass cookie の発行手順¶
- Cloudflare Access に登録済みのアカウントでブラウザから以下の URL を開く:
https://<storefront-domain>/maintenance/access-bypass
- Cloudflare Access の認証フローを完了する(SAML / OIDC / OTP などポリシーに依存)。
- 認証完了後、Worker が KV から
bypassTokenを読み取りmaintenance_bypasscookie を発行する。 - ブラウザが自動的にサイトのトップページ(または
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 で確認する。 |
ロールバック¶
enabledをfalseに戻すupdatedAtを更新して保存する- 一般アクセスで通常画面へ戻ることを確認する
注意事項¶
- KV は eventual consistency のため、切替が全 POP に反映されるまで短時間の遅延があり得る。
bypassTokenを空文字や別形式にしない。既存の回避 URL が無効化される。- トークンをローテーションしたい場合は Vendure Dashboard を優先し、障害時のみ直接更新する。
- deploy 経路では
apps/storefront/wrangler.tomlの placeholder 配置を前提にMAINTENANCE_KVbinding を注入しているため、production では top-level table 群、 staging / preview / mock では[env.<target>]より後ろへ移動しない。
連絡・エスカレーション¶
切替後も復旧しない場合や、binding 障害が疑われる場合は 保守・サポート計画書 に沿って、次を添えて連絡します。
- 発生日時
- 対象環境
- 実施した JSON 更新内容(
enabledの切替有無) - 一般アクセス / 回避 URL / ログ確認の結果
- 実施済みのロールバック有無