つ積み上げログ技術ブログ記事一覧へ

自主執筆記事

GitHub Pagesは301を返せない|10,450ページぶんの200を置いて転送した

ドメインを移したあと 404.html にJSを入れて転送していたが、HTTPステータスは404のままで、5日間Googleに404を返し続けていた。GitHub Pagesは301を返せないので、全パスぶんの200を返す実体を生成して置いた。

SEO公開: 2026/10/02更新: 2026/10/02
GitHub Pagesリダイレクトcanonicalドメイン移転静的サイト

01 / 本文

ブラウザでは飛ぶのに、検索エンジンには404

ドメインを別のドメインへ移し、旧ドメインには 404.html を置いてJavaScriptでパスごとに転送していた。

ブラウザで旧URLを開くと、一瞬で新しいURLに変わる。動いているように見えた。

しかしHTTPステータスは404のままだった。Googlebot は本文のJavaScriptを待たずにステータスを見る。5日間、発見済み未登録が6,162件のまま動かなかった。

curl -s -o /dev/null -w '%{http_code}' https://old.example.jp/some/path/
404

02 / 本文

GitHub Pages には301を返す手段が無い

Apache の .htaccess や nginx の return 301 に当たるものが無い。サーバー側の設定ファイルを置ける仕組みが存在しない。

404.html は「存在しないパスに404を返しつつ、このHTMLを見せる」という機能で、ステータスを変える機能ではない。

選べるのは、実際に200を返すファイルを置くことだけになる。

03 / 本文

全パスぶんの実体を生成する

移転元のサイトマップから全URLを取り出し、同じパスに200を返すHTMLを置いた。10,450ファイルになった。

中身は3行だけでよい。

<link rel="canonical" href="そのページ固有の移転先">
<meta http-equiv="refresh" content="0; url=そのページ固有の移転先">
<meta name="robots" content="noindex,follow">

04 / 本文

全部をトップページに飛ばさない

canonical と refresh は、ページごとの移転先を指す。 全部をトップページに向けると、Googleは転送ではなく「中身の無いページ」として扱う。

1ファイル700バイト程度で、10,450件でも合計8MBほど。生成はスクリプトで一度に作れる。

即時の meta refresh は 301 と同じに扱われる。301が返せない以上、これが上限。

05 / 本文

置いたあとに200件を抜き取って確かめた

生成しただけでは安心できないので、200件を抜き取って3項目を確認した。

HTTP 200        200 / 200
canonical一致    200 / 200
refresh一致      200 / 200

06 / 本文

確認は相手と同じ見え方で取る

この件の反省は、ブラウザで飛んだのを成功の証拠にしたことだった。検索エンジンのために直したのだから、確認も検索エンジンと同じ見え方で取る。

curl でステータスだけを見る。リダイレクトを追う -L は付けない。追ってしまうと、また「飛んだから成功」に戻る。

07 / 本文

まとめ

- GitHub Pages は301を返せない - 404.html の転送はステータスが404のまま。検索エンジンには転送に見えない - 全パスぶんの200を返す実体を置く - canonical と refresh はページごとの移転先を指す - 確認は curl でステータスを見る。-L は付けない

コメント

この記事へのコメント

お名前だけで投稿できます。アカウント登録やログインは不要です。 いただいたコメントは確認のうえ公開します。