.htaccessでの各種リダイレクト例

スポンサーリンク

リダイレクト

リダイレクトについて

リダイレクトはページを転送したり、URLを書き換えたりすることができ、古いWebサイトから新しいWebサイトへの移転をはじめ、端末ごとの振り分けやURLの正規化など様々な用途で使えます。

このページでは主にリダイレクトの例を紹介します。

RewriteとRedirectの違い

RewriteはURLの書き換えが発生せず(URLそのまま)、RedirectはURLが書き換えられるため転送したようにページ遷移します。

URLの書き換えが発生しないというのは、あたかもそのURLが本来のURLのように振る舞うという意味で、リライト先が画像の場合はそのまま画像が表示されます。

書き方はほぼ同じで、末尾のフラグ(オプションのようなもの)の指定の違いのみです。

Rewrite例:URL書き換えなし

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /
   RewriteRule ^test[/]?$ /tmp/test.jpg [L]
</IfModule>

Redirect例:アクセスするとリダイレクト先に転送される(URL書き換えあり)

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /
   RewriteRule ^test[/]?$ /tmp/test.jpg [L,R=302]
</IfModule>

「L」はそれ以降のルールは無視するという意味で、「R=302」は一時的なリダイレクトの意味です。

RewriteRuleで「R=」を付けない場合はRewrite(URL書き換え無し)になるということですね。

異なるドメインの場合は[L]でも302のリダイレクトとして扱われます

基本的な記述方法とフラグ

RewriteRule

RewriteRuleは条件と転送先を1行で書きます。

簡単な転送の場合はこれで行います。

RewriteRule 旧ページ 新ページ [フラグ]

例えば old.html から new.html へ、301で転送する場合は以下のような感じです。

RewriteRule old.html$ new.html [R=301,L]

RewriteCond

RewriteCondは条件だけを記述し、その次に来るRewriteRuleで転送を行います。

RewriteCondは連続して複数記述することができ、末尾に [OR] フラグがあると、その次の条件とはORで判定されます。

例えば以下の XXX と YYY は「XXX OR YYY」という感じで評価されます。

RewriteCond XXX [OR]
RewriteCond YYY
RewriteRule ***

大文字小文字を区別しない [NC] フラグなどと併用する場合はカンマで区切って記述します。

RewriteCond XXX [OR,NC]
RewriteCond YYY [NC]
RewriteRule ***

[OR] が指定されていない場合はANDとして評価されます。

RewriteCond XXX
RewriteCond YYY
RewriteRule ***
RewriteCond XXX [NC]
RewriteCond YYY [NC]
RewriteRule ***

OR と AND が混ざってくると結構ややこしいので、場合によっては別の条件として分けて記述した方が後で分かりやすい場合もあります。

リダイレクトの実例

ページ単位のリダイレクト

old.html にアクセスされると、https://sakue.com/new.html へ転送します。

一時的なリダイレクトの場合は「R=301」を「R=307」もしくは「R=302」にします。

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteBase /
   RewriteRule old.html$ https://sakue.com/new.html [R=301,L]
</IfModule>

同じサイト&ディレクトリ内の場合

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteBase /
   RewriteRule old.html$ new.html [R=301,L]
</IfModule>

WordPressのパーマリンク変更例

<IfModule mod_rewrite.c>
   RewriteEngine on 
   RewriteBase /
   RewriteRule ^wordpress/2020/08/26/さくらインターネットのwordpress/$ "https://sakue.com/archives/136" [R=301,L]
   RewriteRule ^wordpress/2020/08/27/windows10の各種ファイルの保存先/$ "https://sakue.com/archives/155" [R=301,L]
   RewriteRule ^wordpress/2020/08/27/wordpressのメールとさくら/$ "https://sakue.com/archives/176" [R=301,L]
   RewriteRule ^wordpress/2020/08/27/hdmiキャプチャデバイス対決/$ "https://sakue.com/archives/182" [R=301,L]
   RewriteRule ^wordpress/2020/08/27/さくらインターネットと常時ssl/$ "https://sakue.com/archives/187" [R=301,L]
</IfModule>

