tanaka's Programming Memo

プログラミングについてのメモ。

さくらインターネットで.htaccessを使ったリダイレクト

さくらインターネットのスタンダードプランのレンタルサーバーで以下をやった時のメモです。

前提

この記事内容は、以下のような想定です。各所を自分の環境に置き換えて読んでください。

やりたいこと

ドメインの設定

さくらインターネットのサーバコントロールパネルのドメイン設定にて、以下を設定しておきます。

  • foo.sakura.ne.jpへのアクセスは、 /home/foo/www フォルダーに割り当て
  • foo.org へのアクセスは、 /home/foo/www/dokuji フォルダーに割り当て

www フォルダーの .htaccess

/home/foo/www/.htaccess を作成して、以下の内容にしました。

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /

    # http to https
    RewriteCond %{ENV:HTTPS} !^on$
    RewriteCond %{HTTP:X-Sakura-Forwarded-For} ^$
    RewriteRule .* https://foo.sakura.ne.jp%{REQUEST_URI} [R=301,L]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} ^/(.*)$
    RewriteRule .* https://foo.sakura.ne.jp/index.php/%1 [R,L]

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
</IfModule>

www/dokuji フォルダーの .htaccess

/home/foo/www/dokuji/.htaccess を作成して、以下の内容にしました。

<IfModule mod_rewrite.c>
    RewriteEngine On

    # Redirect root to wordpress
    RewriteCond %{REQUEST_URI} ^/$ [NC]
    RewriteRule .* http://%{SERVER_NAME}/wp [R=301,L]

    # Redirect HTTP App Access
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} ^/(.*)$
    RewriteRule .* https://foo.sakura.ne.jp/index.php/%1 [R=301,L]
</IfModule>

解説

各設定やRewriteの表記の意味についてです。

Rewriteルールの開始

まず冒頭の

<IfModule mod_rewrite.c>
    RewriteEngine On

によって、アクセスしてきたURLに対して、条件に合致する部分を書き換えを行う宣言をします。

RewriteRule

Rewriteの最重要コマンドです。パス指定に対して、最初のパラメーターに書き換えたい部分を表す正規表現を記載して、第2パラメーターで置き換えるパス表現を記載します。第3パラメーターは省略可で、書き換えた時の挙動やその後の処理を指定します。

RewriteCondやRewriteBaseは、このRewriteRuleを実行するかや、置き換えパスを省略するための付属の設定という位置付けです。

例えば

    RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]

と書いた場合、 ".*" は、あらゆる文字を0文字以上並べた文字列に一致する正規表現ですので、指定されたパスを全て次の第2パラメーターの文字列に書き換えることを表します。

