ちょっと話題の記事

Amazon CloudFrontとEC2(Nginx)で作る国・地域対応Webサイト構築

2014.11.04

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ども、大瀧です。
CloudFrontによるグローバル対応サイトの構築は、横田の以前のエントリーでRoute 53と組み合わせを紹介済みですが、Route 53のレイテンシーレコードはAWSのリージョンごとの区分けなので、「日本」向けや「台湾」向けなど特定の国や地域別にコンテンツを区別する用途には向いていません。
そこで今回は、7月にリリースされたCloudFrontのジオターゲティング機能を利用して、国・地域に対応するWebサイトを構築してみます。まずは構成図をどーんと。

cf-nginx01

CloudFrontのジオターゲティングは国・地域の地理データベースとクライアントの接続元IP照合するのですが、その結果をオリジンに転送するHTTPリクエストのヘッダに付与します。国・地域によってオリジンを振り分ける機能ではありませんので、CloudFrontのジオターゲティングによって付与されたHTTPヘッダを解釈するためのオリジンを置くところがポイントです。静的コンテンツであれば、オリジンをS3で済ませたいところですが、S3には現状ヘッダによってコンテンツを変える機能が無いため、CloudFront+S3では対応できません。今回はオリジンとして、EC2インスタンスでNginxを構成してみます。

1. CloudFrontの構成

まずは、CloudFrontのDestribution設定で地理データをヘッダに付与するように構成します。Distribution作成時の[Default Cache Behavior Settings]画面のForward HeadersWhitelistに変更します。

cf-nginx02

付与するヘッダ一覧からCloudFront-Viewer-Countryを選択し、[Add]をクリックして追加します。

cf-nginx03

これでOKです。実際のヘッダの動きについては、佐々木のブログ記事を参照ください。

2. Nginxの構成

続いて、オリジンとなるEC2インスタンスのNginxの構成です。今回は日本(JP)、台湾(TW)、中国(CN)向けのコンテンツを/jp/tw/cn以下で提供するようドキュメントルートにコンテンツを配置しました。

$ tree /usr/share/nginx/html/
/usr/share/nginx/html/
├── 404.html
├── 50x.html
├── cn
│   └── index.html
├── index.html
├── jp
│   └── index.html
└── tw
    └── index.html

そして、ドメイン宛(http://example.com/)にリクエストが来ると、HTTPヘッダを見て各国別コンテンツにリダイレクトさせる構成にしてみます。Nginxの構成ファイルnginx.conf内では、リクエストのHTTPヘッダを変数$http_<ヘッダ名のハイフンを_に置換したもの>で参照できます。今回CloudFrontが付与するヘッダはCloudFront-Viewer-Countryなので、$http_cloudfront_viewer_countryifディレクティブの条件にし、HTTP301でリダイレクトさせるrewriteディレクティブを定義しました。

  :
server {
	listen       80;
	server_name  example.com;
	root         /usr/share/nginx/html;
	  :
	location = / {
		if ( $http_cloudfront_viewer_country = JP )
		{ rewrite ^ http://example.com/jp/ permanent; }
		if ( $http_cloudfront_viewer_country = TW )
		{ rewrite ^ http://example.com/tw/ permanent; }
		if ( $http_cloudfront_viewer_country = CN )
		{ rewrite ^ http://example.com/cn/ permanent; }
	}
}
  :

では、Nginxを起動し、動作を確認してみます。

$ sudo service nginx start
Starting nginx:                                            [  OK  ]
$ curl -I http://localhost/
HTTP/1.1 200 OK
Server: nginx/1.0.15
Date: Sun, 02 Nov 2014 15:19:31 GMT
Content-Type: text/html
Content-Length: 3698
Last-Modified: Fri, 26 Apr 2013 20:36:51 GMT
Connection: keep-alive
Accept-Ranges: bytes
$ curl -I --header "CloudFront-Viewer-Country:JP" http://localhost/
HTTP/1.1 301 Moved Permanently
Server: nginx/1.0.15
Date: Sun, 02 Nov 2014 15:19:00 GMT
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Location: http://example.com/jp/
$

いい感じですね!EC2インスタンスをオリジンに設定したCloudFront経由のリクエストも、以下のように確認できます。

$ curl -I http://XXXXXXXXXXXXXX.cloudfront.net/
HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Content-Length: 185
Connection: keep-alive
Server: nginx/1.0.15
Date: Sun, 02 Nov 2014 15:26:03 GMT
Location: http://example.com/jp/
X-Cache: Miss from cloudfront
Via: 1.1 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.cloudfront.net (CloudFront)
X-Amz-Cf-Id: abTQJX3FDe5EVQmseuN4rNuzKzQCMdn0O96oedCeKcbnLtO6gV4iEQ==
$

応用編 S3 Static Website Hostingとの組み合わせ

静的Webサイトであれば、EC2インスタンスの負荷軽減と可用性を考慮してリダイレクト先をS3 Static Website Hostingでホストしても良いでしょう。CloudFrontのデフォルトオリジンをS3 Static Website Hostingのエンドポイントにし、ドメイン宛のアクセス(/)をEC2オリジンに指定することで実現できます。

cf-nginx05

運用編 キャッシュ期限の調整

運用にあたっては、CloudFrontでのコンテンツのキャッシュ期限の調整が必要です(CloudFrontでは、HTTP301リダイレクトも例外なくキャッシュ対象になります)。CloudFrontのキャッシュ期限は、基本的にはオリジンからのレスポンスに含まれるHTTPヘッダをCloudFrontが読み取って決定します(詳細は都元のエントリーを参照ください)。Nginxでは、expiresディレクティブでExpiresヘッダとCache-Controlヘッダをよしなに調整できます。

  :
server {
    listen       80;
    server_name  example.com;
    root         /usr/share/nginx/html;
    expires      10m;
}
  :

最適なキャッシュ期限は、オリジンへの負荷耐性とコンテンツの更新頻度でバランスさせることになります。また、キャッシュ率などの分析はCloudFrontのアクセス分析機能を利用すると良いでしょう。こちらのエントリーを参考にしてください。

まとめ

CloudFrontが付与するHTTPヘッダCloudFront-Viewer-CountryをNginxで条件分岐する、国・地域別Webサイト構築の構成を紹介しました。
コンテンツの配置や振り分け方で様々な組み合わせがあると思いますが、比較的シンプルに実現できる一例として参考になれば幸いです。