共有ホスティングサイトをCloudflare Workersでサーバー保守に備えた方法
要点
静的要素が中心のPHPサイトなら、ライブアカウントを移さず、計画停止中も多くの機能を残せます。KeyboardTester.clickの前段に置いたWorkerは、正常なオリジン応答を変更せず通し、ネットワーク障害や対象のサーバーエラー時だけ静的スナップショットを返します。オリジンが回復すれば次の正常リクエストで自動復帰します。ただし万能なゼロダウンタイムではなく、フォーム、メール、サーバー側AI、保存処理はオリジン依存のままです。
通知には6時間の作業枠だけが示され、実停止時間は不明でした。障害メールを待つと手動切替の空白が生じ、単一のメンテナンスページでは本来のページやブラウザツールを提供できません。
ここでは実際に導入した構成を、HostArmadaとの確認、Workerの判定、スナップショット、同一ゾーンの再帰、無料枠、SEO・広告・解析、制約までまとめます。
時点の注意:2026年7月18日現在、予定保守はまだ実施されていません。結果は強制origin障害、非公開staging、全件監査、正常な本番通過テストによるもので、実際の保守時間の結果ではありません。
HostArmadaのチケットで確認できたこと
作業枠は2026年7月22日10:00~16:00 CDTでした。6時間連続停止なのか、仮移行できるか、影響サービス、全URLに外部から503を返せるか、復旧・補償を質問しました。
エスカレーション後、6時間は予約枠であり停止確定時間ではない、実停止は短い見込みだが、物理作業・更新・検証のため正確には出せないとの回答でした。アカウントを往復移行するとDNS、同期、メール、DB整合性のリスクが増えます。
影響外サーバーに一時vhostとメンテナンスページを置き、開始時と終了時にAレコードを手動変更する案も提示されました。外部DNSは解決を続けますが、Web、DB、メール、パネルは停止します。バックアップと復旧手順はあり、クレジットは実影響後に審査する方針でした。案は妥当な告知手段ですが、手動で機能継続ではありません。
That offer was fair for a maintenance notice. It was still manual and did not provide functional-site continuity, so we used it as the baseline to improve rather than portraying it as a provider failure.
検証可能な時系列:保守メールからテスト済み継続層まで
提供者の告知、こちらの質問、実際に構築・試験した内容、まだ未来の実イベントを明確に分けます。
- 2026年7月 — 保守メール受信
Start Dock共有サーバーの通知は7月22日10:00–16:00 CDTを確保。CPU/RAM/SSD、Webサーバーのsecurity/software、kernel、tmp/cache/log清掃、全般最適化を列挙し、開始後は不可逆と説明しました。
- Start Dock共有ホスティングサーバー
- 2026年7月22日10:00–16:00 CDT
- CPU・RAM・SSD更新
- Webサーバーsecurity/software更新
- kernel更新
- tmp・cache・log清掃
- 全般最適化
- 開始後は不可逆と説明
- 7月16日 — 質問をescalate
実停止時間、仮移行、外部503、Web/DB/mail、backup、rollback、creditを質問。
- 7月17日 — HostArmada回答
6時間は枠、停止は短い見込みだが不明。同期リスクで移行を拒否し、vhostと手動A recordを提案。
- 7月17日に設計選択、18日にフォローアップ送信
常設origin-first Worker、snapshot、非公開staging、衝突検査、503、rollbackを採用。
- 7月17–18日 — 制御試験
1,514 page、1,234 asset、2,748 pathを監査し、障害/通過、再帰修正、apex/www fail-openを検証。
- 7月18日 — 準備済み、実イベント前
層はliveかつテスト済みですが22日の保守は未実施。実時間、traffic、収益は事後証拠が必要です。


構成:まずオリジン、障害時だけスナップショット
Workerはapexとwwwの経路に常駐し、制限時間付きで実オリジンを確認します。正常応答はそのまま返すため、PHP、セッション、ヘッダー、広告、解析は通常どおりです。
ネットワーク障害、タイムアウト、500/502/503/504または520–527では同じパスの静的資産を返します。GET/HEADは継続し、以後も毎回オリジンを試すため自動復帰します。
第二のPHP環境ではないため、書き込み可能DBの二重化、セッション衝突、事後のデータ突合を避けられます。
リクエストの流れ

