How to deploy a static website with CloudFront and a private S3 bucket

How to deploy a static website with CloudFront and a private S3 bucket

In this article we shown how to deploy a static website with CloudFront by keeping the S3 bucket public and making use of S3 website endpoint. Here we will show how to do it with a private bucket.

1. Create S3 bucket

  • Go to S3
  • Click on Create bucket
  • Select Block all public access
  • Save

2. Create a CloudFront distribution

  • Go to CloudFront and create a new distribution
  • Select the origin domain to be the S3 bucket containing your static website and DO NOT click on Use website endpoint
  • Set origin access to Origin access control settings (OAC) and select your bucket
  • Leave all the other options as default and save

3. Update S3 policy

  • After saving, you will be shown a banner where you can copy the policy that you have to save in S3
  • Go to your S3 bucket, click on the Permissions tab, here you can find the bucket policy to edit
  • Paste the policy copied from Cloudfront, it should look like this:
    {
          "Version": "2008-10-17",
          "Id": "PolicyForCloudFrontPrivateContent",
          "Statement": [
              {
                  "Sid": "AllowCloudFrontServicePrincipal",
                  "Effect": "Allow",
                  "Principal": {
                      "Service": "cloudfront.amazonaws.com"
                  },
                  "Action": "s3:GetObject",
                  "Resource": "arn:aws:s3:::<bucket-name>/*",
                  "Condition": {
                      "StringEquals": {
                        "AWS:SourceArn": "arn:aws:cloudfront::<account-id>:distribution/<distribution-id>"
                      }
                  }
              }
          ]
        }
    
  • After saving, your website won’t be accessible from S3 directly, you will get a 403 Forbidden or Access Denied error since you’re enforcing the bucket to be accessible only by CloudFront
  • At this point you should be able to access the website through the CloudFront endpoint. You can find it in the distribution under General > Details > Distribution domain name. If you have an Access Denied error, double check in the Origins setting that the Origin is configured to use the S3 website endpoint, and not the S3 bucket
  • If you do any change to CloudFront config, notice that the content is cached, so you will probably not see any changes until the TTL expired. To speed up this process, you can create an Invalidation

4. Redirect routes to index.html

Since you’re not using the S3 static website feature, CloudFront will not redirect the routes to index.html automatically. For example, you might want to access the page contained in about/index.html by going on the URL www.your-site.com/about instead of www.your-site.com/about/index.html. In order to allow this, you will need to create a custom function

  • Go to CloudFront
  • On the left menu, click on Functions
  • Click on Create function
  • Choose a name for the function and click on Next
  • Copy the following code in the Build tab
    function handler(event) {
      var request = event.request;
      var uri = request.uri;
        
      if (uri.endsWith('/')) {
          request.uri += 'index.html';
      } else if (!uri.includes('.')) {
          request.uri += '/index.html';
      }
        
      return request;
    }
    
  • Go on the Publish tab and click on Publish Function
  • Click on Add association
  • Select your distribution and the cache behaviour, and set Event type to Viewer Request

After adding the association, create a Cache Invalidation and you will be able to access your website correctly after it’s completed

5. Use a custom domain

  • Go to Route53, click on Hosted zone and then click on the hosted zone of your domain
  • Click on Create record and apply the following configuration
  • Record type: A
  • Alias: On
  • Route traffic to: Alias to CloudFront distribution
  • Select your CloudFront distribution

Now create another record to redirect www to the same domain, with the following config:

  • Record type: A
  • Alias: On
  • Route traffic to: Alias to another record in this hosted zone
  • Select the record that you created in the previous step

6. Configure SSL

First thing, you need to create a SSL certificate:

  • Go to AWS Certificate Manager (ACM)
  • Click on Request certificate and configure it with the following:
  • Certificate type: Request a public certificate
  • Fully qualified domain name: your-website-domain.com
  • Click on Add another name to this certificate and set the other name as www.your-website-domain.com
  • Validation method: DNS Validation
  • Click on Request

Now you have to attach your certificate to CloudFront:

  • Go to your CloudFront distribution, click on General and then under the Settings section click on Edit
  • Apply the following config:
  • Alternate domain name (CNAME): add the domains specified in your ACM certificate
  • Custom SSL certificate: select your ACM certificate
  • Click on Save

To redirect traffic from HTTP to HTTPS:

  • Go to Behaviours. There should be only one behaviour here, select it and then click on Edit
  • Set Viewer protocol policy to Redirect HTTP to HTTPS
  • Click on Save

Conclusion

Congratulations, you have successfully created a website with a private S3 bucket and CloudFront! Thanks to CloudFront your user will experience much less latency, due to to the AWS edge locations, where the content will be cached.

Roberto
Roberto Founder and Author of Codevup