1

I am serving static website with s3 and cloudfront at / path.

I want to serve /api/* from HTTP API.

My static website is configured properly with cloudfront. And I have also configured the custom domain to HTTP api with cdk

But when I try to access my http API then I get 404 not found response. Basically Cloudfront is not forwarding my /api/* request to the HTTP API.

Here is my cloudfront CDK code

const distribution = new CloudFrontWebDistribution(this, 'CloudfrontWebDistribution', {
      httpVersion: HttpVersion.HTTP2,
      priceClass: PriceClass.PRICE_CLASS_ALL,
      viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: bucket,
            originAccessIdentity
          },
          behaviors: [{
              isDefaultBehavior: true,
              defaultTtl: Duration.hours(1)
            }]
        }, 
        {
          customOriginSource: {
            domainName: website_domain
          },
          behaviors: [{
            pathPattern: '/api/*',
            isDefaultBehavior: false,
            allowedMethods: CloudFrontAllowedMethods.ALL,
            defaultTtl: Duration.seconds(0),
            minTtl: Duration.seconds(0),
            maxTtl: Duration.seconds(0),
            forwardedValues: {
              queryString: true,
              cookies: {
                forward: 'all'
              }
            }
          }]
        }
      ],
      errorConfigurations: [
        {
          errorCode: 404,
          responseCode: 404,
          responsePagePath: '/404.html'
        }
      ],
      viewerCertificate: ViewerCertificate.fromAcmCertificate(certificate, {
        aliases: [website_domain],
        securityPolicy: SecurityPolicyProtocol.TLS_V1_2_2018
      })
    })

This is not required but I am also giving my HTTP API custom domain CDK code

    const certificate = Certificate.fromCertificateArn(this, 'ssl_cert', certArn)
    
    const domain = new DomainName(this, 'domain', {
      domainName: website_domain,
      certificate
    }) 

    const api = new HttpApi(this, 'endpoint', {
      defaultDomainMapping: {
        domainName: domain,
        mappingKey: 'api'
      },
      corsPreflight: {
        allowCredentials: true,
        allowHeaders: ['Content-Type'],
        allowMethods: [HttpMethod.GET, HttpMethod.POST, HttpMethod.OPTIONS, HttpMethod.HEAD],
        allowOrigins: [
          "https://cdn.ampproject.org",
          "https://www.bing-amp.com"
        ]
      },
      apiName: 'myAPI'
    })
Apoorv Mote
  • 523
  • 3
  • 25

1 Answers1

1

I don't see your route definitions for the HttpApi in the code snippet but I suspect the problem is that they do not start with /api.

The pathPattern in the CloudFront behavior is just there to match the url and route to the appropriate origin. But CloudFront will not remove it from the path forwarded to the origin.

There are two solutions that I'm aware of

  • Prepend /api path segment in front of all your routes
  • Use lambda@edge to remove the path segment before calling the origin.

For the second option see the accepted answer here: Multiple Cloudfront Origins with Behavior Path Redirection

  • Please look at mapping key. Its one time setup that would add `/api ` in front of every route. And I am already looking at implementing lambda@edge but it doesn't support HTTP API. I will have to use REST API. – Apoorv Mote Sep 01 '20 at 07:18