日本語の場合はそのまま日本語で記述しますが、.htaccessの文字コードは「UTF-8」で保存してください。

ディレクトリ単位のリダイレクト

例えば https://sakue.com/old/test.html へアクセスされると、 https://sakue.com/new/test.html などへリダイレクトされます。

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteBase /
   RewriteRule ^old(.*)$ /new$1 [R=301,L]
</IfModule>

一部で正規表現での記述がありますが、

「^」は~で始まる

「(.*)」は任意の文字列

「$1」は1番めの括弧の文字列を利用するという意味です(後方参照)

 

WordPressでディレクトリを変更した場合の例です。

<IfModule mod_rewrite.c>
   RewriteEngine on 
   RewriteBase /
   RewriteRule ^wordpress/archives/(.*)$ /archives/\ [R=301,L]
</IfModule>

https://sakue.com/wordpress/archives/~ を https://sakue.com/archives/~ へ転送します。

ドメイン単位のリダイレクト

ドメインを変更したけど、ディレクトリやファイルの構成は全く同じで、ドメインだけ引っ越したような場合の例です。

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteBase /
   RewriteCond %{HTTP_HOST} ^(old.com) [NC]
   RewriteRule ^(.*) https://new.jp/\ [R=301,L]
</IfModule>

パラメータ付きURLの簡略化

https://sakue.com/cam1 へアクセスすると、https://sakue.com/cgi-bin/zm/nph-zms?mode=single&monitor=1&scale=100 の情報を表示します(URLはそのまま)

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /
   RewriteRule ^cam1/$ /cgi-bin/zm/nph-zms?mode=single&monitor=1&scale=100 [L]
   RewriteRule ^cam2/$ /cgi-bin/zm/nph-zms?mode=single&monitor=2&scale=100 [L]
   RewriteRule ^cam3/$ /cgi-bin/zm/nph-zms?mode=single&monitor=3&scale=100 [L]
</IfModule>

ファイル/ディレクトリが存在しない場合にindex.phpに飛ばす

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteRule . /index.php [L]
</IfModule>

特定ディレクトリの除外

まとめて転送するけど、特定のディレクトリやファイルは除外したい場合の指定方法です。

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteBase /
   RewriteCond %{REQUEST_URI} !(^/除外ディレクトリ名/)
   RewriteRule ^$ https://sakue.com/ [R=301,L]
</IfModule>

複数ある場合は続けて記述します。

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteBase /
   RewriteCond %{HTTP_HOST} ^(sakue.com) [NC]
   RewriteCond %{REQUEST_URI} !(^/SnapShot/)
   RewriteCond %{REQUEST_URI} !(^/tmp/)
   RewriteRule ^(.*) https://new.jp/\ [R=301,L]
</IfModule>

上記の除外例では条件は全て「AND」として扱われるため、以下のような意味になります。

  • ホスト名がsakue.comで始まっている
  • かつ、URIが /SnapShot/ から開始ではない
  • かつ、URIが /tmp/ から開始でもない

上記の条件を満たす場合に転送する。という意味です。

「OR」の場合は [OR] や、フラグと併用する場合は [OR,NC] などと記述しますが、ANDと違って少しややこしいので注意しましょう。

wwwなしのURLに統一

例えば https://www.sakue.com を https://sakue.com にします。

サブディレクトリなども全てwww無しになります。

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{HTTP_HOST} ^www\.sakue\.com
   RewriteRule ^(.*) https://sakue.com/\ [R=301,L]
</IfModule>

www有りのURLに統一

例えば https://sakue.com を https://www.sakue.com にします。

サブディレクトリなども全てwww有りになります。

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{HTTP_HOST} ^sakue\.com
   RewriteRule ^(.*) https://www.sakue.com/\ [R=301,L]
</IfModule>

index.html無しのURLに統一

一般的なWebサーバはファイル名まで指定せず、ディレクトリで終わっている場合は「index.html」などを返しますが、URLから「index.html」を除去してスッキリさせます。

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{THE_REQUEST} ^.*/index.html
   RewriteRule ^(.*)index.html$ https://sakue.com/\ [R=301,L]