一時メンテナンスページと常設Workerの比較
正しい保守通知だけなら前者が簡単です。読み取りページやクライアント側ツールを残したい場合は、準備と検証を伴う後者が適します。
| 項目 | 一時vhost | 常設Worker |
|---|---|---|
| 切替 | 開始・終了時にDNSを手動変更 | リクエストごとに自動 |
| 表示 | 1枚の保守ページ | 該当ページ・ツール・資産 |
| 書き込み | 不可 | 不可、明示的503 |
| 復旧 | DNSを手動で戻す | オリジン正常時に自動 |
| 整合性 | 第二DBなしで低リスク | 第二DBなしで低リスク |
| 運用 | 単純だが定刻作業が必要 | 準備は多いが当日の操作は少ない |
利用者とクローラーへの障害時応答
ページ、ブラウザツール、CSS、スクリプト、画像、フォントは小さな縮退表示付きでスナップショットから配信し、canonicalと構造化データは元URLを保ちます。
書き込みは成功を装いません。POSTなど利用不能な操作には503 Service Unavailable、Retry-After: 300、Cache-Control: no-storeを返します。RFC 9110は503を一時障害・計画保守に定義しています。
This distinction matters: returning a pretty 200 OK “maintenance” page for a failed form can mislead users and crawlers. Returning a controlled 503 for the unavailable action is both more honest and easier for clients to retry.
実際のfallback判定表
| origin結果 | GET / HEAD | POST・書き込み |
|---|---|---|
| 正常、redirect、4xx、対象外status | originを無変更で通過 | originを無変更で通過 |
| network失敗・4.5秒timeout | 該当snapshot、なければ503 | 503 + Retry-After: 300 + no-store |
| 500/502/503/504・520–527 | snapshotと診断header | 503 + Retry-After: 300 + no-store |
| origin停止中の未知safe path | 制御503。ページを捏造しない | 対象外 |
スナップショットの構築と検証
未公開変更を含むローカルPHPではなく、レンダリング済み本番をクロールしました。1,514ページと1,234個の自社資産を取得し、最終的に2,749ファイル、約547.6 MBとなりました。各ファイルは上限内です。
canonicalとschemaを保持し、古い相対参照はコピー内だけ修正。取得時にトラッカーを外し、本番WorkerだけがGA4、AdSense、トップページClarityを遅延追加します。非公開stagingは追跡なし、noindexです。
TypeScript、単体、ローカル強制障害、認証staging、ブラウザ、origin preview、全件リモート監査を実施し、公開2,748パスすべて成功しました。
- 作業枠と予想停止時間を分けて確認する。
- ローカルが本番と同一でなければレンダリング済み本番から作る。
- 全ページと自社資産を棚卸しし個数・サイズ上限を検証する。
- stagingを非公開/noindexにし、障害と正常通過を試す。
- 安全メソッド、対象状態、timeout、503、rollbackを事前定義する。
- 同一ゾーン再帰を防ぎcanonical Hostを保つ。
- Worker迂回が安全な場合だけfail-openを選ぶ。
- 非対応機能を明記し、大きな変更後に更新する。