第2パラメーターは、[https://]で開始して、%{SERVER_NAME}は環境変数で、指定されたパスのうちのドメイン名を得られます。%{REQUEST_URI}も環境変数で、"/"から始めたパスの部分が得られます。これにより、 http://foo.sakura.ne.jp/login などにアクセスがあった場合、以下のように書き換えられます。

https://foo.sakura.ne.jp/login

第3パラメーターは[]で囲まれた部分で、R=301は、ブラウザーのアドレスバーを書き換えた上で、恒久的なリダイレクトであることを表します。

Lは、このルールを適用したら、その後の.htaccessは無視する指定です。

後方参照

以下のようなルールの解釈です。

    RewriteRule ^(.*)/$ /$1 [L,R=301]

ルール内に()で囲まれた箇所があります。これは、その部分を後で参照できるようにするもので、書いた順に$1、$2、$3のように置換文字列の場所に記載できます。上記の例では()は1つだけなので、$1だけが利用できます。

上記は、最後が"/"で終わるパスだった場合、最後の"/"は削除するルールです。Laravelでルートを作成する際に、/で終わることを考慮しなくて済むようにする設定です。

- フラグ
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

というルールは、全てのパスに対して、URLエンコードを行う指定です。認可関連のアクセスについて、Laravelが自動生成したルールです。

RewriteBase

冒頭にある RewriteBase は、RewriteRuleの第2パラメーターの置き換えパスを相対パスで表記した時に、自動的に追加するパスを設定するものです。置き換えパスに相対パスを使わない場合は設定不要です。

RewriteCond

RewriteRuleは単体で使うこともできますが、その場合は条件に一致したパスは無条件で置き換えることになります。RewriteRuleの前にRewriteCondを使って、ルールを適用するかどうかの条件をつけることができます。

RewriteCondの第1パラメーターは、判定するデータです。第2パラメーターは、フラグや正規表現で、第1パラメーターに対するチェック内容を記載します。第3パラメーターは省略可能なフラグです。

RewriteCondは、直下のRewriteRule1つに適用されます。RewriteRule1行ごとに、必要なRewriteCondを記載します。

RewriteCondを複数並べた場合、第3パラメーターに[OR]を指定しなければ、並べた全ての条件が成立している必要があります(AND)。[OR]が指定されているRewriteCondは、それが成立していればRewriteRuleを実行します。

    RewriteCond %{ENV:HTTPS} !^on$
    RewriteCond %{HTTP:X-Sakura-Forwarded-For} ^$
    RewriteRule .* https://foo.sakura.ne.jp%{REQUEST_URI} [R=301,L]

上記がルール1つ分です。まずは、環境変数の%{ENV:HTTPS}が、"on"以外のものであることを確認しています。この環境変数には、httpsアクセスだった場合、"on"が入ります。ただし、さくらインターネットではこのパラメーターが効かない状況があるため、次のフラグを追加しています。

%{HTTP:X-Sakura-Forwarded-For}環境変数は、さくらインターネットの独自環境変数で、httpアクセスだった場合にIPアドレスが入ります。上記のテストでは"^$"となっています。これは1文字もないことを表す正規表現です。つまり、IPアドレスが入っていないので、httpアクセスではない(つまり、httpsである)ことを確認しています。

上記の2つのいずれも成立している時、httpアクセスなので、httpsアクセスに書き換えています。さくらインターネットでは共有SSLを使ったアクセスの場合、初期ドメインにアクセスすることが推奨されていますので、%{SERVER_NAME}ではなく、直接初期ドメインを書きました。

RewriteCondの後方参照

RewriteRuleと同様に、RewriteCondでも後方参照が使えます。指定の方法は同じで、指定箇所を()で囲みます。RewriteRuleで利用する場合は、%1などで指定します。

例えば、 http://foo.org/login などへのアクセスを、 https://foo.sakura.ne.jp/input.php/login に置き換えたい場合は以下のようにします。

    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_URI} ^/(.*)$
    RewriteRule .* https://foo.sakura.ne.jp/index.php/%1 [R,L]

冒頭の2つの条件は、"!-d"でディレクトリーではないことを表し、 "!-f"でファイルでないことを表しています。つまり、存在しないURIへのアクセスを表しています。

3つ目の条件は、パス部分が "/???" という形式であることを条件にしています。最後の"(.*)"の部分が後方参照で利用できます。

書き換えルールは、 https://foo.sakura.ne.jp/index.php/%1 の形に置き換えることを表して、やりたいことを実現しています。

まとめ

一番はまったのは、.htaccessを書き換えても、ブラウザーなどに履歴が残っていると反映されないことでした。キャッシュをしない設定にしておくとか、ブラウザーを閉じてから再度アクセスするなどして確認してください。

さくらインターネットhttps判断は今の所以下で動いています。下の行だけでも動く感じでしたが、念のため2つ描いてあります。さくらの独自環境変数はいつ変更になるかわからないので注意が必要とのこと。また、最終的にはちゃんとSSLを取得して、独自ドメインに設定するべきかとは思います。

    RewriteCond %{ENV:HTTPS} !^on$
    RewriteCond %{HTTP:X-Sakura-Forwarded-For} ^$