CPIのレンタルサーバーで.htaccessにリダイレクトを書いたのに、まったく効かない。私も最初は「書き方が間違っているのか」と何度も見直しましたが、原因はコードではなくmod_rewriteが有効になっていないことでした。
CPIは初期状態だと.htaccessでのURL書き換えがオフになっていて、ひと手間加えないと動きません。この記事では、その有効化のやり方と、www有無の統一・ページ単位の転送・http→httpsリダイレクトを、CPI環境で実際に動く形で紹介します。
関連記事:GMOのiCLUSTAで.htaccessにhttpsリダイレクトを設定しても動かない時の解決方法
まず.htaccessの先頭でmod_rewriteを有効にする
CPIで.htaccessによるリダイレクトを使うには、ファイルの先頭に次の2行を書いておく必要があります。ここが抜けていると、以降のリダイレクトはすべて素通りしてしまいます。
Options +SymLinksIfOwnerMatch
RewriteEngine On
Options +SymLinksIfOwnerMatch はシンボリックリンクの追跡を許可する指定で、CPIではこれがないとmod_rewriteが正しく動きません。頭の「+」を落とさないよう注意してください。RewriteEngine On で書き換えエンジンそのものを有効化します。この2行はCPI公式マニュアルでも必須として案内されています。
用途で分ける2つの書き方(mod_rewrite と mod_alias)
リダイレクトには大きく2系統あります。条件を付けて柔軟に書き換えたいなら RewriteCond / RewriteRule(mod_rewrite)、単純に「このパスをあのURLへ」で足りるなら Redirect / RedirectMatch(mod_alias)です。両方を同じ.htaccessに混在させると挙動が読みにくくなるので、どちらかに寄せるのがおすすめです。
www有無を統一する(RewriteRule)
wwwなしでアクセスされたらwwwありに揃える、という正規化はmod_rewriteが向いています。
Options +SymLinksIfOwnerMatch
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.jp$
RewriteRule (.*) https://www.example.jp/$1 [R=301,L]
RewriteCond でホスト名が example.jp(wwwなし)のときだけ、RewriteRule で www.example.jp へ転送します。[R=301,L] の R=301 は「恒久的な移動」を意味し、検索エンジンに旧URLの評価を引き継がせたいときに使います。一時的な転送なら R=302 です。L はここで処理を打ち切る指定です。
ページ単位で転送する(Redirect / RedirectMatch)
1ページだけ別URLへ飛ばしたいだけなら、条件式のいらないmod_aliasが簡潔です。
Redirect permanent /old/hoge.html https://www.example.jp/new/hoge/
Redirect permanent は301と同じ扱いです。パスの一部を正規表現で受けて置き換えたいときは RedirectMatch を使います。
RedirectMatch permanent ^/old/(.*)\.html$ https://www.example.jp/new/$1/
なお Redirect の第2引数は「サーバー上のパス」、第3引数は「転送先の完全なURL」です。ここを取り違えるとループや404の原因になります。
http→httpsへのリダイレクト(CPI特有の注意)
常時SSL化でつまずきやすいのがこの部分です。独自SSLでサーバー自身がSSLを終端している場合は、次の基本形が使えます。
Options +SymLinksIfOwnerMatch
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.example.jp/$1 [R=301,L]
%{HTTPS} off は「暗号化されていない通信のときだけ」という条件で、httpでのアクセスをhttpsへ振り向けます。CPIの公式ナレッジでもこの形が示されています。
ただし注意したいのは、%{HTTPS} はサーバー自身がSSLを処理しているときにしか on になりません。共有SSLやCDN・ロードバランサーを前段に挟む構成では、サーバーには常にhttpで届くため %{HTTPS} がずっと off のままになり、リダイレクトが無限ループします。その場合は、前段が付与する X-Forwarded-Proto ヘッダーで判定します。
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^(.*)$ https://www.example.jp/$1 [R=301,L]
あるいは接続ポートで判定する方法もあり、CPIのマニュアルでは %{SERVER_PORT} !^443$ を使う例も案内されています。環境によってどれが効くかが変わるので、ループや500エラーが出たら判定条件を切り替えて試すのが早いです。
動かないときに見直すポイント
- 先頭の
Options +SymLinksIfOwnerMatchとRewriteEngine Onが入っているか(CPIで最も多い抜け)。 - https化のループは
%{HTTPS}ではなくX-Forwarded-Protoやポート番号で判定すべき環境ではないか。 Redirect(mod_alias)とRewriteRule(mod_rewrite)を混在させて競合していないか。- ブラウザが301をキャッシュしている可能性があるため、確認はシークレットウィンドウで行う。
判断に迷う設定はCPIのサポートマニュアルにも記述例があるので、あわせて確認すると確実です。
まとめ:コピペで動く最小構成
CPIでリダイレクトが効かないほとんどの原因は、先頭2行の書き忘れです。最後に、mod_rewriteの有効化からwww統一・https化までをまとめた最小構成を置いておきます。ドメイン部分を自分のものに置き換えれば、そのまま動きます。
Options +SymLinksIfOwnerMatch
RewriteEngine On
# http でのアクセスを https へ(独自SSLの場合)
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.example.jp/$1 [R=301,L]
# www なしを www ありへ統一
RewriteCond %{HTTP_HOST} ^example\.jp$
RewriteRule (.*) https://www.example.jp/$1 [R=301,L]
これで直らない場合は、SSLの終端位置(独自SSLか共有SSLか)を疑い、判定条件を X-Forwarded-Proto に切り替えてみてください。私はこの切り替えでループが止まりました。