安全に再現する手順とサニタイズ済みコード
1. 契約を先に定義。対象host、安全なmethod、fallback status、timeout、未知path、route削除を決めます。non-200全てが障害ではありません。
2. レンダリング済み本番をcrawl。canonical sitemapからsame-originのHTML/CSS資産だけを集め、URLを正規化し、traversalを防ぎ、個数・サイズ超過でbuildを止めます。
3. 意味を保持。canonical、hreflang、schema、リンク、client tool資産を残し、service workerとtrackingをコピーから外します。広告・解析はproductionだけで挿入します。
4. ASSETSとrun_worker_first。コピー前にoriginを確認します。例はplaceholderのみです。
5. 同一zone再帰を防止。管理下のDNS-only名をresolveOverrideに使い、URL/Hostを維持し、TLS/vhostを確認します。
6. 非公開staging。secret、noindex、robots遮断、広告/解析なし、origin previewを用意します。
7. apex、次にwww。衝突を拒否しredirectを検証。fail-openは可用性用途だけにします。
8. rollbackを分離。所有routeだけ削除し、Worker/snapshotは保持、臨時権限を失効します。
サニタイズ済みWorker/asset設定
{
"name": "example-host-outage-fallback",
"main": "src/index.ts",
"compatibility_date": "2026-07-17",
"assets": {
"directory": "./snapshot/dist",
"binding": "ASSETS",
"run_worker_first": true,
"html_handling": "none",
"not_found_handling": "none"
},
"vars": {
"MODE": "production",
"ORIGIN_BASE": "https://example.com",
"ORIGIN_RESOLVE_OVERRIDE": "origin-bypass.example.com",
"ORIGIN_TIMEOUT_MS": "4500"
}
}origin-first判定とstatus
const FALLBACK_STATUSES = new Set([
500, 502, 503, 504, 520, 521, 522, 523, 524, 525, 526, 527
]);
try {
const origin = await fetch(originRequest, {
signal: AbortSignal.timeout(4500),
redirect: "manual",
cf: { resolveOverride: "origin-bypass.example.com" }
});
if (!FALLBACK_STATUSES.has(origin.status)) return origin;
return serveSnapshot(request, origin.status);
} catch {
return serveSnapshot(request);
}書き込みへの正しい503
if (!new Set(["GET", "HEAD"]).has(request.method)) {
return new Response("Temporarily unavailable", {
status: 503,
headers: {
"Retry-After": "300",
"Cache-Control": "no-store",
"Content-Type": "text/plain; charset=utf-8"
}
});
}build、staging、activate、rollback
# Build from rendered production and validate the package
python scripts/build_snapshot.py
npm run types
npm run check
npx wrangler deploy --env staging --dry-run
# Deploy and test the private preview (use your own secret securely)
npx wrangler deploy --env staging
python scripts/smoke_staging.py --base "https://<private-preview>" --password "<secret>"
# Inspect, activate, or remove only the owned routes
python scripts/manage_routes.py status
python scripts/manage_routes.py activate --confirm ACTIVATE-KBT-FALLBACK
python scripts/manage_routes.py deactivate --confirm REMOVE-KBT-FALLBACKテスト計画:障害・通過・復旧を証明
トップ、主要tool、CSS/JS、記事、Arabic RTL、長い翻訳、robots、missing path、HEAD、POST、www redirect、mobile light/darkを確認します。
snapshotではheader、canonical、H1、JSON-LD、資産、通知。origin previewではloopなし。正常productionではfallback headerなしと無変更応答を確認します。
公開originを故意に壊さず、非公開previewまたは別test originを使い、生成時刻とmanifest hashを記録します。
ロールバック、監視、復旧
即時rollbackは所有Worker routeだけの削除です。DNS変更やWorker削除ではありません。apex/wwwを確認し、古いfallback HTMLがある場合だけpurgeします。
保守中はheader、origin status、log、主要page、503を監視。最初の正常応答で自動復帰します。後で安定性確認、臨時権限失効、測定保存、snapshot更新を行います。
2つの落とし穴:同一ゾーン再帰と無料上限
keyboardtester.click/*のWorkerが同じ公開ホストを単純fetchすると自分に戻る恐れがあります。同一ゾーンの既存DNS-only名へresolveOverrideし、URLとHostはcanonicalのままオリジンへ解決しました。オリジンIPや迂回経路は公開しません。
Freeは現在1日100,000 Workerリクエスト、1バージョン20,000静的ファイル、1ファイル25 MiBです。2,749ファイルは範囲内。ルートはfail-openで、枠超過時はError 1027ではなくHostArmadaへ直接迂回します。可用性用途には適しますが、セキュリティ強制には不適切です。
フォールバック中のSEO・広告・解析
存在するコピーは元URLで200、canonical、schema、内部リンクを保ち、利用不能な書き込みだけ503です。公開ミラードメインや新規送信URLはありません。
stagingはパスワード、robots遮断、noindex、計測なし。本番コピーHTMLだけに遅延GA4/AdSense、トップページだけClarityを追加し、正常オリジン応答は変更しません。計測と広告配信の可能性は残りますが、広告充足や収益は保証できません。
We did not submit fallback URLs to search engines because there are no new public URLs. The continuity layer sits behind the same addresses Google already knows.
production挿入はlive性能に合わせ、GA4は操作後またはload 2秒後、AdSenseは操作後または15秒後、トップClarityは操作後または12秒後です。streaming HTMLRewriterはfallback GET HTMLだけを変更し、HEAD、CSS、JS、画像は変更しません。
制約と別方式を選ぶ場面
フォーム、サーバーAI、メール、DB書き込み、セッション、保存送信はオリジン停止中に使えません。ブラウザ内ツールも必要ファイルが全てコピーされている場合だけ動きます。
コピーは古くなるため、大きな変更後に更新し、障害だけでなく復旧も試験します。書き込み・取引中心の製品はアプリとDBの複製が必要です。
コンテンツ中心でクライアントツールが多い共有サーバーには、データ分岐、手動切替、別公開ドメインなしで明確な縮退運転を作れる適切な方法でした。見える停止を短くしますが依存を全廃はしません。
一次資料と実測根拠
数値は2026年7月17~18日のマニフェスト、デプロイ、実経路検証によるものです。製品仕様と上限はリンク先の一次資料に基づきます。
- Cloudflare Workers: Static Assets
- Cloudflare Workers: Platform Limits
- Cloudflare Workers Request API
- Cloudflare Workers Routes API
- RFC 9110: HTTP Semantics
- HostArmada support correspondence, July 16–17, 2026
よくある質問
- 共有サーバーが本当にゼロダウンタイムになりますか?
いいえ。読み取りコピーは残りますが、フォーム、書き込み、メール、AI、セッションはオリジンが必要です。
- 障害時にDNS変更が必要ですか?
この常設方式では不要です。Workerが毎回確認し自動復帰します。
- Googleは全URLで保守ページを見ますか?
いいえ。コピー済みページは200とcanonical/schemaを保ち、利用不能な操作だけ一時503です。
- なぜアカウント全体を一時移行しないのですか?
往復移行はDNS、ファイル、メール、DB同期の危険を増やすためです。
- resolveOverrideはなぜ必要ですか?
Workerが自分の公開経路を再呼び出さないためです。同一ゾーンの別名で解決し、URLとHostは維持します。
- 無料上限に達すると?
fail-openでWorkerを迂回しオリジンへ行きます。オリジン停止時のコピーは失いますが追加の枠エラーを防ぎます。
- いつコピーを更新しますか?
大きなコンテンツ・テンプレート・スクリプト・資産変更後と計画保守前です。
重要なのは全てをWorkerに置くことではなく、障害に合う最小の継続層を選び、非公開で試し、限界を示し、復旧を自動化することです。