1

I have a flask app deployed to AWS Lambda via zappa. Zappa creates an AWS rest endpoint such as random_api_ID.execute-api.us-east-2.amazonaws.com/devwhich works perfectly when directly entered into the browser. But, when I use Cloudfront to associate this end point to my custom domain, dev.mywebsite.com, I get a 404 error in the response for any assets stored in a subfolder. The reason is because Cloudfront is serving urls such as

dev.mywebsite.com/dev/static/css/style.css

instead of

dev.mywebsite.com/static/css/style.css

Also, this works: random_api_ID.execute-api.us-east-2.amazonaws.com/dev/static/css/style.css

But this does not: random_api_ID.execute-api.us-east-2.amazonaws.com/static/css/style.css

So, somehow, I need Cloudfront to associate random_api_ID.execute-api.us-east-2.amazonaws.com/dev with dev.mywebsite.com instead of dev.mywebsite.com/dev.

My Cloudfront distribution has the following parameters:

 Alternate Domain Name: dev.mywebsite.com 
 Origin Domain: random_api_ID.execute-api.us-east-2.amazonaws.com
 Origin Path: dev <-- this is the stage name

I've tried mapping a custom domain to the zappa-generated AWS rest endpoint via AWS API Gateway; however, that solution produces a private Cloudfront domain that I have no control over; I prefer a solution that involves configuring Cloudfront.

Thanks in advance!

Vee
  • 1,821
  • 3
  • 36
  • 60

2 Answers2

0

There is an option that you are able to add your stageName to make your URL to be accessible without it.

Reference: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html#DownloadDistValuesOriginPath

Go to your CloudFront's Distribution, edit your Origin which points to API Gateway URL.

  • Find the Origin path option
  • Place your stageName into it (my example is dev stage) so it should be /dev (need to have / at prefix)

CloudFront Origin Config

Then click Save changes and wait for the deployment around 5 minutes. And try to access it as you would love to

https://<domainName>/<resourceName>
Binh Nguyen
  • 1,891
  • 10
  • 17
  • My stage name is also called `dev` and when I entered it in the `origin path` field, Cloudfront serves the url with `dev` appended to the root. When I leave `origin path` blank, them the browser fails to load the url without the stage name. What might be causing us to get different results? – Vee Oct 10 '21 at 01:03
  • Also, I noticed that in your `origin path` field, you entered `dev` instead of `/dev`. When I enter my stage name in that field without the forward slash and try to save my changes, Cloudfront returns the error, `Failed to create origin: The parameter originPath contains one or more parameters that are not valid.`. What am I missing? – Vee Oct 10 '21 at 03:25
  • When you leave the origin path blank, it just maps between your CloudFront DNS with your API DNS so if you want to access your dev stage, the CloudFront DNS needs to have /dev. So if we add the origin path, we no need to add that /dev right. – Binh Nguyen Oct 10 '21 at 04:15
  • Your comment `so if you want to access your dev stage, the CloudFront DNS needs to have /dev. So if we add the origin path, we no need to add that /dev right`, I need to have the cloudfront-dns to include the api-dns with the stage name. In other words: `cloudfront_dns = api_dns/{stage}`. But, when adding `stage` in the `origin-path`, it seems that Cloudfront produces `cloudfront_dns/{stage} = api_dns/{stage}` – Vee Oct 10 '21 at 04:52
  • Yes, if you use Origin Path, it helps you to add the {stage} hiddenly without typing it into the domain name. Ah wait, after checking my origin path, it should have the / at prefix. Sorry for my confusion ^^ – Binh Nguyen Oct 10 '21 at 05:19
  • No worries about the `/` at prefix. Ok, so I leave `origin path` empty, then the issue is that I need to type `dev.myexample.com\dev` in order for the app to work. This is not ideal bc when I migrate to production, I can't have my users remember to type `www.myexample.com/prod` every time they want to use my app. What I need is when a user types www.myexample.com, Cloudfront serves them 'api_dns/prod'. – Vee Oct 10 '21 at 05:21
  • So you need to have 2 CloudFront distribution, 1 for dev and 1 for prod. Each distribution, you edit your origin and add the Origin Path :D – Binh Nguyen Oct 10 '21 at 05:30
  • Right, your solution of leaving `origin path` empty and then just typing `devtest.mywebsite.com/dev` will work just fine. But, then in production, I will have the same issue that I have now; I will need to populate `origin path` with `/dev` and then the `static` assets will return a 404. This is why I would like to have this problem solved in dev since production should mirror development. – Vee Oct 10 '21 at 06:04
  • I don't see your points of using dev resources with Prod stage. You need to have your Prod resources also and it must be under Prod stage. – Binh Nguyen Oct 10 '21 at 10:34
  • My mistake... Regarding my previous comment, I meant to say that in production, I will have the same issue that I have now; I will need to populate origin path with `/prod` and then the static assets will return a 404. – Vee Oct 11 '21 at 00:23
  • This solution did not work for me as leaving `origin path` blank will require my users to type `www.mywebsite.com/dev` every time they visit my app. Thus, I prefer the solution using Cloudfront functions as detailed in the selected answer. Thanks for trying, Leondkr! – Vee Oct 12 '21 at 18:59
0

I found this article and ended up solving the problem by using Cloudfront Functions:

  1. Make sure you have a Cloudfront distribution that's a) associated with your AWS API Gateway endpoint and b) contains your custom domain name.

  2. Within the origin tab of your distribution, I entered the full AWS API Gateway endpoint. My app uses an endpoint automatically generated by Zappa,random_api_ID.execute-api.us-east-2.amazonaws.com/dev. Entering the full endpoint into the origin domain field should automatically populate the origin path field with \dev.

  3. In the Cloudfront navigation pane, choose Functions then click the Create function button.

  4. Enter a function nam, then click Create Function.

  5. With the Build tab selected, go to the Function Code section and enter the following Javascript:

    function handler(event) {
        var request = event.request;
        request.uri = request.uri.replace(/^\/[^/]*\//, "/"); 
        return request;
    }
    

enter image description here

  1. Save your function

  2. Test your function by clicking the Test tab and enter a url with an appended stage name:

enter image description here

  1. Clicking the test function button. You should get a successful execution message below your function code:

enter image description here

  1. Click the Publish tab and publish your function by clicking the Publish function button.

  2. Under the publish section, you need to associate the published function to your Cloudfront distribution. Click the Add distribution button.

  3. In the new window, select a distribution and click the Add Association button.

enter image description here

  1. Wait for Cloudfront to finish deploying your distribution. When it's finished, check your custom domain in the browser and make sure assets are successfully loaded.
Vee
  • 1,821
  • 3
  • 36
  • 60