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 構成に合わせて調整してください。



コメント