</IfModule>

index.phpの場合も同様です

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{THE_REQUEST} ^.*/index.php
   RewriteRule ^(.*)index.html$ https://sakue.com/\ [R=301,L]
</IfModule>

index.html、index.phpの両方に対応し、転送先のホスト名も環境変数から取る場合の例です。

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteCond %{THE_REQUEST} ^.*/index.(html|php)
   RewriteRule ^(.*)index.(html|php)$ https://%{HTTP_HOST}/\ [R=301,L]
</IfModule>

httpからhttpsへリダイレクト(常時SSL)

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteCond %{HTTPS} off
   RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

httpからhttpsへリダイレクト(一部除外)

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /

   # HTTPでアクセスされた場合、
   RewriteCond %{HTTPS} off

   # 以下のURLは常に https にリダイレクトする
   RewriteCond %{HTTP_HOST} sakue.com
   RewriteCond %{REQUEST_URI} ^/admin/.*$ [OR]
   RewriteCond %{REQUEST_URI} ^/inquiry/.*$ 

   # ただし以下は除く
   RewriteCond %{REQUEST_URI} !^/assets/.*$
   RewriteCond %{REQUEST_URI} !^.*\.(js|css|gif|jpg|png|ico)$

   # https にリダイレクト
   RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</IfModule>

httpsからhttpへリダイレクト(一部除外)

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /

   # HTTPSでアクセスされた場合、
   RewriteCond %{HTTPS} on

   # 以下のURL以外は常に http にリダイレクトする
   RewriteCond %{HTTP_HOST} sakue.com
   RewriteCond %{REQUEST_URI} !^/admin/.*$
   RewriteCond %{REQUEST_URI} !^/inquiry/.*$

   # ただし以下は除く
   RewriteCond %{REQUEST_URI} !^/assets/.*$
   RewriteCond %{REQUEST_URI} !^.*\.(js|css|gif|jpg|png|ico)$

   # http にリダイレクト
   RewriteRule ^.*$ http://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</IfModule>

httpとhttpsの転送(混合)

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /

   # (1) HTTPでアクセスされた場合、
   RewriteCond %{HTTPS} off

   # 以下のURLは常に https にリダイレクトする
   RewriteCond %{HTTP_HOST} sakue.com
   RewriteCond %{REQUEST_URI} ^/admin/.*$ [OR]
   RewriteCond %{REQUEST_URI} ^/inquiry/.*$ 

   # ただし以下は除く
   RewriteCond %{REQUEST_URI} !^/assets/.*$
   RewriteCond %{REQUEST_URI} !^.*\.(js|css|gif|jpg|png|ico)$

   # https にリダイレクト
   RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R,L]


   # (2) HTTPSでアクセスされた場合、
   RewriteCond %{HTTPS} on

   # 以下のURL以外は常に http にリダイレクトする
   RewriteCond %{HTTP_HOST} sakue.com
   RewriteCond %{REQUEST_URI} !^/admin/.*$
   RewriteCond %{REQUEST_URI} !^/inquiry/.*$

   # ただし以下は除く
   RewriteCond %{REQUEST_URI} !^/assets/.*$
   RewriteCond %{REQUEST_URI} !^.*\.(js|css|gif|jpg|png|ico)$

   # http にリダイレクト
   RewriteRule ^.*$ http://%{HTTP_HOST}%{REQUEST_URI} [R,L]
</IfModule>

404のエラーを返す

リモートホストを返す環境変数の %{REMOTE_HOST} を使う場合は、httpd.confで以下を有効にする必要があります。
エラーは出ませんが、ホスト名が取れないので一致しません。

HostnameLookups On

特定のIPやホストからのアクセスは404を返す

「~または~」というORの条件の場合は末尾に [OR] を付けます。

以下の例ではIPアドレスが「192.168.2.2」または「192.168.2.3」の場合に404を返します。

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{REMOTE_ADDR} ^192\.168\.2\.2$ [OR]
   RewriteCond %{REMOTE_ADDR} ^192\.168\.2\.3$
   RewriteRule ^.*$ - [R=404,L]
