How to forward cloudfront to HTTP API with custom domain

1.2k Views Asked by At

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'
    })
1

There are 1 best solutions below

1
Rolf Spuler On

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