Skip to content

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. Then, I want to host the website on Amazon Simple Storage Service (Amazon S3).

Resolution

To use Amazon S3 to host a static website that uses API Gateway as the proxy, use an HTTP integration or an AWS service integration.

Use an HTTP integration

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

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 then deploy your REST API.

Create a REST API

Complete the following steps:

  1. Open the API Gateway console.
  2. Choose Create API.
  3. Under REST API, choose Build.
  4. For API name, enter a name for your REST API.
  5. From the API endpoint type dropdown list, choose your endpoint type, and then choose Create API.
  6. In the navigation pane, choose Resources under your API.
  7. Choose Create resource.
  8. For Resource path, keep as /.
  9. For Resource name, enter a name. For example, key.
  10. Choose Create resource.

Create the method for the root resource

Complete the following steps:

  1. Under Resources, select the resource you created. For example, /key.
  2. Under Methods, choose Create method.
  3. From the Method type dropdown list, choose GET.
  4. For Integration type, choose HTTP.
  5. Select HTTP proxy integration.
  6. From the HTTP method dropdown list, choose GET.
  7. For Endpoint URL, enter http://BUCKET_NAME.s3-website.REGION.amazonaws.com/key.
    Note: Replace BUCKET_NAME with your bucket name, REGION with your bucket's Region, and key with the name of your resource.
  8. Choose Create method.

Deploy the REST API

Complete the following steps:

  1. Choose Deploy API.
  2. From the Stage dropdown list, choose *New Stage*.
  3. For Stage name, enter a name. For example, STAGE_NAME.
  4. Choose Deploy.
  5. Under Stage details, note the invoke URL to test your API.
  6. To test the API proxy for your S3 website, run the following curl command:
    curl -X GET https://API_ID.execute-api.REGION.amazonaws.com/STAGE_NAME/index.html
    Note: Replace API_ID with your API ID, REGION with your Region, and STAGE_NAME with the name of your stage.

Use an AWS service integration

Configure the S3 static website

If your S3 static website is blocked from public access, then configure the website so that you can access it only from the API proxy.

Complete the following steps:

  1. Configure a static website on Amazon S3.
    Note: When you configure the static website, skip the Step 3: Edit Block Public Access settings section. Keep the default Block all public access setting on.
  2. Modify a bucket policy that makes your bucket content publicly available to allow the API proxy to access only the S3 bucket. Example bucket policy:
    {  
      "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_ID:API_ID/*/GET/"
            }
          }
      }]
    }
    Note: Replace BUCKET_NAME with your bucket name, REGION with your region, ACCOUNT_ID with your AWS account ID, and API_ID with your API ID.
  3. Create an AWS Identity and Access Management (IAM) policy to allow the GetObject API access to the S3 bucket. Example IAM policy:
    {
      "Version": "2012-10-17",
      "Statement": [{
        "Effect": "Allow",
        "Action": ["s3:GetObject"],
        "Resource": [
            "arn:aws:s3:::BUCKET_NAME/*"
        ]
      }]
    }
    Note: Replace BUCKET_NAME with your bucket name.
  4. Create an IAM role, and then attach the preceding IAM policy.
  5. Note the IAM role's Amazon Resource Name (ARN).
    Note: 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"
      }]
    }

Create a REST API proxy for the S3 service

Complete the following steps:

  1. Open the API Gateway console.
  2. Choose Create API.
  3. For REST API, choose Build.
  4. For API name, enter a name for your REST API.
  5. From the API endpoint type dropdown list, 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 client traffic accesses from the internet. If your client traffic accesses your APIs only from within the same AWS Region, then use Regional endpoints.
  6. Choose Create API.

Create GET method for the root resource

Complete the following steps:

  1. Select the root resource /.
  2. Choose Create method.
  3. From the Method type dropdown list, choose GET.
  4. For Integration type, choose AWS service.
  5. From the AWS Region dropdown list, choose your Region.
  6. From the AWS service dropdown list, choose Simple Storage Service (S3).
  7. For AWS subdomain, keep the field blank.
  8. From the HTTP method dropdown list, choose GET.
  9. For Action type, choose Use path override.
  10. For Path override, enter your S3 bucket path. For example, BUCKET_NAME/index.html.
  11. For Execution role, enter the IAM role's ARN.
  12. Choose Create method.

Note: The 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

Complete the following steps:

  1. Choose Create resource.
  2. For Resource Path, keep as /.
  3. For Resource name, enter a name. For example, object.
  4. Choose Create resource.

Configure a GET method for the resource

Complete the following steps:

  1. Under Resources, select the resource you created. For example, /object.
  2. Complete steps 2-12 in the Create GET method for the root resource section.
  3. Choose GET, and then choose Integration request.
    Note: Replace object with the name of your resource.
  4. Choose Edit.
  5. Expand URL path parameters, and then choose Add path parameter.
  6. Under Name, enter the name of your resource.
  7. Under Mapped from, enter the value as method.request.path.object.
    Note: Replace object with the name of your resource.
  8. Choose Save.

Set up the response header mappings for the GET method

You must map the backend content type header parameter value to the frontend counterpart so that the browser processes the response with the content type.

Complete the following steps:

  1. Under Resources, select /.
  2. Choose GET, and then choose Method response.
  3. Under Response 200, choose Edit.
  4. Under Header name, choose Add header.
  5. Set the Name as Content-Type.
  6. Choose Save.
  7. Choose Integration response, and then choose Edit.
  8. Under Header mappings, next to Content-Type, enter the Mapping value as integration.response.header.Content-Type.
  9. Repeat steps 2-8 for the GET method under the /object resource.
    Note: Replace object with the name of your resource.

Deploy the REST API

Complete the following steps:

  1. Choose Deploy API.
  2. From the Stage dropdown list, choose *New Stage*.
  3. For Stage name, enter a name. For example, STAGE_NAME.
  4. Choose Deploy.
  5. Under Stage details, note the invoke URL to test your API.

To test the API proxy for your S3 static website, run a curl command.

Note: For the following examples, replace API_ID with your API ID, REGION with your Region, and STAGE_NAME with the name of your stage.

To test the root resource, run the following curl command:

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

To test the object resource, run the following curl command:

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

Host 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 3 years ago

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

AWS
EXPERT
replied 3 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.

AWS
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"

AWS
replied 2 years ago

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

AWS
EXPERT
replied 2 years 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 a year ago

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

AWS
MODERATOR
replied a year ago