Webサイト移転に役立つS3+CloudFrontでのリダイレクト設定まとめ

こんにちは。[CYBIRDエンジニア Advent Calendar](http://qiita.com/advent-calendar/2016/cybird) 7日目の[gucchon](http://qiita.com/gucchon)です。新卒4年目、webエンジニアです。

6日目は[megadreams14](http://qiita.com/megadreams14)さんの[iOS/AndroidのWebViewを活用したSPA(SinglePageApplication)でのゲーム開発](http://qiita.com/megadreams14/items/2ee06e8797da3d90ff82)でした。megadreams14さんのプロジェクトとは違いますが、この1年は私もハイブリッドアプリの新規開発をしていて、megadreams14さんから共有していただいた知見には何度も助けていただきました。しかしそれ故に、私が書こうかなと思ってた内容をmegadreams14さんが見事に書ききってしまったので、それとは全然関係のない、最近ちょっとハマってしまったことでも書いておこうかと思います。

## 本日の内容
みんな大好き、AWS S3での静的Webサイトホスティング。CYBIRDで運用しているいくつかのサイトも利用させていただいておりますが、先日とあるシリーズもののコンテンツの各公式サイトを、ひとつのサイトにまとめたい...ということで移転作業を行いました。当初はリダイレクトさせればすぐ終わるでしょと思っていたのですが、そのリダイレクトに意外と手こずってしまったので、今回は旧サイトを新サイトへ移転する際のリダイレクト設定の手順を、注意点を交えてまとめておこうと思います。

##移転の要件
* ```https://old.jp/``` 配下のページを ```http://new.jp/xxx/``` 配下に移す
* ```https://old.jp``` はS3+CloudFront(Redirect HTTP to HTTPS設定)で運用中
* ```http://new.jp``` はS3(HTTPのみ)で運用中
* ```https://old.jp/``` 配下のページへのアクセスは ```http://new.jp/xxx/index.html``` にリダイレクトさせたいが、一部のページは指定したページへリダイレクトさせたい

## S3でのリダイレクトについて
まずはS3の設定変更から。
S3で別のホスト名にリダイレクトする方法は2つあります。

バケットの「プロパティ」>「静的ウェブサイトホスティング」から、

1. 「ウェブサイトのホスティングを有効にする」にて、リダイレクトルールを設定する
2. 「別のホスト名にすべてのリクエストをリダイレクトする」で全てのリクエストを別ドメインにリダイレクトする

という方法です。

サイトのファイル構成が変わらなければ、2の方法が手っ取り早いです。
![advent_calendar_2016_1.png](https://qiita-image-store.s3.amazonaws.com/0/60647/5dc08b9c-b5a6-97c9-11d7-e483e8f03bbc.png)
これで終わり。
```old.jp/index.html``` は ```new.jp/xxx/index.html``` にリダイレクトされるし、```old.jp/aaa/bbb/ccc.html``` は ```new.jp/xxx/aaa/bbb/ccc.html``` にリダイレクトされます。

ただ、今回の場合は、基本的には ```new.jp/xxx/index.html``` にリダイレクトして、一部のページのみ、指定ページへリダイレクトさせたいという話だったので、1の方法を採用し、リダイレクトルールを設定していきます。

## リダイレクトルールの設定
まず、旧サイトの特定ページへのアクセスを、新サイトの特定ページへリダイレクトさせる設定です。
```old.jp/aaa.html``` を ```new.jp/xxx/bbb.html``` へリダイレクトさせる場合は、こんな感じです。

```
<RoutingRules>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>aaa.html</KeyPrefixEquals>
        </Condition>
        <Redirect>
            <HostName>new.jp</HostName>
            <ReplaceKeyWith>xxx/bbb.html</ReplaceKeyWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>
```

例では、htmlページを指定していますが、ディレクトリ名の変換などの場合は、```<ReplaceKeyPrefixWith>```を使用します。

続いて、その他の全リクエストを、新サイトの特定の1ページへリダイレクトさせる場合の設定です。
ここでひとつ躓いたのですが、どうやらリダイレクト条件を指定する```KeyPrefixEquals```には正規表現やワイルドカードが使用できないようです。そのため、ドメイン直下のディレクトリやページを列挙しないといけないという...

なので私の場合は、リダイレクト条件を```<HttpErrorCodeReturnedEquals>```要素を使ったステータスコードによる指定にしました。バケットの中身を空にして、どんなリクエストがきても404エラーを発生させ、リダイレクト条件に合致させる作戦です。

移転作業をする際、運用中のサイトを空にする勇気と覚悟が必要でしたが、まぁ移転するのだし、どうせいずれ消さねばなりません。

ということで、前述のリダイレクトルールと合わせて、最終的にはこんな感じになりました。

```
<RoutingRules>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>aaa.html</KeyPrefixEquals>
        </Condition>
        <Redirect>
            <HostName>new.jp</HostName>
            <ReplaceKeyWith>xxx/bbb.html</ReplaceKeyWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <HostName>new.jp</HostName>
            <ReplaceKeyWith>xxx/index.html</ReplaceKeyWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>
```

リダイレクトルールは上から順番に判定されていくようです。そのため、ルールを逆にしてしまうと、 ```old.jp/aaa.html``` も ```new.jp/xxx/index.html``` にリダイレクトされてしまうので、注意が必要です。

ルーティングルールの構文などについて、詳しくは公式ドキュメントをどうぞ。
参考: [ルーティングルールを指定するための構文](http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/HowDoIWebsiteConfiguration.html#configure-bucket-as-website-routing-rule-syntax)

## HTTPSのリダイレクト
旧サイトへのアクセスがHTTPのみだった場合は、ここまでの設定で問題ないでしょう。しかし、元々CloudFrontを使用していて、HTTPSでアクセスしていた場合は、CloudFront側の設定を確認する必要があります。

確認するのはCloudFrontのOrigin Domain Nameの項です。この設定が、S3のエンドポイントを指定していないとリダイレクト設定が有効にならないようです。

#### Origin Domain Name指定
* リダイレクト設定が無効:  ```old.jp.s3.amazonaws.com```
* リダイレクト設定が有効:  ```old.jp.s3-website-ap-northeast-1.amazonaws.com```

この項目を設定しようとした際、S3バケットがあれば選択候補として出してくれますが、あれをポチッと選ぶとリダイレクトができない罠が存在します。

## リダイレクトが上手くできているか確認
最後に意図した通りリダイレクトされているかを確認する方法についてです。

まずはキャッシュの対策をしないと、何かとキャッシュが邪魔をします。
キャッシュ対策として私が行ったのは以下のようなものです。

#### キャッシュ対策
* 移転完了までCloudFrontのCache BehaviorはTTLを0にしておく
* 確認はブラウザのシークレットモードを使う
* クエリストリングをつけてみる

リダイレクトが正しく動作しているかはChromeの拡張機能で確認しました。
[Redirect Path](https://chrome.google.com/webstore/detail/redirect-path/aomidfkchockcldhbkggjokdkkebmdll?hl=ja)という拡張機能があったので使ってみましたが、非常にわかりやすくて便利でした。
これを追加して、シークレットウインドウでも使えるように```chrome://extensions/```で「シークレットウインドウでの実行を許可する」にチェックを入れておきましょう。
リダイレクトの経路が確認できるので、意図した通りに正しく301リダイレクトが実行されていれば成功です。


## 最後に
S3+CloudFrontでのリダイレクトについてまとめました。若干ハマりポイントがあったり、キャッシュのせいなのか普通に失敗してるのかわからん...みたいなことで無駄に時間がかかったりするとつらいですが、サーバなど用意しなくとも細かく設定できるのは嬉しいですね。サイト移転の場合は、旧サイトのSEO資産も引き継ぎたいので、301リダイレクトは適切に設定したい所です。

さて、明日の[CYBIRDエンジニア Advent Calendar](http://qiita.com/advent-calendar/2016/cybird) 8日目、担当は私の大先輩の[daisuke-senmyou](http://qiita.com/daisuke-senmyou)さんです。Advent Calendar 3年目にして初登場！期待が高まりますね。必見です。