Article

サイトリニューアル時のSEO引き継ぎ:リダイレクト設定の極意

高田晃太郎
サイトリニューアル時のSEO引き継ぎ:リダイレクト設定の極意

HTTPリダイレクトは1ホップあたり100〜300msの遅延を追加し³、チェーンが長いとクロールが完了しないことがあります¹。GoogleのSearch Centralでも、過度なリダイレクトチェーンは処理が打ち切られる可能性があると説明され、一般に複数回の転送を要するURLは評価の対象になりにくくなるとされています¹(過去の発言では、5ホップ前後を上限とする言及もあります⁹)。設計の些細な迷いが、検索評価とユーザー体験の両方に直結するのがサイトリニューアル時のリダイレクトです。

情報設計の見直しや技術スタックの刷新に伴いURL構造が変わるのは健全な進化ですが、検索エンジンが過去のシグナルを新URLへ的確に引き継げなければ、ランキング、クリック、コンバージョンは一時的では済まない落ち込みを招きます。Googleは301/308でも302/307でもPageRank(リンク評価)を引き継げると明言していますが⁴、移行の成否はコードの種類ではなく、マッピングの完全性、ホップ数、実装位置、検証の徹底に左右されます。本稿では、CTO/エンジニアリーダーに向けて、理論と運用の両輪でリダイレクト設計の要点を示し、主要な実装パターンのコード例と検証方法を提示します。

リニューアルで失われるものと守るべきシグナル

検索エンジンにとってURLは一次キーです。URLが変わると、コンテンツの同等性、内部リンクの構造、外部リンクの評価、構造化データやhreflang(言語・地域ターゲティング)、canonical(優先URLの宣言)、ページ速度やレンダリング要件まで、複数のシグナルを再評価する必要が生じます。Googleは、正しく設定されたリダイレクトとコンテンツ同等性が確認できれば評価を引き継ぐと説明しますが²、実務では小さな不一致が連鎖して毀損を生みます。タイトルの差分が大きい、本文の情報量が著しく増減している、メインコンテンツの意図が変わっている、内部リンクの係り方が変わっている、このような要素が重なるほど転送先の関連性は薄れます。一般的には、目視と差分チェックを組み合わせ、**意図と情報量の一致を高い水準(目安として9割程度)**に揃えると回復が早い傾向が報告されています。

引き継ぎで最重要なのは、旧URLから新URLへのマッピングを漏れなく一対一で定義し、単一ホップで到達させることです。カテゴリ統合や語尾の正規化、トラッキングパラメータの扱いなどで、無自覚に二段・三段の転送が生まれがちです。HTTPからHTTPS、www有無の正規化、スラッシュの有無などの正規化は、最終的な新URLに一足飛びで着地するよう順序と優先度を設計します¹。さらに、永久に廃止するURLは曖昧に他ページへ逃がさず、明確に410 Goneで返すほうがインデックスの健全性は高まります⁵。サイト全体の健全性という観点では、404をゼロに固執せず、404/410を正しく返して検索エンジンの理解を助ける設計のほうが長期的に有利です⁵。

大規模移行では、URL一覧をクロールとログで突き合わせ、正規表現と辞書の併用でマッピングを生成し、ステージングで影響を可視化する進め方が有効とされています。チェーンとループをゼロに抑え、ヒット率を高めても、長年の外部リンクを持つ一部URLでは同等性のわずかな差が回復速度に影響することがあります。その場合、H1や導入の要旨、内部リンクの係り方を旧ページに寄せて同等性を高めると、Search Consoleで対象クエリが徐々に新URLへ置き換わる傾向が観察されます。細部の一貫性が、検索評価の橋渡しを確実にします。

リダイレクト設計の原則とアンチパターン

設計の基本はシンプルです。恒久的な移行には301か308を使い²⁷、暫定措置やA/Bテストなど一時的な用途には302か307を用います²⁸。308はメソッドと本文を保持する点でPOSTが絡むAPIやフォームの移行で意味を持ちますが⁷、コンテンツページの移行では301でも実質的な差はありません。翻って、恒久移行を302で長期運用するのは悪手です。評価は引き継がれるとはいえ⁴、暫定であるという実装上の意味が運用にノイズをもたらします。

