mod_rewrite
を「用語の意味 → 基本構文 → 実例(判定と実行を明示) → 動作確認 → 運用の注意」の順にまとめました。各サンプルは判定(RewriteCond)と実行(RewriteRule)を行コメントで示し、%1
(条件のキャプチャ参照)、$1
(ルールのキャプチャ参照)、HSTSの意味まで解説します。
まず押さえる用語ミニ辞典
- RewriteEngine On:mod_rewriteを有効化。
- RewriteCond TEST PATTERN [FLAG]:判定を書く行。
TEST
(例:%{HTTP_HOST}
,%{HTTPS}
,%{REQUEST_URI}
)がPATTERN
にマッチしたら真。先頭に!
で否定。=
や!=
による文字列比較も可(例:RewriteCond %{HTTPS} =on
)。 - RewriteRule REGEX TARGET [FLAG]:実行を書く行。リクエストパス(.htaccessならそのディレクトリ基準)が
REGEX
にマッチしたらTARGET
へ書き換え/リダイレクト。 - キャプチャと参照:
(…)
で囲んだ部分は「キャプチャ」。RewriteRule
の正規表現のキャプチャは$1
,$2
…で参照。RewriteCond
での直近のマッチは%1
,%2
…で参照(条件側のキャプチャ参照)。
- 主なフラグ:
[L]
=そこで評価打ち切り /[R=301]
=恒久リダイレクト /[QSA]
=既存クエリ保持 /[QSD]
=既存クエリ破棄 /[NC]
=大文字小文字無視 /[NE]
=二重エスケープ防止 /[E=K:V]
=環境変数設定 /[F]
=403 /[G]
=410。 - HSTS(HTTP Strict Transport Security):ブラウザに「このドメインは常にHTTPSで開け」と命令するヘッダ(例:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
)。先に全ページをHTTPSで安定運用してから有効化する(誤設定で戻せなくなるため要注意)。 - .htaccessとVHostの違い:.htaccessはそのディレクトリ基準で
^
が解釈される。可能ならVHost(サーバ設定)側で完結させる方が速くて安全。
基本構文(.htaccess想定)
<IfModule mod_rewrite.c>
RewriteEngine On
# 判定(必要に応じて複数並べる)
# RewriteCond <TEST> <PATTERN> [FLAGS]
# 実行(マッチしたら置換/リダイレクト)
# RewriteRule <REGEX> <TARGET> [FLAGS]
</IfModule>
実例(行コメント入り)+ていねい解説
1) HTTP→HTTPSへ統一(301)+HSTSの考え方
RewriteEngine On
# 判定:HTTPSでないなら(=on に等しくない)
RewriteCond %{HTTPS} !=on
# 実行:同じホスト・同じパスへ https で 301
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
解説:判定はRewriteCond %{HTTPS} !=on
。%{HTTPS}
はTLSで来た時on
。偽ならRewriteRule
が発動し、%{HTTP_HOST}
(ホスト名)と%{REQUEST_URI}
(パス&クエリ)をそのままHTTPSに乗せ換える。
HSTSは別レイヤ(ヘッダ)で有効化:Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
。ただし完全HTTPS運用が安定してから。
2) wwwあり/なしの統一(301)
RewriteEngine On
# 判定:ホストが www. で始まる(^www\.(.+)$)
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
# 実行:%1 は 直前の RewriteCond の (.+) キャプチャ
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]
解説:^www\.(.+)$
にマッチすると真。(.+)
でwww.
以降をキャプチャし、%1
で参照(条件側のキャプチャ)。これで「非wwwのホスト名+同じパス」へ301。
逆(wwwなし→wwwあり)に統一するなら、判定を否定にする:
RewriteEngine On
# 判定:ホストが www. ではない
RewriteCond %{HTTP_HOST} !^www\. [NC]
# 実行:www. を付与
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
3) 末尾スラッシュの統一(301)
RewriteEngine On
# 判定:/で終わるパス
RewriteCond %{REQUEST_URI} .+/$
# 実行:スラッシュを外した同じパスへ
RewriteRule ^(.+?)/$ /$1 [R=301,L]
解説:判定は%{REQUEST_URI}
が…/
で終わるか。実行は$1
(ルール側のキャプチャ)でパス本体を再利用。APIや特定ディレクトリを除外したい場合は、その判定(RewriteCond
)を先に追加して早期除外。
4) フロントコントローラ(MVCやSPA)
RewriteEngine On
# 判定:物理ファイル/ディレクトリが存在しない
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# 実行:index.php に内部振り分け
RewriteRule ^ index.php [L]
解説:!-f
/!-d
で「無い時だけ」流す。静的ファイル(画像/CSS/JS)は素通りで高速。
5) 旧URL→新URL(301)
RewriteEngine On
# 判定:/old-path または /old-path/
RewriteRule ^old-path/?$ /new-path [R=301,L]
解説:この例は判定をRewriteRule
の正規表現に直書き(シンプルな一致)。大量移行はRewriteMap
で外部表を引くと速くて管理もしやすい。
6) クエリを保持/破棄(QSA/QSD)
# 既存クエリを保持し page=1 を追加
RewriteRule ^search$ /search.php?page=1 [QSA,L]
# 既存クエリを破棄して正規URLへ
RewriteRule ^temp$ /article [QSD,R=301,L]
解説:[QSA]
はQuery String Append(保持+追加)、[QSD]
はDiscard(破棄)。トラッキングパラメータ排除や重複URLの抑制に有効。
7) 直リンク(ホットリンク)防止
RewriteEngine On
# 判定:Referer が空でない かつ 自ドメイン以外
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !example\.com [NC]
# 実行:画像拡張子なら403
RewriteRule \.(png|jpe?g|gif|webp)$ - [F,L]
解説:HTTP_REFERER
は偽装可能なので抑止目的。別画像へ誘導したい場合は[R=302]
でプレースホルダーへ。
8) 拡張子隠し(/about → /about.php)
RewriteEngine On
# 判定:対応する .php が物理に存在する
RewriteCond %{REQUEST_FILENAME}\.php -f
# 実行:/about → /about.php に内部振替
RewriteRule ^(.+)$ $1.php [L]
解説:存在チェックしてから振る。Options -MultiViews
(コンテンツネゴシエーションの無効化)推奨。MultiViewsが有効だと競合しやすい。
「本当に動いてる?」確認の実践
1) リダイレクトはヘッダだけ確認
curl -I http://example.com/old-path
# → HTTP/1.1 301 Moved Permanently
# Location: https://example.com/new-path
コツ:-L
(追従)を付けると最終URLしか見えない。原因追跡は付けない。
2) 内部リライトは「環境変数+一時ヘッダ」で可視化
# 実行時に環境変数をセット
RewriteRule ^ index.php [E=REWRITE_HIT:1,L]
# VHost/Directory 側でヘッダ出力(mod_headers)
Header set X-Rewrite "1" env=REWRITE_HIT
解説:内部リライトはブラウザから見えないので、ヒット時のみX-Rewrite: 1
を返して観測。調査が終わったら削除。
3) 詳細ログ(期間限定)
# Apache 2.4
LogLevel rewrite:trace2 # 0~8程度。調査後は warn に戻す
4) アクセスログに印を付ける
# 例:ヒット時に環境変数 HIT=1 を付与
RewriteRule ^ - [E=HIT:1]
# ログフォーマットに %{HIT}e を埋め込む
LogFormat "%h %l %u %t \\"%r\\" %>s %b \\"%{HIT}e\\"" vhost
CustomLog ${APACHE_LOG_DIR}/access.log vhost
有効化・配置とチューニング
- mod_rewrite有効化(Debian系):
a2enmod rewrite
→systemctl reload apache2
- .htaccessよりVHost推奨:
AllowOverride None
が基本。やむなく使う時は必要最小限。 - 評価コスト削減:
!-f
/!-d
や否定条件で早期除外。正規表現は^
と$
でアンカー。 - 大量301:
RewriteMap
(テキスト/プログラム)で一括変換。 - プロキシ/CDN併用:Cloudflare等の前段があると
%{HTTPS}
やIPの見え方が変わる。X-Forwarded-Proto
等を考慮し、必要ならApache側で信頼プロキシ設定を行う。
ハマりやすいところ
- リダイレクトチェーン:301→301…は避け、一発で最終URLへ。
- 二重エンコード:URLに%が含まれる場合は
[NE]
で保護することがある。 - MultiViewsの干渉:
Options -MultiViews
を検討。 - HSTSのロックイン:HSTSは戻しにくい。HTTPS完全移行が安定してから。
このページの設定はベースラインです。トラフィックやアプリ、CDN/WAF 構成に合わせて調整してください。
コメント