</IfModule>

改行をなくすと「XXX OR YYY」のようになるので、最後の要素には付けないという感じです。

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{REMOTE_ADDR} ^192\.168\.2\..*$ [OR]
   RewriteCond %{REMOTE_ADDR} ^192\.168\.3\..*$ [OR]
   RewriteCond %{REMOTE_ADDR} ^192\.168\.4\..*$
   RewriteRule ^.*$ - [R=404,L]
</IfModule>

フラグと併用する場合は[]内にカンマ区切りで記述します。

例えば大文字・小文字を区別しない [NC] と併用する場合は [OR,NC] のように書きます。

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REMOTE_HOST} ^.*\.aaa\.jp$ [OR,NC]
RewriteCond %{REMOTE_HOST} ^.*\.bbb\.jp$ [OR,NC]
RewriteCond %{REMOTE_HOST} ^.*\.ccc\.jp$ [OR,NC]
RewriteCond %{REMOTE_HOST} ^.*\.ddd\.jp$
RewriteRule ^.*$ - [R=404,L]
</IfModule>

特定のIPやホスト「以外」は404を返す

404のエラーを返す場合はフラグで「R=404」を指定します。

<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteCond %{REMOTE_ADDR} !^192\.168\.2\.*$
   RewriteCond %{REMOTE_HOST} !^.*.ppp\.infoweb\.ne\.jp$
   RewriteRule ^.*$ - [R=404,L]
</IfModule>

[OR] が記述されていない場合はANDの条件になりますので、上記の例はIPアドレスが「192.168.2.」でなく、かつホスト名が「.ppp.infoweb.ne.jp」でもない場合に404のエラーを返します。

環境変数による振り分け

ちょっと長くなってしまったので条件の例だけ記載します。

例の末尾のほとんどに [NC] というフラグがついていますが、大文字・小文字を区別しないというフラグなので、区別する場合は外してください。

列挙していく場合、末尾に [OR] が無い場合は「AND」になる点に注意してください。
[NC] フラグと併用する場合は [OR,NC] のようにカンマ区切りで記述します。

ユーザーエージェントで振り分け

RewriteCond %{HTTP_USER_AGENT} ".*Android.*" [NC]

サーバーのホスト名で振り分け

RewriteCond %{HTTP_HOST} "^.*\.sakue\.com" [NC]

リファラで振り分け(直前のURL)

RewriteCond %{HTTP_REFERER} "^.*\.sakue\.com" [NC]

IPアドレスで振り分け

RewriteCond %{REMOTE_ADDR} "^192\.168\..*" [NC]

リモートホスト名で振り分け

RewriteCond %{REMOTE_HOST} "^.*\.sakue\.com" [NC]

リモートホストで振り分けする場合は httpd.conf で以下を有効にする必要があります。
エラーは出ないもののホスト名が取得できないので一致してくれません。

HostnameLookups On

ユーザー名で振り分け

RewriteCond %{REMOTE_USER} "^admin$" [NC]

リクエストメソッド(GET/POST)で振り分け

RewriteCond %{REQUEST_METHOD} "^(GET|POST)$" [NC]

日付で振り分け

環境変数の%{TIME_YEAR}に4桁の年が、%{TIME_MON}に2桁の月が、%{TIME_DAY}に2桁の日が格納されています。

2020/10/21以降

RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} ">20201021"

2020/10/21以前

RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} "<20201021"

2020/10/21と等しい

RewriteCond %{TIME_YEAR}%{TIME_MON}%{TIME_DAY} "=20201021"

時刻で振り分け

環境変数の%{TIME_HOUR}と%{TIME_MIN}に、それぞれ2桁の「時」と「分」が格納されていますので、それで判断します。

08時以前

RewriteCond %{TIME_HOUR}%{TIME_MIN} "<0800"

18時以降

RewriteCond %{TIME_HOUR}%{TIME_MIN} ">1800"

曜日で振り分け

曜日は「日曜日を0」とした数字が格納されていますので、それで判断します。

日曜

RewriteCond %{TIME_WDAY} "0"

月曜

