Published on

Hosting static website with AWS Cloudfront

Authors
  • foto
    Name
    Krzysztof Olszewski
    Twitter

How to host a static website with AWS services

I would like to show you step by step, how to use AWS services, to create website installation with automated manner.

diagram/diagrams_image.png

https://github.com/deltacodepl/aws-cloudfront-acme-ovh

I'm using OVH as domain registar, so we have to configure ovh provider for Terraform. To get API login required keys, we have to specify, which part of the API we will be using, in our case its domain/* path. For better security we can restrict access to our API, to specific IP's.

AWS Certificate Manager

Project we want to host should be available under subdomain, so we put neccessary variables into work: domain_name = "example.com" & cert_domain_name = "promo.example.com" and generate certifiacate using ACM.

It's important to know, that w can create our certs only within us-east-1 AZ

resource "aws_acm_certificate" "website-cert" {
  domain_name       = var.domain_name
  subject_alternative_names = [ var.cert_domain_name]
  validation_method = "DNS"
  lifecycle {
    create_before_destroy = true
  }
}

Because we have more than one domain, we have to create validation records in ovh service.

resource "ovh_domain_zone_record" "ovh_acm_record" {
    for_each = {
      for dvo in aws_acm_certificate.website-cert.domain_validation_options : dvo.domain_name => {
        # name = trim(dvo.resource_record_name, ".")
        name = dvo.resource_record_name
        record = dvo.resource_record_value
        type = dvo.resource_record_type
      }
    }

    zone      = var.domain_name
    # name of the record
    subdomain = each.value.name
    fieldtype = each.value.type
    ttl       = "60"
    # value of the record
    target    = each.value.record
}

So we are using DNS validation method, and Terraform create for us two neccessary records, which can be seen at OVH web cloud settings panel.

Cloudfront

Our S3 bucket will be private, and only our cloudfront distrbution intstance will have access to it, in oposite to basic public accessible website buckets.

To setup this functionality we have to use Origin Access Identity:

resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
    comment = "access-identity-${var.cert_domain_name}"
}

and we can define our cloudfront s3_distribution:

resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {

    # Origin domain
    # domain_name = aws_s3_bucket.s3_front_website_bucket.bucket_regional_domain_name
    # FIXME: terraform return same result as for bucket_domain_name
    domain_name = "${var.cert_domain_name}.s3.us-east-1.amazonaws.com"
    origin_id   = var.cert_domain_name

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path
    }
  }

  # for CNAME setting
  aliases = [var.cert_domain_name]

  enabled             = true
  is_ipv6_enabled     = true
  comment             = var.cert_domain_name
  default_root_object = "index.html"
  ...

as you can see, there is an unsolved problem with Terraform behaviour, that wont let us configure properly domain name, so wh have to hardcode it domain_name = "${var.cert_domain_name}.s3.us-east-1.amazonaws.com".

Finishing

After running our playbook we can access website under generated by AWS *.cloudfront.net domain name. We can simple create CNAME record in ovh dns zone settings and get fully working static website with ovh hosted custom domain.