Cloudflare Workers の静的アセット配信(Workers Assets)は、Cloudflare Pages の流れを汲むシンプルで強力なホスティング手段です。筆者も自社サービスの運用で使っていますが、「ローカルでは問題ないのに本番だけおかしい」という落とし穴を実際にいくつも踏んできました。本記事では、その中でも影響が大きかった4つを、症状・原因・対処・確認コマンドの型で整理します。
[目次を開く]
1. 拡張子付きURLは本番で307リダイレクトされる
症状
Google Search Console で sitemap 内のURLに「リダイレクトエラー」が並びました。ローカル確認では気づかず、本番の /page.html にアクセスすると 307 Temporary Redirect で /page に飛ばされていたのが原因です。
原因
Workers Assets には html_handling という設定があり、デフォルトの挙動(auto-trailing-slash 相当)では /page.html へのアクセスは拡張子なしの /page へリダイレクトされます。URLをきれいに保つための機能ですが、sitemap・canonical・og:url に拡張子付きURLを書いていると、検索エンジンから見て「正規URLがリダイレクトされる」状態になり、GSCでエラー扱いになります。
対処
サイト内で使うURLを 拡張子なしの正規URLに統一 します。sitemap・canonical・og:url・内部リンクのすべてから拡張子を排除しました。html_handling の挙動自体はオプションで変更もできますが、リダイレクト先に合わせて正規URLを揃えるほうが素直です。
確認コマンド
# 307が返ることの確認(Locationが正規URL)
curl -I https://example.com/page.html
# 正規URLは200で返ることの確認
curl -I https://example.com/page 2. マネージドrobotsファイルはオリジン分と「結合」される
症状
オリジン側の robots ファイルに Sitemap: 行を追加してデプロイしたところ、本番を見ると 自分の書いた覚えのないAIボット向けの記述が先頭に付いて いました。
原因
Cloudflare のマネージド robots ファイル(AIボット遮断機能)が有効なゾーンでは、ゾーンレベルの内容が先に返され、オリジンの内容は その後ろに結合 されます。つまり本番の内容は「Cloudflare生成分+オリジン分」の合成結果になり、オリジンのファイル単体とは一致しません。
対処
これは仕様なので、機能を使うなら受け入れたうえで、デプロイ後に必ず本番の結合結果を確認する 運用にしました。特に Sitemap: 行の追加やクロール制御の変更をした場合は、意図した行が結合後にも生きているかを見ます。
確認コマンド
# 本番での結合結果を確認する
curl https://example.com/robots.txt 3. git管理外のアセットが本番から消える
症状
別マシンからデプロイした直後、本番のブラウザゲームが起動しなくなりました。調べると、ゲーム本体の wasm.gz や .pck といった大型ファイルが本番から消えていました。
原因
wrangler deploy は ローカルのアセットディレクトリの内容をそのまま本番に反映 します。差分アップロードではなく「ローカルが正」なので、ローカルに存在しないファイルは本番からも消えます。大型バイナリを git 管理外にしていたため、git clone しただけの別マシンにはそのファイルが無く、デプロイで本番側も消えたわけです。CIからのデプロイでも同じことが起きます。
flowchart LR
localA["ローカルA<br/>(全アセットあり)"] -->|"wrangler deploy"| prodOk["本番: 完全な状態"]
localB["ローカルB<br/>(git cloneのみ・大型ファイルなし)"] -->|"wrangler deploy"| prodNg["本番: 大型ファイルが消える"] 対処
デプロイ前に、git管理外ファイルがローカルに揃っていることを確認する チェックをデプロイ手順に組み込みました。恒久策としては、大型アセットを別ストレージ(R2等)に逃がす、あるいはCIに含める仕組みを作るのが理想です。
確認コマンド
# デプロイ前: 管理外の必須アセットが存在するか
ls -lh dist/game/*.wasm.gz dist/game/*.pck
# デプロイ後: 本番から取得できるか
curl -I https://example.com/game/main.wasm.gz 4. mainマージだけでは本番反映されない/直後は古キャッシュを引く
症状
PRをmainにマージして「リリース完了」と思い込んでいたら、本番が古いままでした。さらに、デプロイ直後に動作確認したら 変更が反映されていないように見えて 空振りしたこともあります。
原因
自動デプロイを組んでいない場合、mainへのマージはあくまでリポジトリ上の操作で、本番反映には wrangler deploy --env production の実行が別途必要です。また、デプロイ直後はエッジに古いキャッシュが残っていることがあり、確認アクセスが旧版を引くことがあります。
対処
- 「マージ=リリースではない」を手順書に明記し、デプロイコマンドの実行までをリリース作業とする
- デプロイ直後の確認は少し待つ、または複数のエンドポイントで新版を確認する。急ぐ場合はキャッシュパージという手段もあります
- 根本的には、mainマージで自動デプロイされるCI/CDを組むのが確実です。CI/CDの考え方は CI/CDとは何か にまとめています
確認コマンド
# 本番へのデプロイ(自動化していない場合)
wrangler deploy --env production
# 新版に含まれる変更が見えるか(複数パスで確認)
curl -s https://example.com/ | grep "新しく入れた文言"
curl -I https://example.com/new-page 5. デプロイ前チェックリスト
| # | チェック項目 | 確認方法 |
|---|---|---|
| 1 | sitemap・canonical・og:url に拡張子付きURLがない | ソースをgrep |
| 2 | git管理外の必須アセットがローカルに揃っている | ls で実在確認 |
| 3 | wrangler deploy --env production を実行した(マージだけで終わっていない) | デプロイログ |
| 4 | 本番の robots ファイルの結合結果が意図通り | curl で本番を直接確認 |
| 5 | 動作確認はキャッシュを疑いつつ複数エンドポイントで | curl -I +少し待つ |
6. よくある質問
Q. 拡張子付きURLへのリダイレクトを無効化できますか?
html_handling の設定で挙動を変えられます(none 等のオプションがあります)。ただし既にインデックスされたURLとの整合を考えると、リダイレクト先である拡張子なしURLに正規URLを統一するほうが運用は安定します。
Q. robots ファイルの結合はどのプランでも起きますか?
Cloudflareのマネージド robots ファイル(AIボット対策)機能を 有効にしているゾーンで 起きる挙動です。機能をオフにすればオリジンの内容がそのまま返ります。有効にしている場合は、変更のたびに本番の結合結果を確認するのが安全です。
Q. 消えたアセットはロールバックで戻せますか?
Workersのバージョン管理からロールバックできる場合もありますが、確実なのは「全アセットが揃ったローカルから再デプロイ」することです。そもそも消える事故を防ぐため、デプロイ前チェックに組み込むことをおすすめします。
Q. デプロイ直後の確認はどのくらい待てばいいですか?
環境によりますが、筆者は数十秒〜数分置いてから確認しています。急ぎの場合はキャッシュパージを使う、確認用に複数のURL・複数の変更点を見る、といった方法で誤判定を減らせます。
7. まとめ
Cloudflare Workers の静的アセット配信は手軽ですが、「本番だけで起きる挙動」がいくつかあります。
- 拡張子付きURLは307リダイレクトされる。正規URLは拡張子なしに統一する
- マネージド robots ファイルはオリジン分と結合される。デプロイ後は
curlで結合結果を見る -
wrangler deployはローカルが正。git管理外アセットの実在をデプロイ前に確認する - mainマージ=リリースではない。デプロイ実行と、キャッシュを疑った動作確認まで
いずれも「本番を curl で直接確認する」習慣で早期に気づけるものです。Cloudflare自体の全体像は Cloudflare入門 も参考にしてください。