RewriteCond %{TIME_WDAY} "1"

火曜

RewriteCond %{TIME_WDAY} "2"

水曜

RewriteCond %{TIME_WDAY} "3"

木曜

RewriteCond %{TIME_WDAY} "4"

金曜

RewriteCond %{TIME_WDAY} "5"

土曜

RewriteCond %{TIME_WDAY} "6"

平日

RewriteCond %{TIME_WDAY} ">0"
RewriteCond %{TIME_WDAY} "<6"

動作確認

Chromeのデベロッパーツール

「…」から、その他のツール > 「デベロッパーツール」に進みます。

「Network」タブを開きます。

「Preserve log」にチェックを入れます。

このチェックをONにすると、ページが移動(今回のリダイレクト)してもログがクリアされません。
逆にOFFの状態だとリダイレクトや更新ボタンなどの際に毎回ログがクリアされます。

テスト中にキャッシュを使わないように「Disable cache」にもチェックを入れておきます。

この状態でリダイレクト設定があるページを開いて確認します。

「Status」の列に注目してみると、302(一時的な移動)でリダイレクトされているのが確認できます。

Firefoxの開発者ツール

Firefoxの開発者ツールでリダイレクトを追うこともできます。

ツール > ウェブ開発 > 開発者ツールを表示

「ネットワーク」タブを開きます。

テスト中にキャッシュが使われないよう「キャッシュを無効化」にもチェックを入れてください。

そのままだとページが遷移するとログもクリアされてしまい、リダイレクトが追えないため、「永続ログ」にチェックを入れます。

ログがゴチャゴチャして邪魔な場合は左にある「ゴミ箱」アイコンをクリックするとログがクリアされます。

開発者ツールのネットワークタブを開いたまま、リダイレクトがあるページを開いてみます。

左端に「ステータス」という項目がありますが、3から始まるステータスコード(301や302など)が転送を意味するものです。

以下の例では302(一時的な移動)が返ってきているのが分かります。

番外:リバースプロキシ

ここで説明するリダイレクトとは関係ありませんが、似た動きをするリバースプロキシも簡単に説明しておきます。

リバースプロキシはWebサーバの前段に置いて、代理でコンテンツを取得してきて表示するような機能です。

apacheの例だと、以下のように設定した場合、「/cam1」へアクセスされた場合は「http://localhost:8081」の内容を表示します。

URLの書き換えが発生せず、あたかもそこにあるように振る舞うため、本来のサーバの隠蔽や負荷分散などにも使われます。

ProxyPass /cam1 http://localhost:8081
ProxyPassReverse /cam1 http://localhost:8081

設定自体は非常に簡単なので以下にメモしておきます。

プロキシモジュールを有効にする

最近のApacheでは /etc/httpd/conf.modules.d/ へ「LoadModule」行が分離されており、httpd.confで「Include conf.modules.d/*.conf」の行があれば全て読み込まれているので特に設定する必要はありません。

少し前のApacheでは以下の行を有効にします。

Linux版の場合

LoadModule proxy_module libexec/mod_proxy.so
LoadModule proxy_http_module libexec/mod_proxy_http.so

Windows版の場合

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

httpd.confへ追加

以下のような感じで記述します。

複数ある場合はProxyPass行をまとめて書き、その後にProxyPassReverse行をまとめて書きます。

ProxyPass /cam1 http://localhost:8081
ProxyPass /cam2 http://localhost:8082
ProxyPassReverse /cam1 http://localhost:8081
ProxyPassReverse /cam2 http://localhost:8082

以下のような順序で書くと、2番目に記述した「cam2」で403エラーが出てしまいます。

ProxyPass /cam1 http://localhost:8081
ProxyPassReverse /cam1 http://localhost:8081
ProxyPass /cam2 http://localhost:8082
ProxyPassReverse /cam2 http://localhost:8082

apache再起動

systemctl restart httpd

これで例えば「https://sakue.com/cam1」へアクセスすると、ローカルの8081ポートで待ち受けているサーバが応答してコンテンツを表示します。

コメントフォーム

タイトルとURLをコピーしました