【.htaccess】301リダイレクトの書き方|Redirect・RewriteRule・正規表現パターンまとめ

【.htaccess】301リダイレクトの書き方|Redirect・RewriteRule・正規表現パターンまとめ Webサイト全般

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変更時はこちら 一時的な場合のみ
注意:「とりあえず302」は危険です。302のまま長期間放置すると、Googleが301として再解釈するケースもありますが、評価の引き継ぎが不安定になります。恒久的な変更なら必ず301を使いましょう。

方法①: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の転送 条件付き・パターン置換
処理順序に注意:同じ.htaccessファイル内では、RewriteRuleRedirectより先に処理されます。両方を混在させると意図しない動作になることがあるため、どちらか一方に統一するのが安全です。

実務でよく使うリダイレクトパターン

パターン①: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]

エックスサーバーの場合、管理画面の「.htaccess編集」から追記できます。詳しくは「エックスサーバーの管理画面から.htaccessを編集する方法」をご覧ください。

パターン③:ドメイン移転

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 301Locationヘッダーが正しいことを確認します。

リダイレクトチェーンを追跡する

# -L でリダイレクトを自動追跡、-s で余計な出力を抑制
curl -I -L -s https://example.com/old-page.html

複数回リダイレクトが連鎖していないか確認できます。リダイレクトチェーンは3回以上になるとSEOに悪影響があるため、2回以内に収めましょう。

方法②:ブラウザのDevTools

  1. DevTools を開く(F12
  2. 「Network」タブを選択
  3. 「Preserve log」にチェック
  4. 旧URLにアクセス
  5. 最初のリクエストのステータスが301であることを確認
  6. 「Location」ヘッダーが正しい転送先であることを確認
ブラウザキャッシュに注意:301はブラウザにキャッシュされます。テスト時はシークレットウィンドウを使うか、DevToolsの「Disable cache」を有効にしてください。

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に複数のルールを書く場合、実行順序を把握しておくことが重要です。

  1. RewriteRule(mod_rewrite)が最初に処理される
  2. Redirect / RedirectMatch(mod_alias)が次に処理される
  3. [L]フラグを付けたRewriteRuleにマッチすると、それ以降のRewriteRuleはスキップされる
  4. ただし[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の後に評価
ベストプラクティス:RewriteRuleとRedirectを混在させず、どちらかに統一しましょう。混在させると処理順序の予測が難しくなり、デバッグが困難になります。

まとめ

.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ヘッダーを確認しましょう。

関連記事