アンチパターンは、チェーン、ループ、曖昧転送、パラメータの落下、正規化の多段化です。曖昧転送とは、旧記事Aをカテゴリトップや似て非なるBへ便宜的に飛ばす行為で、クエリ対応やユーザー意図の観点で悪影響が大きい。パラメータの落下は、UTMのようなトラッキングだけでなく、ソートやフィルタの意味を持つクエリが消失するケースが地味に痛い。正規化の多段化は、http→https→www付与→スラッシュ付与→新パス、のように階段を作ってしまうことで、前述の遅延とクロール失敗の確率を上げます¹。設計段階で、どの入力URLも最終URLへ一発で到達するルールに整理し、衝突や包括漏れをサンドボックスで検証します。

大文字小文字、末尾スラッシュ、日本語パスのエンコード、トレーリングインデックス、ハイフンとアンダースコアの揺れも無視できません。ケースインセンシティブなマッチに逃げると副作用が大きくなる場面もあるため、フレームワークやサーバのマッチング特性を把握し、言語別・市場別のhreflangや地域別サイトの正規化に波及しないよう、ローカルルールとグローバルルールの境界を明確にします。Googleのリダイレクトガイド²とサイト移転のベストプラクティス¹は、設計の原則確認に役立ちます。

ステータスコードの選び方

恒久移行には301または308を推奨します²⁷。GET主体のコンテンツ移行なら301、フォーム送信後のサンクスページやAPIの経路変更ならメソッドを保持する308が安全です⁷。302と307は一時的用途に限定し、長期運用は避けます²⁸。廃止するなら410、法的理由があるなら451を使います⁵¹⁰。さらに、rel=canonicalで優先URLを示すこととリダイレクトは補完関係にあります。移行直後は両方を整え²、サイトマップXMLも新URLで再送信¹し、Search Consoleのアドレス変更ツール(ドメイン移転時)を適切に用います⁶。

チェーンとループを防ぐルールの順序設計

最初にホストとプロトコルの正規化を定義し、続けて末尾スラッシュや大文字小文字の統一を行い、その上で旧→新パスのマッピングを適用するのが基本です。ただし、この順序をそのまま実装に落とすと多段化することがあります。実装層が複数(CDN、エッジ、オリジン)に跨る場合は、最も手前の層でまとめて最終URLへ解決させ、後段はパススルーに徹させます。ループ検出は、転送先が再び転送対象に一致しないかを正規化後の形で比較するのがコツです。検証では、代表URLだけでなく、スラッシュの有無、大文字小文字、クエリ有無、HTTP/HTTPS、www有無の直積を作り、すべてが単一ホップで着地することを確認します¹。

主要スタック別の実装コードと検証

環境ごとにベストな実装位置と表現が異なります。ページレンダリング後では遅すぎるため、基本はCDNやエッジ、サーバ設定層で完結させます。以下は実運用で頻出するパターンの実装例です。

Apache(.htaccess)でのベーシックな移行は、mod_rewriteを使って一発で最終URLへ飛ばします。辞書を使うと規模の大きい移行でも安全に運用できます。順序は「個別マッピング → まとめ正規化」の順にし、個別マッピングは絶対URLへ直接転送すると単一ホップにできます。

# .htaccess
RewriteEngine On

# 旧→新のパスマッピング(絶対URLへ一発で)
RewriteRule ^old-path/?$ https://www.example.com/new-path [R=301,L]
RewriteRule ^blog/(.*)$ https://www.example.com/media/$1 [R=301,L]

# 存在しない旧記事は410
RewriteRule ^old-archive/.* - [G,L]

# 残余のHTTP/HTTPS, www正規化をまとめて処理(クエリは自動保持)
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\.example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]

Nginxはリライトルールとreturnを併用すると読みやすさと性能のバランスが取れます。正規表現は最小限にし、特定パスはlocation = でピンポイントに定義します。returnでの転送は明示的にクエリを保持します。

# HTTP→HTTPS, 非www→www
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name www.example.com;

    # 旧→新の明示的マッピング(クエリ保持)
    location = /old-path {
        return 301 https://www.example.com/new-path$is_args$args;
    }
    rewrite ^/blog/(.*)$ /media/$1 permanent; # 既定でクエリ保持

    # 廃止URLは410
    location ^~ /old-archive/ { return 410; }
}

Cloudflare Workersのようなエッジ実行環境では、辞書とパターンで高速に解決できます。メソッド保持が必要なら308、通常のページなら301で十分です⁷。

// Cloudflare Workers
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const host = 'www.example.com';

    if (url.host !== host) {
      url.host = host;
      // メソッド保持が不要なページ転送は301で十分
      return Response.redirect(url.toString(), 301);
    }

    const map = new Map([
      ['/old-path', '/new-path'],
    ]);

    if (map.has(url.pathname)) {
      url.pathname = map.get(url.pathname);
      return Response.redirect(url.toString(), 301);
    }

    const blog = url.pathname.match(/^\/blog\/(.*)$/);
    if (blog) {
      url.pathname = `/media/${blog[1]}`;
      return Response.redirect(url.toString(), 301);
    }

    return fetch(request);
  }
};

