Cloudflare Pages の _redirects に www リダイレクトを書いたら黙って無視された

· ops-log Cloudflare Pages リダイレクト 静的サイト SEO

本記事にはアフィリエイト広告(PR)が含まれます。

このサイトは shikumilog.com で公開している。ところが www.shikumilog.com にアクセスしても、同じ中身が 200 で返ってくることに気づいた。同一内容が 2 つの URL で配信されている状態だ。

致命傷ではない。www 側のページも canonical は apex(www なしのドメイン)を指しているので、検索エンジンに「正はこちら」という表明はできている。ただ、このサイトは 2026-08-09 に公開して 08-12 に Search Console へ登録したばかりの新規ドメインで、この時点(08-16)のインデックス登録は 0 件だった。その段階で、同じ内容を 2 つの URL で取りに来させるのは損だ。www → apex の 301 リダイレクトを入れることにした。

結論を先に書く。最初に入れた設定は、正しくデプロイされたのに効かなかった。原因は書き間違いではなく、書く場所——レイヤ——の間違いだった。

_redirects に書いてデプロイした

Cloudflare Pages には _redirects というファイルでリダイレクトを定義する仕組みがある。ビルド出力にこのファイルを置くと、Pages がそれを読んでリダイレクトを適用する。

私はここに www → apex の転送を書いた。ホスト名から始まる、別のホスティングサービス(Netlify)のドキュメントで見かけたことのある形だ。サイトジェネレーターのビルド出力に _redirects を吐く実装を足して、sitemap の URL エンコード修正(こちらは別の不具合で、<loc> に半角スペースがそのまま入っていた)と合わせて 1 つの PR にした。CI は通り、マージしてデプロイされた。

効かない。しかしファイルは配信されている

デプロイ後、www にアクセスすると 200 のままだった。反映待ちかと思い、20 秒間隔で 6 回計測した。6 回とも 200。301 は一度も返らなかった。

ここからの切り分けで、可能性が 1 つずつ消えていった。

まず「デプロイに失敗した」の線。同じ PR に入れた sitemap のエンコード修正は、本番の sitemap.xml で効いていた。エンコード済みの <loc> が 33 件、生の空白を含む <loc> は 0 件。デプロイそのものは成功している。

次に「ファイルが出力に含まれていない」の線。/_redirects に直接アクセスすると、トップページの HTML が返ってきた。公式ドキュメントによれば、このファイルは静的ファイルとしては配信されず、Pages に解釈される("This file will not itself be served as a static asset, but will instead be parsed by Cloudflare Pages")。つまりこの応答はむしろ「ファイルは取り込まれている」ことを示す。

つまり、設定は入っている。入っているのに、効いていない。

公式ドキュメントに「❌」があった

答えは公式ドキュメントの対応表にあった。Cloudflare Pages の _redirects の仕様には「Advanced redirects」という表があり、そこにこうある。

Domain-level redirects — ❌

例として挙げられているのが workers.example.com/* workers.example.com/blog/:splat 301、まさに私が書いた形だ。ホスト名から始まるリダイレクトは、この仕組みの対象外だった。仕様の定義でも source は「A file path.」と明記されている。ワイルドカードやプレースホルダは使えるが、いずれもパスの中の話で、ホストは最初から守備範囲にない。

そして、今回いちばん効いた一文がこれだ。

Only one redirect can be defined per line and must follow this format, otherwise it will be ignored.

形式に合わない行は、エラーにならない。警告も出ない。黙って無視される。 CI は通る。デプロイは成功する。ファイルは取り込まれる。それでも、その行だけが存在しないものとして扱われる。「設定は入っているのに効かない」ように見えたものの正体は、「入ってはいるが、読まれていない」だった。

私の側の誤りは単純で、Netlify の _redirects とファイル名が同じだから中身も同じだろう、と確認せずに書いたことだ。同じ表を見ると、クエリパラメータによるマッチや国・Cookie による出し分けも ❌ で、ホスト指定はその一例にすぎない。ファイル名が同じでも、別の製品では別物だった。なお、この書き方が Netlify 側で本当に効くのかは、今回は検証していない。

ホストの転送は CDN の仕事だった

ホスト単位のリダイレクトは、ビルド出力ではなく CDN 側の設定でやる。Cloudflare にはダッシュボードに Redirect Rules があり、「WWW からルートにリダイレクト」というテンプレートまで用意されていた。

設定した内容はこうだ。

設定後の実測。トップ・記事 URL・クエリ付き URL の 3 パターンで確認し、3 パターンとも apex へ 301 が返った。パスとクエリは保持され、apex 側は 200 のままでリダイレクトループもない。

効かなかった _redirects の出力は、別の PR で削除した。動かない設定をリポジトリに残すと、後からコードを読んだ人間——たいてい未来の自分——が「www の転送は対応済み」と誤読するからだ。効かないと分かった設定は、消すところまでが後始末だと思う。

同じことをする人へ

この記事は、運営者自身の実践記録に基づいています。

出典