How do I use Amazon S3 to host a static website that uses API Gateway as the proxy?

7 minute read
2

I want to use Amazon API Gateway to create an API as a proxy for my static website and host the website on Amazon Simple Storage Service (Amazon S3).

Resolution

HTTP proxy integration

If your static website is publicly accessible, then use HTTP integration and provide the S3 static website URL for the API.

First, configure a static website on Amazon S3. Then, use the API Gateway console to create a REST API and a method for the root resource, and deploy your REST API.

Create a REST API

Complete the following steps:

  1. For REST API, choose Build.
  2. For API name, enter a name for your REST API.
  3. On the Endpoint type menu, choose your endpoint type, and then choose Create API.
  4. In the navigation pane, choose Resources under your API's name.
  5. On the Actions meu, choose Create resource.
  6. For Resource name, enter a name, for example key.
  7. For Resource rath, enter a path parameter, for example {key}.
  8. Choose Create resource.

Create the method for the root resource

Complete the following steps:

  1. Choose the resource name {key}b.
  2. On the Actions menu, choose Create method.
  3. On the {key} menu, choose GET, and then choose the check mark icon.
  4. For Integration type, choose HTTP, select Use HTTP Proxy integration, and then keep HTTP method as GET.
  5. For Endpoint URL, enter http://BUCKET_NAME.s3-website.REGION.amazonaws.com/{key}, and then choose Save.

Deploy the REST API

Complete the following steps:

  1. On the Actions menu, choose Deploy API.

  2. On the Deployment stage menu, choose [New Stage].

  3. For Stage name, enter a name, for example Dev.

  4. Choose Deploy.

  5. From the Dev Stage Editor, note the invoke URL to test your API.

  6. Run the following command to test the API proxy for your Amazon S3 website:

    curl -X GET https://API_ID.execute-api.REGION.amazonaws.com/index.html

    Note: Replace the example URL with your invoke URL.

AWS service integration

Configure the Amazon S3 static website

If your Amazon S3 static website is blocked from public access, then configure the website so that it's accessed only from the API proxy.

