モチベーション
サイトを公開する場合、 www.example.com
と example.com
の両方でアクセス可能とすることがある (いわゆる、wwwのあり・なし設定)。 ただし、両方のFQDNが有効な場合であっても、SEO効果などの理由から、サーバー側でリダイレクトを行い、1つのFQDNを正としてサイトを運営する方が良い。
これを nginx で「wwwありに寄せる」書く場合は以下のように書く。 なお、現時点でサイトを運営するならば https にすべきだとは思うが、単なる例なのでここでは触れないこととする。
# www ありに寄せる例
server {
listen 80;
server_name www.example.com;
# 以下サイトの設定を記述
}
server {
listen 80;
server_name example.com;
location / {
return 301 http://www.example.com$request_uri;
}
}
これと同様のことを CloudFront で行う方法の1つとして、Lambda@Edge を利用した方法を紹介する。
追加モチベーション
これが必要なもう一つの理由としては CloudFront -> API Gateway -> Lambda
という構成を採っているのだが、デフォルト設定のままだと Lambda でアクセスしてきたホストを取得できないという問題がある。 そのため、ホスト毎に処理を切り替えたい場合に困ってしまった。
そこで、今回は上記のように、そもそもどちらか一方のみを正とすることで、Lambdaで利用するホスト名を固定値で参照可能とした。
なお Lambda@Edge を使えば上記の構成でも Lambda にホスト名を渡すことはできる。 具体的には以下の記事を参照。
Lambda@Edge でのリダイレクト
どうすればリダイレクトできるかの具体例は公式ページに書いてある。
今回は同じCloudFront ディストリビューションで www.example.com
と example.com
の両方を受け付け、www.example.com
以外 を www.example.com
にリダイレクトする例 (先述の nginx と同じ例) を示す。 nginxと異なり、こちらではディストリビューションで "http -> https リダイレクト" 設定が行われているものとする。
#!/usr/bin/python
# -*- coding: utf-8 -*-
REDIRECT_HOST = 'www.example.com'
def lambda_handler(event, context):
request = event['Records'][0]['cf']['request']
headers = request['headers']
if headers['host'][0]['value'] == REDIRECT_HOST:
# ホスト名が指定したものであればリダイレクトしない
return request
uri = request['uri']
redirect_response = {
'status': '301',
'statusDescription': 'Moved Permanently',
'headers': {
'location': [{
'key': 'Location',
'value': f'https://{REDIRECT_HOST}{uri}'
}]
}
}
return redirect_response
これをビュワーリクエストに設定すればよい。 Lambda@Edge の設定方法は 前のベーシック認証を設定する記事 を参照のこと。
別解
今回は1つの CloudFront ディストリビューションで複数の FQDN が有効になっている場合の対処を示した。 一方、1つのFQDNごとに1つのディストリビューションを用意できるのであれば、用意したディストリビューションへの通信の全てをリダイレクトする設定を書けば対処可能である。
具体的には、「Cloudfront ディストリビューションを Web Hosting してリダイレクトルールを記載した S3 バケットに流してリダイレクトさせる」「空のS3に流すが、Lambda@Edgeをビュワーリクエストに記載してここで固定のリダイレクトを行う」などである。