Serving reflex frontend statically from Cloudfront

Hi!

We are deploying a reflex application to AWS.

We have the backend successfuly running as a container in fargate (it works fine as I can connect my local frontend-only server an the app works just fine)

The frontend has been exported as static assets and deployed to S3/Cloudfront (I have experience with both react and angular deployments using this pattern), however I am facing a problem with client routes.

The client is only receiving the root url “eg: app.domain.com/” it does not receive any other path nor query parameters. I am logging the path as the first action on all my states.

Can the problem be related with cloudfront? I am using the same configuration that I usually deploy with angular and react… but perhaps something is missing?

  • Redirecting error responses to index.html
  • Disabled cache to make sure its not interfering

Is there any specific reflex spec that could be producing this problem I am not familiar with the internal working of the platform, but the docker nginx server seems to be straightforward.

Any help will be much appreciated!

Edit: This is my actual CDK code for cloudfront. I have no problem sharing the full CDK script once it works as a recipe :wink:

Edit2: I have successfully deployed the same frontend bundle to netlify, so cloudfront is probably the root cause

Edit3: Reflex is based on nextjs right? I have read that client routing is not as straightforward as other frameworks… any feedback on this?

# S3 Bucket for Frontend
        site_bucket = s3.Bucket(
            self,
            "SiteBucket",
            bucket_name=f"xxxxxxxx",  # Replace with a unique bucket name
        )

        # Origin Access Identity for CloudFront to access S3
        origin_access_identity = cloudfront.OriginAccessIdentity(
            self, "OAI", comment="OAI for my frontend"
        )

        # Grant CloudFront access to the S3 bucket
        site_bucket.grant_read(origin_access_identity)

        # Existing ACM Certificate
        certificate_global = acm.Certificate.from_certificate_arn(
            self,
            "CertificateGlobal",
            certificate_arn="axxxxxxxxxx",
        )

        # CloudFront Distribution
        distribution = cloudfront.Distribution(
            self,
            f"{APP_NAME}-Distribution",
            default_behavior=cloudfront.BehaviorOptions(
                origin=origins.S3Origin(
                    site_bucket, origin_access_identity=origin_access_identity
                ),
                viewer_protocol_policy=cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
                allowed_methods=cloudfront.AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
                cache_policy=cloudfront.CachePolicy.CACHING_DISABLED,  # Disable caching
            ),
            domain_names=["xxxxx"],  # Replace with your domain name
            certificate=certificate_global,
            default_root_object="index.html",
            http_version=cloudfront.HttpVersion.HTTP2,
            error_responses=[
                cloudfront.ErrorResponse(
                    http_status=403,
                    response_http_status=200,
                    response_page_path="/index.html",
                    ttl=Duration.minutes(0),
                ),
                cloudfront.ErrorResponse(
                    http_status=404,
                    response_http_status=200,
                    response_page_path="/index.html",
                    ttl=Duration.minutes(0),
                ),
            ],
        )

        # S3 Deployment
        s3_deployment.BucketDeployment(
            self,
            "DeployWebsite",
            sources=[
                s3_deployment.Source.asset("../.web/_static")
            ],  # Replace with your frontend build directory
            destination_bucket=site_bucket,
            distribution=distribution,
            distribution_paths=["/*"],
        )

I’m not well versed in the cloudfront deployment, but at least one thing you’ll want to change is redirecting 404 to /404.html to trigger client side routing for dynamic routes.

Reflex does use nextjs so you will need to configure your cloudfront routing rules to support nextjs apps

There are a couple different tutorial online on how to do this Deploy Next JS Application to Amazon CloudFront with S3 - DEV Community

If you are looking for a simpler deployment your can just run you app on fargate in prod mode and expose the 3000/8000 ports