AWSでサブドメインなし（wwwなし）からサブドメインあり（wwwあり）へのリダイレクト設定

※本記事は[社内ブログ](https://www.sink-capital.com/blogs/domain_redirect)の内容を一部変えて転記しています。
## 背景
AWSのS3 + cloudfrontでwebサイトを公開する際に
wwwありのURL（[https://www.sink-capital.com/](https://www.sink-capital.com/)）で公開を行ったのですが、
サブドメインなしのURL（[https://sink-capital.com/](https://sink-capital.com/)）だと繋がらないことに気付いたため修正を行いました。


## 一般的な方法
基本的には
[Amazon Route 53 を使って、サブドメイン(www)なしから、ありドメインへリダイレクト](https://www.superbusinessman.biz/redirecting-domain-using-route53/)
に記載のある方法で、
サブドメインなしのURLから来たリクエストを、
全てサブドメインありのURLにリダイレクトすることを目指しました。

1. サブドメインなしのURLからリクエストが来る
2. route53のAレコードaliasでS3にリクエストを飛ばす
3. S3の設定でサブドメインありのURLにリダイレクト

ただし上記の対応だとhttpsに対応できないという問題点がありました。
（route53とS3だと証明書を入れ込むことができないため）

## 今回の対応方法
webサイト自体の公開方法と同様にcloudfrontを利用してS3に接続を行いました。

1. サブドメインなしのURLからリクエストが来る
2. route53のAレコードaliasでcloudfrontにリクエストを飛ばす
3. cloudfrontからS3にリクエストを流す
4. S3の設定でサブドメインありのURLにリダイレクト

## 実際のコード（terraform）
### cloudfront.tf
```json
resource "aws_cloudfront_distribution" "sci_website" {
  enabled = true
  aliases = [
    "${var.root_domain_name}"]
  comment = "${terraform.workspace}-www-root-alias"
  default_root_object = "index.html"
  price_class = "PriceClass_All"

  origin {
    domain_name = "${var.root_domain_name}.s3-website-${var.region}.amazonaws.com"
    origin_id = "S3-${aws_s3_bucket.sci_www_root_alias_bucket.bucket}"

    custom_origin_config {
      http_port = 80
      https_port = 443
      origin_protocol_policy = "http-only"
      origin_ssl_protocols = [
        "TLSv1"]
    }
  }

  default_cache_behavior {
    allowed_methods = [
      "GET",
      "HEAD"]
    cached_methods = [
      "GET",
      "HEAD"]
    target_origin_id = "S3-${aws_s3_bucket.sci_www_root_alias_bucket.bucket}"

    forwarded_values {
      query_string = true
      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "https-only"
    min_ttl = 3600
    default_ttl = 10800
    max_ttl = 86400
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    acm_certificate_arn = "${aws_acm_certificate.sci_com.arn}"
    ssl_support_method = "sni-only"
    minimum_protocol_version = "TLSv1"
  }
}
```

### route53.tf
```json
resource "aws_route53_record" "root" {
  zone_id = "${var.route53_zone_id}"
  name = "${var.root_domain_name}"
  type = "A"

  alias {
    name = "${aws_cloudfront_distribution.sci_website.domain_name}"
    zone_id = "${aws_cloudfront_distribution.sci_website.hosted_zone_id}"
    evaluate_target_health = true
  }
}

resource "aws_route53_record" "cert_validation" {
  zone_id = "${var.route53_zone_id}"
  name = "${aws_acm_certificate.sci_com.domain_validation_options.0.resource_record_name}"
  type = "${aws_acm_certificate.sci_com.domain_validation_options.0.resource_record_type}"
  ttl = 60
  allow_overwrite = true
  records = [
    "${aws_acm_certificate.sci_com.domain_validation_options.0.resource_record_value}"]
}

resource "aws_acm_certificate" "sci_com" {
  provider = "aws.ue1"
  domain_name = "${var.root_domain_name}"
  subject_alternative_names = []
  validation_method = "DNS"
}

resource "aws_acm_certificate_validation" "sci_com_validation" {
  provider = "aws.ue1"
  certificate_arn = "${aws_acm_certificate.sci_com.arn}"
  validation_record_fqdns = [
    "${aws_route53_record.cert_validation.0.fqdn}"]
}
```

### s3.tf
```json
resource "aws_s3_bucket" "sci_www_root_alias_bucket" {
  bucket = "${var.root_domain_name}"
  acl = "private"

  website {
    redirect_all_requests_to = "https://www.${var.root_domain_name}"
  }
}
```

### variable.tf
※ドメイン名はお好きに

```json
variable "route53_zone_id" {}
variable "root_domain_name" {
  default = "sink-capital.com"
}
variable "region" {
  default = "ap-northeast-1"
}
```

## 感想
terraform中に出てくる細かい設定がいくつかあり、
一つでも間違えると繋がらなかったりするので意外と大変でした。
特にキャッシュが残るせいで繋がったり繋がらなかったり。。。
ただterraformでかけたので心理的安全性はかなり高くなります。

## 参照リンク

- https://www.superbusinessman.biz/redirecting-domain-using-route53/
- http://notes.webutvikling.org/s3-bucket-cloudfront-using-terraform/