実測と修正の記録・2026年8月15日

同じページが4つのURLで200を返していた|10サイトを実測して301で寄せた記録

あなたのサイトの1ページは、いくつのURLで開けますか。http・https・www有無で最大4通りが全部200を返しているなら、クロールの予算を4分割しています。私たちのサイトは17サイト中15サイト(初日に10サイト、翌日の洗い直しでさらに5サイト)がこの状態で、気づかないまま運用していました。判定は10秒でできます。

このサイトはAnthropicの公式サイトではありません。Claude Codeの機能・料金・提供範囲は変わる可能性があるため、重要な判断の前には公式のドキュメントと自分のアカウント設定を確認してください。

先に結論

手順は3つだけです。急いでいるならこの節だけで動けます。

  1. 4通りのURLをヘッダで叩いて判定する(10秒)。ページのソースをいくら見ても分かりません。次の節のコマンドをそのまま使ってください
  2. 200が混ざっていたら、.htaccessの301で正規URLへ寄せる。使ったルールは下に置いてあります。2条件を1本にまとめると、どの変種からでも1回のリダイレクトで着きます
  3. ただし、ルールを書く前に %{HTTPS} の実測を挟む。ここを飛ばすと、環境によってはリダイレクトが無限ループしてサイト全体が落ちます。確認用のPHPも下に置いてあります

効果はすぐには出ません。クロールの配分が戻るまで2〜4週間見てください。逆に言うと、この欠陥を放置している限り、本文をいくら改善してもクロールの無駄は残り続けます。

まず自分のサイトを10秒で判定する

トップページを4通りのURLで叩きます。見るのはHTMLではなくレスポンスヘッダです。

curl -I http://example.jp/
curl -I https://www.example.jp/
curl -I http://www.example.jp/

この3本が 301 と Location: https://example.jp/ を返していれば正常です。どれかが200を返したら、同じ内容が複数のURLで配信されています。

この欠陥はページのソースを見ても分かりません。私たちの10サイトも、<link rel="canonical"> は全サイト正しく https の非www を指していました。canonicalが正しいので、HTMLを目視しても、HTMLを機械で検査しても、何も出てきません。だからヘッダで見ます。1サイト10秒で判定できます。

直す前に %{HTTPS} を実測する(ここを飛ばすとサイトが落ちる)

直し方は .htaccess に301のルールを1本足すだけですが、先に実測しないと書いてはいけない値があります。サーバーが「今のアクセスはhttpsだ」と申告するかどうかです。

ロードバランサやプロキシの後ろにいるサーバーだと、実際にはhttpsで来ていても %{HTTPS} が常に off のままになることがあります。その状態で「httpならhttpsへ飛ばす」と書くと、飛ばした先でもまた off なので無限にリダイレクトし続け、サイト全体が見えなくなります。

そこで、診断用のPHPを1サイトに一時的に置いて、httpとhttpsの両方から叩きました。あなたの環境でも同じものが使えます。

<?php
header('Content-Type: text/plain; charset=UTF-8');
header('X-Robots-Tag: noindex, nofollow');
foreach (array('HTTPS','SERVER_PORT','REQUEST_SCHEME',
               'HTTP_X_FORWARDED_PROTO','HTTP_HOST') as $k) {
  echo $k . '=' . (isset($_SERVER[$k]) ? $_SERVER[$k] : '(未設定)') . "\n";
}

私たちの環境での結果はこうでした。

アクセスHTTPSSERVER_PORTX-Forwarded-Proto
https でon443未設定
http で未設定80未設定

X-Forwarded-Proto が無く、%{HTTPS} がスキームどおりに変わる=プロキシを挟んでいない、と確認できたので、%{HTTPS} !=on を条件に使って問題ないと判断しました。あなたの環境で X-Forwarded-Proto が出てくるなら、条件はそちらで書く必要があります。

この診断PHPは使い終わったら消してください。消えたかどうかの確認はFTPのファイル一覧で行ってください。削除直後にブラウザで叩くと404ではなく500が返ることがあり、HTTPの応答だけでは「消えた」と判定できません。

投入したルール

.htaccess の先頭に置きました。2つの条件を1本のルールにまとめているのがポイントで、こうすると http://www.example.jp/ も1回のリダイレクトで正規URLに着きます。条件を分けて2本書くと2ホップになり、その分だけ余計に遅くなります。

