301リダイレクトは、URLが恒久的に変更されたことをブラウザと検索エンジンに伝える仕組みです。
.htaccessに記述するだけで、旧URLへのアクセスを新URLへ自動転送できます。
この記事では、RedirectディレクティブとRewriteRuleの2つの方法を軸に、実務でよく使うリダイレクトパターンをすべて解説します。
- 301と302の違いとSEOへの影響
- Redirect / RewriteRuleの使い分け
- ページ・ディレクトリ・ドメイン単位のリダイレクト
- www統一・常時SSL・末尾スラッシュの正規化
- curl -Iやブラウザでの動作確認方法
- 効かないときのトラブルシューティング
301と302の違い
リダイレクトには主に2種類のステータスコードがあります。目的に合ったコードを選ばないと、SEO評価の引き継ぎに失敗します。
| 項目 | 301(Moved Permanently) | 302(Found / Temporary) |
|---|---|---|
| 意味 | 恒久的な移転 | 一時的な移転 |
| SEO評価 | 新URLに引き継がれる | 旧URLに留まる |
| ブラウザキャッシュ | キャッシュされる | 毎回サーバーに問い合わせ |
| 使用場面 | URL変更・ドメイン移転・SSL化 | メンテナンス中・A/Bテスト |
| Google推奨 | URL変更時はこちら | 一時的な場合のみ |
方法①:Redirectディレクティブ
Apache標準のmod_aliasが提供するディレクティブです。シンプルなURLの転送に向いています。
基本構文
# 基本形 Redirect 301 /旧パス https://example.com/新パス # 具体例:ページ単位のリダイレクト Redirect 301 /old-page.html https://example.com/new-page/ # ディレクトリ単位(配下すべて転送) Redirect 301 /old-dir/ https://example.com/new-dir/
| パラメータ | 説明 | 例 |
|---|---|---|
301 |
ステータスコード | 301 / 302 / 303 / 410 |
/旧パス |
リダイレクト元(パスのみ) | /old-page.html |
新URL |
リダイレクト先(完全URL) | https://example.com/new/ |
ポイント:Redirect ディレクティブの旧パスにはドメインを含めません。/から始まるパス部分だけを指定します。一方、転送先はhttps://から始まる完全なURLを指定します。
RedirectMatchで正規表現を使う
パターンに一致する複数URLをまとめてリダイレクトしたい場合はRedirectMatchを使います。
# .html を削除してリダイレクト RedirectMatch 301 ^/(.+).html$ https://example.com/$1/ # 特定ディレクトリ配下を別ディレクトリへ RedirectMatch 301 ^/blog/2024/(.*)$ https://example.com/archive/2024/$1 # 複数拡張子をまとめてリダイレクト RedirectMatch 301 ^/(.+).(htm|shtml)$ https://example.com/$1/
方法②:RewriteRuleによるリダイレクト
mod_rewriteが提供する高機能な書き換えルールです。条件(RewriteCond)と組み合わせて柔軟な制御ができます。
基本構文
RewriteEngine On # ページ単位 RewriteRule ^old-page.html$ https://example.com/new-page/ [R=301,L] # ディレクトリ単位 RewriteRule ^old-dir/(.*)$ https://example.com/new-dir/$1 [R=301,L]
| フラグ | 意味 | 用途 |
|---|---|---|
[R=301] |
301リダイレクト | 恒久的な転送 |
[R=302] |
302リダイレクト | 一時的な転送 |
[L] |
Last(最後のルール) | 以降のルールを処理しない |
[NC] |
No Case(大文字小文字無視) | URL の大文字小文字を区別しない |
[QSA] |
Query String Append | クエリ文字列を引き継ぐ |
[NE] |
No Escape | 特殊文字をエスケープしない |
RewriteCondで条件を付ける
RewriteEngine On
# 特定のホスト名でアクセスされた場合のみリダイレクト
RewriteCond %{HTTP_HOST} ^old-domain.com$ [NC]
RewriteRule ^(.*)$ https://new-domain.com/$1 [R=301,L]
# クエリ文字列を条件にする
RewriteCond %{QUERY_STRING} ^id=123$
RewriteRule ^page.php$ https://example.com/new-page/? [R=301,L]
末尾の「?」の意味:リダイレクト先URLの末尾に?を付けると、元のクエリ文字列を引き継がずにリダイレクトします。?id=123を消したい場合に使います。
Redirect vs RewriteRule 比較
どちらを使うべきか迷ったときの判断基準です。
| 比較項目 | Redirect | RewriteRule |
|---|---|---|
| モジュール | mod_alias | mod_rewrite |
| 正規表現 | RedirectMatchで対応 | 標準で使用可能 |
| 条件分岐 | 不可 | RewriteCondで柔軟に可能 |
| クエリ文字列の制御 | 不可 | 可能(QSA / ? で制御) |
| 処理順序 | RewriteRuleの後に実行 | Redirectの前に実行 |
| 記述の簡潔さ | ◎ シンプル | △ やや複雑 |
| 推奨場面 | 単純な1対1の転送 | 条件付き・パターン置換 |
RewriteRuleがRedirectより先に処理されます。両方を混在させると意図しない動作になることがあるため、どちらか一方に統一するのが安全です。
実務でよく使うリダイレクトパターン
パターン①:wwwあり/なしの統一
RewriteEngine On
# www なし → www あり に統一
RewriteCond %{HTTP_HOST} ^example.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [R=301,L]
# www あり → www なし に統一
RewriteCond %{HTTP_HOST} ^www.example.com$ [NC]
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L]
パターン②:http → https(常時SSL化)
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
パターン③:ドメイン移転
RewriteEngine On
RewriteCond %{HTTP_HOST} ^(www.)?old-domain.com$ [NC]
RewriteRule ^(.*)$ https://new-domain.com/$1 [R=301,L]
サブドメインも含めて転送する場合は次のように書きます。
RewriteEngine On
RewriteCond %{HTTP_HOST} old-domain.com$ [NC]
RewriteRule ^(.*)$ https://new-domain.com/$1 [R=301,L]
パターン④:末尾スラッシュの統一
RewriteEngine On
# 末尾スラッシュを付与(ファイル以外)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1/ [R=301,L]
# 末尾スラッシュを除去
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^(.+)/$ https://%{HTTP_HOST}/$1 [R=301,L]
パターン⑤:index.htmlの正規化
RewriteEngine On
RewriteRule ^(.*/)?index.html$ https://%{HTTP_HOST}/$1 [R=301,L]
URLの末尾に/index.htmlが付いている場合、ディレクトリURLに正規化します。重複コンテンツの防止に有効です。
パターン⑥:クエリ文字列付きURLのリダイレクト
RewriteEngine On
# ?id=123 → /page/123/ にリダイレクト
RewriteCond %{QUERY_STRING} ^id=([0-9]+)$
RewriteRule ^page.php$ https://example.com/page/%1/? [R=301,L]
%1はRewriteCondのキャプチャグループを参照します。末尾の?で元のクエリ文字列を削除しています。
正規表現チートシート
.htaccessのリダイレクトで頻出する正規表現パターンをまとめました。
| パターン | 意味 | マッチ例 |
|---|---|---|
^ |
行頭 | – |
$ |
行末 | – |
. |
任意の1文字 | a, 1, – |
.* |
0文字以上の任意の文字列 | (空文字列含む) |
.+ |
1文字以上の任意の文字列 | abc, 123 |
[0-9]+ |
1桁以上の数字 | 42, 2024 |
[a-z]+ |
1文字以上の英小文字 | page, blog |
(.*) |
キャプチャグループ($1で参照) | パス全体 |
. |
ピリオド(エスケープ) | . |
(www.)? |
www.があってもなくても | www. / 空 |
リダイレクトの確認方法
設定後は必ず動作確認を行いましょう。正しくリダイレクトされないと、SEO評価を損ないます。
方法①:curl -I コマンド
ターミナルで最も確実に確認できる方法です。
# レスポンスヘッダーだけ取得 curl -I https://example.com/old-page.html # 出力例 HTTP/1.1 301 Moved Permanently Location: https://example.com/new-page/
HTTP/1.1 301とLocationヘッダーが正しいことを確認します。
リダイレクトチェーンを追跡する
# -L でリダイレクトを自動追跡、-s で余計な出力を抑制 curl -I -L -s https://example.com/old-page.html
複数回リダイレクトが連鎖していないか確認できます。リダイレクトチェーンは3回以上になるとSEOに悪影響があるため、2回以内に収めましょう。
方法②:ブラウザのDevTools
- DevTools を開く(
F12) - 「Network」タブを選択
- 「Preserve log」にチェック
- 旧URLにアクセス
- 最初のリクエストのステータスが
301であることを確認 - 「Location」ヘッダーが正しい転送先であることを確認
WordPressでの注意点
WordPressサイトで.htaccessリダイレクトを設定する際には、特有の注意点があります。
記述する位置
WordPressの.htaccessには# BEGIN WordPress〜# END WordPressのブロックがあります。リダイレクトルールはこのブロックの上に記述してください。
# --- カスタムリダイレクト(ここに記述)---
RewriteEngine On
RewriteRule ^old-page/$ https://example.com/new-page/ [R=301,L]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress
# BEGIN WordPress〜# END WordPressの間に書いた内容は、パーマリンク設定を保存するたびにWordPressが上書きします。カスタムルールは必ずこのブロックの外に書いてください。
リダイレクトプラグインとの併用
| 方法 | メリット | デメリット |
|---|---|---|
| .htaccess直接編集 | 最速(Apacheレベルで処理) | 記述ミスで500エラーの可能性 |
| プラグイン(Redirectionなど) | GUI操作・ログ取得可能 | PHPレベルの処理で若干遅い |
| wp_redirect()関数 | 条件分岐が柔軟 | テーマ/プラグイン依存 |
パフォーマンスを重視するなら.htaccess、管理のしやすさを重視するならプラグインが適しています。
WordPressでのリダイレクト全般については「【WordPress】特定のページをリダイレクトする方法」で詳しく解説しています。
効かないときのトラブルシューティング
リダイレクトが動作しない場合、以下を順番に確認してください。
| チェック項目 | 確認方法 | 対処法 |
|---|---|---|
| mod_rewriteが有効か | apache2ctl -M | grep rewrite |
サーバー管理者に依頼 / httpd.confで有効化 |
| .htaccessが読み込まれているか | AllowOverrideがNoneでないか確認 |
AllowOverride Allに変更 |
| RewriteEngine Onの記述漏れ | .htaccessの先頭を確認 | RewriteEngine Onを追記 |
| ルールの順序 | より具体的なルールが先にあるか | 具体的なルール → 汎用的なルールの順に並べる |
| ブラウザキャッシュ | シークレットウィンドウで確認 | キャッシュクリア or curl -Iで確認 |
| CDNキャッシュ | CDN管理画面を確認 | キャッシュパージ |
| WordPress上書き | # BEGIN/END WordPress内に書いていないか | ブロックの上に移動 |
| 500エラーが出る | エラーログを確認 | 構文エラーを修正(よくある原因:スペース不足、フラグの書き間違い) |
デバッグ用:RewriteLog(開発環境のみ)
Apache 2.4以降では、httpd.confでリライトのログレベルを上げて原因を特定できます。
# httpd.conf に追記(本番では使わない) LogLevel alert rewrite:trace6
ログファイルにRewriteRuleの評価過程が出力されるため、どのルールでマッチ/スキップしたか確認できます。
SEOへの影響と注意点
| 観点 | 301の場合 | 対策 |
|---|---|---|
| ページランク | 新URLに引き継がれる | できるだけ早く301を設定する |
| インデックス | 数日〜数週間で新URLに切り替わる | Search Consoleで「URL検査」から再クロール依頼 |
| リダイレクトチェーン | チェーンが長いとクロール予算を浪費 | A→B→CではなくA→Cに直接リダイレクト |
| リダイレクトループ | A→B→Aでクロール不能 | curl -I -Lで事前確認 |
| サイトマップ | 旧URLが残っていると警告 | リダイレクト後にサイトマップを更新 |
| 内部リンク | リダイレクト経由は無駄 | 内部リンクのURLを新URLに直接書き換える |
ルールの実行順序
.htaccessに複数のルールを書く場合、実行順序を把握しておくことが重要です。
RewriteRule(mod_rewrite)が最初に処理されるRedirect/RedirectMatch(mod_alias)が次に処理される[L]フラグを付けたRewriteRuleにマッチすると、それ以降のRewriteRuleはスキップされる- ただし
[L]はmod_aliasのRedirectには影響しない
# 実行順序の例 RewriteEngine On RewriteRule ^page-a$ /page-b [R=301,L] # ← 1番目に評価 RewriteRule ^page-c$ /page-d [R=301,L] # ← page-aがマッチした場合スキップ Redirect 301 /page-e /page-f # ← RewriteRuleの後に評価
まとめ
.htaccessの301リダイレクト設定について、用途別に整理します。
| 用途 | 推奨方法 | 記述例 |
|---|---|---|
| ページ単位の転送 | Redirect | Redirect 301 /old /new |
| パターンマッチ転送 | RedirectMatch / RewriteRule | RedirectMatch 301 ^/blog/(.*)$ /archive/$1 |
| 条件付き転送 | RewriteRule + RewriteCond | ホスト名・プロトコルで分岐 |
| www統一 | RewriteRule | RewriteCondでHTTP_HOSTを判定 |
| 常時SSL | RewriteRule | RewriteCondでHTTPS offを判定 |
| 末尾スラッシュ統一 | RewriteRule | ファイル存在チェックと組合せ |
リダイレクトを設定したら、必ずcurl -IやブラウザのDevToolsで301ステータスとLocationヘッダーを確認しましょう。

