Cloudfront as a reverse proxy

I run two services on AWS. One is a static website, the other is a serverless API.

The static website consists of the following setup:

flowchart TD 
    User --> Cloudfront
    Cloudfront -- Default Behaviour --> S3

It's extremely simple, and handles global caching really easily.

The serverless API is a bit more complex, but it's still pretty simple.

flowchart LR
    User --> APIGateway[API Gateway]
    APIGateway -- GET /bar --> Lambda1[Lambda 1]
    APIGateway -- GET /foo --> Lambda2[Lambda 2]

I've just setup Mastodon recently and need to update my /.well-known/webfinger to point to the mastodon instance. This will let me use my root domain as my mastodon username URL. Issue is - I'm already using the webfinger endpoint for OIDC...

So the solution is to set up a special API function that can handle this request. If It's meant for mastodon - send it there. Otherwise, return whatever else I want as JSON.

flowchart TD 
    User -- /.well-known/webfinger --> Cloudfront
    Cloudfront -- Custom Behaviour --> APIGateway[API Gateway]
    APIGateway --> Lambda[Lambda]

The issue I was running into was my cloudfront custom behaviour wasn't working. This was due to CloudFront forwarding the Host header to the origin. API Gateway doesn't like this & will always return a 403 {"message":"Forbidden"}.

I fixed this by ensuring the OriginRequestPolicyId was set up to a policy that forwarded everything except the Host header. AWS Incorrectly warn that this will break API Gateway, but it does not.

Here's my working truncated Cloudfront distribution config CacheBehaviors and Origins are the primary changes:

WebsiteCloudFrontDistribution:
  Type: AWS::CloudFront::Distribution
  Properties:
    DistributionConfig:
      Origins:
        - DomainName: ${self:custom.s3Bucket}.s3.${opt:region}.amazonaws.com
          Id: ${self:custom.s3Bucket}.s3.${opt:region}.amazonaws.com
          OriginAccessControlId: !Ref WebsiteCloudfrontOriginAccessControl
          S3OriginConfig:
            OriginAccessIdentity: ""
        - DomainName: api.pfy.ch
          Id: api.pfy.ch
          CustomOriginConfig:
            OriginProtocolPolicy: https-only
      DefaultRootObject: index.html
      CacheBehaviors:
        - PathPattern: /.well-known/*
          TargetOriginId: api.pfy.ch
          ViewerProtocolPolicy: redirect-to-https
          CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # Disable caching
          OriginRequestPolicyId: 88de81a8-de41-4bfc-a73-d5de1f3cd023 # Custom policy to forward everything except host!
          AllowedMethods:
            - GET
            - HEAD
            - OPTIONS
            - PUT
            - POST
            - PATCH
            - DELETE
          CachedMethods:
            - HEAD
            - GET
          ForwardedValues:
            QueryString: true

If forwarding to API Gateway ENSURE that the Host header is not forwarded.



This page was originally published 2 Sept 2024

Updated 215 days ago (17 Mar 2025)