Next.jsはアプリケーション側に委ねるより、可能ならCDNで完結させるのが理想ですが、プロジェクト管理の観点でnext.config.jsに集約しておくとレビューフローに乗せやすくなります(permanent: true は308を返します)。

// next.config.js
/**** 完全な例 ****/
/** @type {import('next').NextConfig} */
const nextConfig = {
  async redirects() {
    return [
      { source: '/old-path', destination: '/new-path', permanent: true },
      { source: '/blog/:slug*', destination: '/media/:slug*', permanent: true },
    ];
  },
};
module.exports = nextConfig;

Netlifyの_redirectsファイルを使うと、宣言的に記述できます。ビルド成果物と一緒にデプロイされるため、インフラ変更なしで扱えるのが利点です。

# _redirects
/old-path        /new-path       301
/blog/*          /media/:splat   301
/old-archive/*   /               410

AWS CloudFrontでは、軽量なリダイレクトはCloudFront Functionsのviewer-requestで早期に振り分けるのが近年の一般的な選択肢です(高度な処理が必要な場合はLambda@Edge)。クエリを保持して転送します。

// CloudFront Functions (viewer-request)
function handler(event) {
  var request = event.request;
  var host = request.headers.host.value;

  if (host !== 'www.example.com') {
    return redirect('https://www.example.com' + request.uri + qs(request.querystring));
  }

  if (request.uri === '/old-path') {
    return redirect('https://www.example.com/new-path' + qs(request.querystring));
  }

  // /blog/* → /media/*
  if (request.uri.startsWith('/blog/')) {
    var tail = request.uri.slice('/blog/'.length);
    return redirect('https://www.example.com/media/' + tail + qs(request.querystring));
  }

  return request;
}

function qs(q) {
  if (!q || Object.keys(q).length === 0) return '';
  var pairs = [];
  for (var k in q) {
    var v = q[k];
    // 値が複数ある場合も展開
    if (Array.isArray(v)) {
      v.forEach(function(p){ pairs.push(k + '=' + p.value); });
    } else if (v && v.value) {
      pairs.push(k + '=' + v.value);
    } else {
      pairs.push(k); // 値なしクエリ
    }
  }
  return '?' + pairs.join('&');
}

function redirect(location) {
  return {
    statusCode: 301,
    statusDescription: 'Moved Permanently',
    headers: {
      location: { value: location }
    }
  };
}

Node.js/Expressでは、ルータの最上流で処理し、衝突やループを避けるために正規化後のキーでマップを引くのが安全です。パラメータは可能な限り保持します。

import express from 'express';
const app = express();

const map = new Map([
  ['/old-path', '/new-path'],
]);

app.use((req, res, next) => {
  const desiredHost = req.headers.host === 'example.com' ? 'www.example.com' : req.headers.host;
  if (req.headers.host !== desiredHost) {
    return res.redirect(301, `https://${desiredHost}${req.url}`);
  }

  const key = (req.path.replace(/\/$/, '') || '/');
  const search = req._parsedUrl.search || '';

  if (map.has(key)) {
    return res.redirect(301, `${map.get(key)}${search}`);
  }

  const m = req.path.match(/^\/blog\/(.*)$/);
  if (m) {
    return res.redirect(301, `/media/${m[1]}${search}`);
  }

  return next();
});

app.listen(3000);

実装後の検証は、遅延と到達性の両方を見ます。curlでヘッダーを確認し、Locationが最終URLを指し、ホップが一回であること、クエリが保持されていることを確かめます。Chrome DevToolsのNetworkタブで旧URL→新URLのシーケンスを確認し、Timingで追加TTFB(最初のバイト到達時間)の増分が100〜300ms程度に収まっているか観察します³。WebPageTestやLighthouseでモバイル回線を想定した遅延の増分を測ると、CDNでの処理とアプリ層での処理の差が明確に見えます。Core Web Vitalsの最適化に取り組んでいる場合は、LCP(最大視覚コンテンツ表示)の起点が新URLで正しく計測されていることも確認しましょう。

移行当日の運用と90日間の観測

ローンチ前にはDNSとキャッシュのTTLを短縮し、ロールバックの余地を確保します。リダイレクトはフラグで一括切り替えできるよう用意し、ステージングと本番でルールが同一であることをダンプ比較で保証します。サイトマップXMLは新URLで提供し¹、robots.txtの参照とSearch Consoleへの再送信を行います。ドメイン移転であればアドレス変更ツールを使い⁶、旧ドメインでもサイトマップを一定期間提供してシグナルを伝達します。内部リンクは可能な限り新URLへ直貼りに差し替え、自己リダイレクトを発生させないことが肝要です¹。404、410、5xx、3xxの分布を時系列でウォッチします。

初週は、404が急増するパターン、外部リンクの重い旧URLが曖昧転送に落ちているパターン、パラメータが消失するパターンが典型的です。404はリファラとパスから原因を素早く特定し、辞書に追記して再デプロイします。重い外部リンクは個別に301で最終URLへ直行させ、コンテンツの同等性を微調整します。パラメータの扱いは、意図的に落として良いもの(完全なトラッキング専用)と、保持すべきもの(ソート・フィルタ・ページング)を設計に反映させます。Search Consoleのクロール統計で、1日あたりのクロール済みページ数、平均応答、リダイレクト比率を観察し、過度な3xx比率や応答時間の悪化がないかをチェックします。

KPIは段階的に見ます。短期はインデックスの置き換わり速度と404率、中期はクエリ単位での新URLへの評価移行、長期はセッション品質とコンバージョンです。一般的に、設計と実装が適切な移行では、1〜2週間で主要クエリの検索結果が新URLに置き換わり、4〜8週間で大半が復調するケースが多いとされます。逆に、3週間を超えても旧URLが検索結果に居座り続ける場合、同等性や内部リンク、サイトマップの一貫性に未解決の原因が潜むことが多い。問題の特定には、旧→新のマッピング表を中間のリダイレクトや正規化を経た最終URLへ展開し、Search ConsoleのURL検査で両者のインデックス状態とcanonicalの解釈を突き合わせます²。構造化データの継承が崩れているケースも見逃せません。

最後に、移行の影響をパフォーマンス面でも丁寧に観測します。Redirectの追加でLCPやTTFBがどれほど動くか、CDN実装とアプリ実装で差はあるか、国や回線ごとの差がどの程度かを計測し、リダイレクト規則の簡素化やエッジ移行の投資対効果を定量化します。経営視点では、外部リンクの価値と回復までの期間、機会損失、作業コストを一つの表にまとめて意思決定の材料にすると、次のリニューアルでもブレない基準ができます。

移行設計をチームの資産にする

移行は一度きりのイベントではありません。製品の進化ごとにURLや情報設計は変わります。移行計画テンプレート、マッピングの生成スクリプト、検証用のURL直積セット、ダッシュボード定義をリポジトリに残し、次回は差分だけを詰める体制にしておくと、速度と品質が両立できます。設計審査をPull Requestにのせ、インフラとアプリの接点で多段化が起きていないかをコードレビューでチェックする文化を作ると、属人性を減らせます。

実装と観測の往復が、検索評価の連続性とユーザー体験の滑らかさを支えます。

まとめ:評価を失わずに前へ進むために

サイトリニューアルは、検索評価を壊すリスクと、体験とビジネス価値を高める機会の両方を抱えています。鍵は、旧→新の一対一マッピングを作り、単一ホップで到達させ、同等性を担保し、デプロイ前後の検証を怠らないことです。HTTPの性質上、リダイレクトは遅延を生みますが³、実装層を前倒しし、ルールを簡素に保てば、その影響は小さく抑えられます。ローンチから90日間の継続観測で未解決の揺れを潰し込み、必要な微調整を行えば、評価は新しい情報設計の上で安定していきます。

次に着手すべきは、あなたの環境での最適な実装位置の決定と、現行URLの完全な棚卸しです。今日からクロールとログの収集を始め、マッピング表の初版を用意してみませんか。もし基準やテンプレートが必要なら、本稿のリンク先ガイドを起点に、チームの文脈へ合わせて育てていきましょう。変化を恐れず、評価を失わず、前へ。

参考文献

  1. Google Search Central: Move your site with URL changes
  2. Google Search Central: Redirects and Google Search
  3. MDN Web Docs: HTTP Redirections
  4. Search Engine Land: Google says no PageRank dilution using 301 or 302 or other 30x redirects anymore
  5. Google Search Central: HTTP status codes and network errors
  6. Google Search Console ヘルプ: アドレス変更ツールについて
  7. MDN Web Docs: 308 Permanent Redirect
  8. MDN Web Docs: 307 Temporary Redirect
  9. SEO Roundtable: Google: GoogleBot Will Follow 5 Redirect Hops At Most
  10. MDN Web Docs: 451 Unavailable For Legal Reasons