Complete the following steps:

  1. Configure a static website on Amazon S3.
    Note: When you're configuring the static website, skip step 3. Keep the default Block all public access setting turned on.

  2. Modify the bucket policy in step 4 to allow the API proxy to access only the Amazon S3 bucket:

    {
      "Version": "2012-10-17",
      "Statement": [{
          "Sid": "APIProxyBucketPolicy",
          "Effect": "Allow",
          "Principal": {
            "Service": "apigateway.amazonaws.com"
          },
          "Action": "s3:GetObject",
          "Resource": "arn:aws:s3:::BUCKET_NAME/*",
          "Condition": {
            "ArnLike": {
              "aws:SourceArn": "arn:aws:execute-api:REGION:ACCOUNT:API_ID/*/GET/"
            }
          }
      }]
    }
  3. Create an AWS Identity and Access Management (IAM) policy to allow the GetObject API to the Amazon S3 bucket:

    {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Action": ["s3:GetObject"],
        "Resource": "*"
      }]
    }
  4. Create an IAM role, and then attach the preceding IAM policy.

  5. Note the IAM role's ARN to use in a later step.
    The IAM role must contain the following trust policy for API Gateway to assume the role:

    {
      "Version": "2012-10-17",
      "Statement": [{
        "Sid": "",
        "Effect": "Allow",
        "Principal": {
            "Service": "apigateway.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }]
    }

Use the API Gateway console to complete the following steps.

Create a REST API proxy for the Amazon S3 service

Complete the following steps:

  1. Choose Create API.
  2. Choose REST API, and then choose Build.
  3. For API name, enter a name for your REST API.
  4. For Endpoint type, choose the endpoint type based on where the majority of client traffic originates from.
    Note: It's a best practice to use edge-optimized endpoints for public services that are accessed from the internet. Regional endpoints are used primarily for APIs that are accessed from within the same AWS Region.
  5. Choose Create API.

Create GET method for the root resource

To configure the root method for proxy requests to Amazon S3 static websites, complete the following steps:

  1. Select root resource "/".
  2. On the Actions menu, choose Create method.
  3. Choose GET, and then choose the check mark icon.
  4. For Integration type, choose AWS service.
  5. On the AWS Region menu, choose your Region.
  6. On the AWS service menu, choose Simple Storage Service (S3).
  7. For AWS Subdomain, keep the field blank.
  8. For HTTP method, select GET.
  9. For Action type, choose Use path override.
  10. For Path override, enter the Amazon S3 bucket path, for example BUCKET_NAME/index.html.
  11. For Execution role, enter the IAM role's ARN.
  12. Choose Save.

This setup integrates the frontend GET API request https://your-api-host/stage/ to the GET S3 backend https://your-s3-host/index.html.

Create an API resource object

To access specific objects from an S3 bucket, create a resource that's named {object} that maps the object path in the frontend API request. For example, map GET https://your-api-host/stage/home.html to the GET S3 backend https://your-s3-host/home.html.

Complete the following steps:

  1. Choose Resources.
  2. On the Actions menu, choose Create resource.
  3. For Resource name, enter a name, for example {object}.
  4. For Resource Path, enter a path, for example {object}.
  5. Choose Create resource.

Configure a GET method for the resource

Complete the following steps:

  1. Select the {object}.
  2. On the Actions menu, choose Create method.
  3. Choose GET, and then choose the check mark icon.
  4. For Integration type, choose AWS service.
  5. On the AWS Region menu, choose your Region.
  6. On the AWS service menu, choose Simple Storage Service (S3).
  7. For AWS subdomain, keep the field blank.
  8. For HTTP method, choose GET.
  9. For Action type, choose Use path override.
  10. For Path override, enter your Amazon S3 bucket path, for example BUCKET_NAME/{object}.
  11. For Execution role, enter the IAM role's ARN.
  12. Choose Save.
  13. Choose GET for the Resource name {object}, and then choose Integration request.
  14. Expand URL path parameters, enter a name value object and mapped from value method.request.path.object, and then select the check box to save.

Set up the response header mappings for the GET method

Map the backend content type header parameter value to the frontend counterpart so that the browser successfully processes the response with the content type.

Complete the following steps:

  1. Choose GET.
  2. Under Resources /, choose Method response.
  3. Expand the arrow next to HTTP Status 200.
  4. Under Response Headers for 200, choose Add header.
  5. Choose the header Name as Content-Type, and then select the check box to save.
  6. Choose Method execution.
  7. Choose Integration response, and then expand the arrow next to HTTP status regex.
  8. Expand Header mappings.
  9. For Content-Type, enter the mapping value as integration.response.header.Content-Type.
  10. Repeat steps 1-6 for the GET method under Resource /{object}.
  11. Repeat the steps in the Deploy the REST API section of this article.

Test the API proxy

To test the API proxy for your Amazon S3 static website, use a browser or a curl command:

Root (/) resource

curl -X GET https://API_ID.execute-api.REGION.amazonaws.com/STAGE_NAME/

{Object} resource

curl -X GET https://API_ID.execute-api.REGION.amazonaws.com/STAGE_NAME/home.html

Related information

Tutorial: Create a REST API as an Amazon S3 proxy

Hosting a static website using Amazon S3

Develop REST APIs in API Gateway

Create a deployment for a REST API in API Gateway

8 Comments

Under Create the Method for the Root Resource step 4 it will not allow me to enter http://.s3-website-.amazonaws.com/{key} for endpoint URL. Is there something else I should add?

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
EXPERT
replied 2 years ago

There seems to be a typo in "Configure a GET method for the resource" section, pt.9 "For Path override, enter your Amazon S3 bucket path similar to <bucket_name>/{object.".

The typo is - ' {object. ' Correction - ' {object} '

replied 2 years ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 2 years ago

The API gateway was returning content-type: application/json despite the s3 content type being set correctly. This was causing the page to display as text instead of rendered html by the browser. To resolve this, I added a header mapping to the 200 response:

method.response.header.Content-Type: "integration.response.header.Content-Type"

profile pictureAWS
replied a year ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
EXPERT
replied a year ago

Hello! Thank you for this article. It has been a huge help. I've got it working so that I can launch the index.html page on my non-public S3 bucket! The one issue I'm having, is that none of the images are loading in the index.html (each fails to load with a access forbidden). Does this have something to do with the step where we create the API Resource Object? The images are in the root/img "folder" of the S3 bucket. I'm not sure how to create a resource for the images. Any help is greatly appreciated!

replied 9 months ago

Thank you for your comment. We'll review and update the Knowledge Center article as needed.

profile pictureAWS
MODERATOR
replied 9 months ago