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

Last updated: 2022-11-03

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 control (OAC) or origin access identity (OAI)
    Note: It's a best practice to use origin access control (OAC) to restrict access. Origin access identity (OAI) is a legacy method for this process.
  • 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 CloudFormation to deploy a static website endpoint as the origin, and 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 OAC or an OAI (legacy)

  1. Use the Amazon S3 console to create a bucket and to upload your website files.
    Note: You don't need to turn on 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, restrict access to the Amazon S3 origin using one of the following methods. It's a best practice to use OAC. Using OAI is a legacy setting.

    When creating your distribution, use the following settings to restrict access by using OAC:
    Enter your Amazon S3 bucket name in Origin Domain field.
    Under Origin access, select Origin access control settings (recommended).
    In the Origin access control dropdown list, select the OAC name and choose Create control setting.
    In the dialog box, name your control setting. It's a best practice to leave the default setting Sign requests (recommended). Then, choose Create.
    CloudFront provides you with the policy statement to give OAC permission to access your Amazon S3 bucket after creating the distribution. Select Copy Policy and paste the policy in your S3 bucket policy configuration.

    -or-

    When creating your distribution, use the following settings to restrict access using an OAI:
    Enter your Amazon S3 bucket name in Origin Domain field.
    Under Origin access, select Legacy access identities.
    In the Origin access identity dropdown list, select the origin access identity name. Then, choose Create new OAI.
    In the dialog box, name your new origin access identity and choose Create.
    For Bucket policy, select Yes, update the bucket policy.
  3. When creating your distribution, it's a best practice to use SSL (HTTPS) for your website. To use a custom domain with HTTPS, select Custom SSL certificate. You can choose Request certificate to request a new certificate. If you aren't using a custom domain, you can still use HTTPS with the cloudfront.net domain name for your distribution.
    Important: If you entered Alternate domain names (CNAMEs) for your distribution, then 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. 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.
  5. Wait for your DNS changes to propagate and for the previous DNS entries to expire.
    Note: The length of time for the previous DNS values to expire depends on the TTL value that's set at your hosted zone. It also depends on whether your local resolver uses those TTL values.

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

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

Note: When you use the Amazon S3 static website endpoint, connections between CloudFront and Amazon S3 are available only over HTTP. To use HTTPS for connections between CloudFront and Amazon S3, configure an S3 REST API endpoint for your origin.

  1. Use the Amazon S3 console to create a bucket and turn on 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 DOC-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.
    Note: For this configuration, the S3 bucket's block public access settings must be turned off. If your use case requires the block public access settings to be turned on, use the REST API endpoint as the origin. Then, restrict access by an origin access control (OAC) or origin access identity (OAI).
  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, enter the endpoint that you copied in step 2.
    Note: Don't select the bucket from the dropdown list. The dropdown list includes only the S3 Bucket REST API endpoints that aren't used in this configuration.
  5. When creating your distribution, it's a best practice to use SSL (HTTPS) for your website. To use a custom domain with HTTPS, select Custom SSL certificate. You can choose Request certificate to request a new certificate. If you aren't using a custom domain, then you can still use HTTPS with the cloudfront.net domain name for your distribution.
    Important: If you entered Alternate domain names (CNAMEs) for your distribution, then 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. 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.
  7. Wait for your DNS changes to propagate and for the previous DNS entries to expire.
    Note: The length of time for the previous DNS values to expire depends on the TTL value that's set at your hosted zone. It also depends on whether your local resolver uses those TTL values.

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

This configuration restricts access by setting up a custom Referer header on the distribution. Then, it uses a bucket policy to allow access only for requests with the custom Referer header.

Important: Be sure to evaluate whether the access allowed by this setup meets the requirements of your use case.

Note: When you use the Amazon S3 static website endpoint, connections between CloudFront and Amazon S3 are available only over HTTP. To use HTTPS for connections between CloudFront and Amazon S3, configure an S3 REST API endpoint for your origin.

  1. Use the Amazon S3 console to create a bucket and turn on 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 DOC-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, enter the endpoint that you copied in step 2.
    Note: Don't select the bucket from the dropdown list. The dropdown list includes only the S3 Bucket REST API endpoints that aren't used in this configuration.
    Under Add custom header, choose Add header.
    For Header name, enter Referer.
    For Value, enter a customer header value that you want to forward to the origin (S3 bucket). To restrict access to the origin, enter a random or secret value that only you know.
  4. When creating your distribution, it's a best practice to use SSL (HTTPS) for your website. To use a custom domain with HTTPS, select Custom SSL certificate. You can choose Request certificate to request a new certificate. If you aren't using a custom domain, you can still use HTTPS with the cloudfront.net domain name for your distribution.
    Important: If you entered Alternate domain names (CNAMEs) for your distribution, then 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. 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. For this configuration, the S3 bucket’s block public access settings must be turned off. Amazon S3 considers a bucket policy that grants anonymous access restricted by a Referer to be public. If your use case requires the block public access settings to be turned on, then use the REST API endpoint as the origin. Then, restrict access with an origin access control (OAC) or origin access identity (OAI).
    Note: To block access for any request that doesn't include the custom Referer header, use an explicit deny statement in the bucket policy.
  6. 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.
  7. Wait for your DNS changes to propagate and for the previous DNS entries to expire.
    Note: The length of time for the previous DNS values to expire depends on the TTL value that's set at your hosted zone. It also depends on whether your local resolver uses those TTL values.

Using CloudFormation to deploy a static website endpoint as the origin, and 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 CloudFront Response Header Policies to add security headers to every server response

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