How do I use CloudFront to serve a static website hosted on Amazon S3?

Last updated: 2020-10-06

I want to host a static website on an Amazon Simple Storage Service (Amazon S3) bucket. Then, I want to serve my website through an Amazon CloudFront distribution. How can I do that?

Short description

To serve a static website hosted on Amazon S3, you can deploy a CloudFront distribution using one of these configurations:

  • Using a REST API endpoint as the origin, with access restricted by an origin access identity (OAI)
  • Using a website endpoint as the origin, with anonymous (public) access allowed
  • Using a website endpoint as the origin, with access restricted by a Referer header
  • Using AWS CloudFormation to deploy a REST API endpoint as the origin, with access restricted by an OAI and a custom domain pointing to CloudFront

For more information on the two endpoint types, see Key differences between a website endpoint and a REST API endpoint.

Resolution

Follow the steps to configure a CloudFront distribution with the S3 endpoint type that you want to use as the origin:

Using a REST API endpoint as the origin, with access restricted by an OAI

  1. Use the Amazon S3 console to create a bucket and to upload your website files.
    Note: You don't need to enable static website hosting on your bucket for this configuration. This configuration uses the REST API endpoint of the bucket, instead of the website endpoint from the static website hosting feature. 
  2. Create a CloudFront web distribution. In addition to the distribution settings that you need for your use case, enter the following:
    For Origin Domain Name, select the bucket that you created.
    For Restrict Bucket Access, select Yes.
    For Origin Access Identity, select Create a New Identity.
    For Comment, you can choose to keep the default value. Or, you can enter a custom label for the OAI.
    For Grant Read Permissions on Bucket, select Yes, Update Bucket Policy.
  3. If you don't want to use SSL (HTTPS) for your website, proceed to the next step. To use SSL for your website, for SSL Certificate, you can select the Default CloudFront Certificate or a Custom SSL Certificate. Or, you can choose Request or Import a Certificate with ACM to request a new certificate.
    Important: If you entered Alternate domain names (CNAMEs) for your distribution, the CNAMEs must match the SSL certificate that you select. To troubleshoot issues with your SSL certificate, see How can I troubleshoot issues with using a custom SSL certificate for my CloudFront distribution?
  4. Choose Create Distribution.
  5. Update the DNS records for your domain to point your website's CNAME to your CloudFront distribution's domain name. You can find your distribution's domain name in the CloudFront console in a format that's similar to d1234abcd.cloudfront.net.
  6. Wait for your DNS changes to propagate and for the previous DNS entries to expire.
    Note: The time it takes for the previous DNS values to expire depends on the TTL value that's set at your hosted zone, and whether your local resolver uses those TTL values. 

Using a website endpoint as the origin, with anonymous (public) access allowed

Note: This configuration allows public read access on your website's bucket. For more information, see Setting permissions for website access.

  1. Use the Amazon S3 console to create a bucket and to enable static website hosting on the bucket.
  2. From the Static website hosting dialog box, copy the Endpoint of your bucket without the leading http://. The format is similar to AWSDOC-EXAMPLE-BUCKET.s3-website-region.amazonaws.com. You need the endpoint in this format for a later step.
  3. Add a bucket policy that allows public read access to the bucket that you created.
  4. Create a CloudFront web distribution. In addition to the distribution settings that you need for your use case, enter the following:
    For Origin Domain Name, enter the endpoint that you copied in step 2.
  5. If you don't want to use SSL (HTTPS) for your website, proceed to the next step. To use SSL for your website, for SSL Certificate, you can select the Default CloudFront Certificate or a Custom SSL Certificate. Or, you can choose Request or Import a Certificate with ACM to request a new certificate.
    Important: If you entered Alternate domain names (CNAMEs) for your distribution, the CNAMEs must match the SSL certificate that you select. To troubleshoot issues with your SSL certificate, see How can I troubleshoot issues with using a custom SSL certificate for my CloudFront distribution?
  6. Choose Create Distribution.
  7. Update the DNS records for your domain to point your website's CNAME to your CloudFront distribution's domain name. You can find your distribution's domain name in the CloudFront console in a format that's similar to d1234abcd.cloudfront.net.
  8. Wait for your DNS changes to propagate and for the previous DNS entries to expire.
    Note: The time it takes for the previous DNS values to expire depends on the TTL value that's set at your hosted zone, and whether your local resolver uses those TTL values. 

Using a website endpoint as the origin, with access restricted by a Referer header

Note: This configuration restricts access by setting up a custom Referer header on the distribution, and then using a bucket policy to allow access only for requests with the custom Referer header. Be sure to evaluate whether the access allowed by this setup meets the requirements of your use case.

  1. Use the Amazon S3 console to create a bucket and to enable static website hosting on the bucket.
  2. From the Static website hosting dialog box, copy the Endpoint of your bucket without the leading http://. The format is similar to AWSDOC-EXAMPLE-BUCKET.s3-website-region.amazonaws.com. You need the endpoint in this format for a later step.
  3. Create a CloudFront web distribution. In addition to the distribution settings that you need for your use case, enter the following:
    For Origin Domain Name, enter the endpoint that you copied in step 2.
    For Origin Custom Headers, under Header Name, enter Referer. Under Value, enter a custom header that you want to forward to the origin (S3 bucket). To restrict access to the origin, you can enter a random or secret value that only you know.
  4. If you don't want to use SSL (HTTPS) for your website, proceed to the next step. To use SSL for your website, for SSL Certificate, you can select the Default CloudFront Certificate or a Custom SSL Certificate. Or, you can choose Request or Import a Certificate with ACM to request a new certificate.
    Important: If you entered Alternate Domain Names (CNAMEs) for your distribution, the CNAMEs must match the SSL certificate that you select. To troubleshoot issues with your SSL certificate, see How can I troubleshoot issues with using a custom SSL certificate for my CloudFront distribution?
  5. Choose Create Distribution.
  6. Open your website's bucket from the Amazon S3 console. Then, add a bucket policy that allows s3:GetObject on the condition that the request includes the custom Referer header that you specified in step 3.
    Note: To block access for any request that doesn't include the custom Referer header, use an explicit deny statement in the bucket policy.
  7. Update the DNS records for your domain to point your website's CNAME to your CloudFront distribution's domain name. You can find your distribution's domain name in the CloudFront console in a format that's similar to d1234abcd.cloudfront.net.
  8. Wait for your DNS changes to propagate and for the previous DNS entries to expire.
    Note: The time it takes for the previous DNS values to expire depends on the TTL value that's set at your hosted zone, and whether your local resolver uses those TTL values. 

Using CloudFormation to deploy a REST API endpoint as the origin, with access restricted by an OAI and a custom domain pointing to CloudFront

With this solution, your website:

  • Is deployed with CloudFormation
  • Is hosted on Amazon S3
  • Is distributed by CloudFront
  • Uses an SSL/TLS certificate from AWS Certificate Manager (ACM)
  • Uses Lambda@Edge to add security headers to every server response

For instructions on deploying this solution, see Amazon CloudFront Secure Static Website on the GitHub website.