# canonical-host-20260815
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} !=on [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.jp%{REQUEST_URI} [R=301,L]
</IfModule>

先頭に置いても、既存の RedirectMatch(mod_alias)や後続のルールとは干渉しませんでした。IfModule の中で完結しているためです。

もうひとつ前提があります。httpsの証明書に www 付きのホスト名も含まれていること。含まれていないと、https://www.〜 へのアクセスは301を受け取る前に証明書エラーで止まります。「301を書いたのに直らない」の原因がこれだったことがあります(証明書側の話)。

1サイトずつ、復旧できる形で流す

複数サイトあっても一括では流さないでください。手順は1サイトにつき次の4段です。

  1. 今の .htaccess をFTPでダウンロードして退避する(ローカルの一時領域へ。公開ディレクトリの中に置かない)
  2. ルールを先頭に足してアップロードする
  3. 4通りのURLを叩いて、正規URLが200、他3本が301であることを確認する
  4. 正規URLが200でなければ、退避したファイルをその場で戻す

4段目が肝心です。ループが起きた場合、正規URLは200を返さなくなります。その判定を自動で入れておけば、事故ってもそのサイトだけで止まります。実際のコードでは、キャッシュで揺れることがあるので1.5秒あけて最大4回まで見に行き、それでも駄目なら復旧、としました。

結果は10サイトすべてで 301が3/3、正規URLは200。下層ページ・sitemap.xml・robots.txt もあわせて確認しました。

robots.txt まで301しないこと

ひとつ注意があります。サイトの引っ越しで同じようなルールを書くとき、/robots.txt まで転送先へ301してはいけません。移転元のrobots.txtが読めなくなると、クローラが移転元を回らなくなり、その結果301そのものが認識されなくなります。

今回のようにホスト名を揃えるだけの301なら、同じサイト内なのでこの問題は起きません。ドメインをまたぐときだけ気をつけてください。

証拠:実際に起きていた規模

ひとつのページには、ふつう次の4通りのアドレスがあり得ます。

  • https://example.jp/(正規にしたいURL)
  • https://www.example.jp/
  • http://example.jp/
  • http://www.example.jp/

正しくは、下の3つが正規URLへ301で飛ぶ必要があります。ところが実測すると4つとも200を返し、4つとも同じHTMLを返していました。検索エンジンから見ると、中身の同じページが4本存在しているのと変わりません。

規模の小さいサイトほどこれが効きます。クロールに割り当てられる量には上限があり、それを4分割していたわけです。実際、調べていた6サイトは平均順位が17〜21位(=検索結果の2ページ目)にかたまっていて、クリック率の問題ではなく、そもそも順位が付いていない状態でした。

追記(8月16日): 「全部直した」が間違っていた

この記事は当初「10サイト全部で直した」として公開しました。翌日、その数え方が崩れました。

保有ドメインの一覧から稼働中のサイトを機械的に洗い直したところ、定期検査の対象に入っていないサイトが5つ見つかり、5つとも同じ4URL200の状態でした。「全10サイト」という数は、手で管理していた古いリストに依存していたわけです。うち1サイトは143URL中14本しか検索結果に出ておらず、症状も一致していました。

5サイトにも同じルールを適用し、17サイトすべてで301が3/3になったことを確認しています。

なお、この5サイトでは診断PHPによる %{HTTPS} の再実測を省きました。同一サーバー・同一アカウントで、前日に実測した同じルールが12サイトで動いていたためです。条件が同じだと確認できているときだけ実測を省けます。サーバーやアカウントが違うなら、実測からやり直してください。省いた場合でも、1サイトずつ・正規URLが200でなければ即復旧、の形は変えていません。

「直した対象の一覧そのものが間違っている」という欠陥への対策は、検査コードの書き方に追記しました。

よくある質問

canonicalタグを入れてあれば十分ではないですか?

canonicalは「どれが正規か」という申告であって、強制力はありません。4つのURLが全部200を返す状態そのものが残るので、クロールは4回発生します。301はアクセスの時点で1本に寄せるので、そこが違います。

www有りを正規にする場合は?

向きが逆になるだけで考え方は同じです。ただし途中で向きを変えると、それまでに積み上げた評価がいったん揺れます。すでにどちらかで運用しているなら、いま検索結果に出ているほうに合わせてください。

サーバー管理画面の「HTTPSにリダイレクト」機能ではだめですか?

httpsへの強制だけならそれで足ります。ただしwww有無は別問題なので、そちらは処理されません。両方を1本で扱いたかったので、今回は.htaccessに書きました。

効果はいつ分かりますか?

クロールの配分が戻るまで時間がかかるので、2〜4週間あけてから再測定する予定です。すぐに順位が動く種類の修正ではありません。

次に読むページ