Score:1

AWS CloudFront 404 error on web root only - node.js with express and pug

in flag

The Setup

I have a web site built on node.js, express.js, and pug.js running on an AMI Linux instance in AWS. I've given the instance an Elastic IP and if I browse directly to the generated DNS record for that elastic IP, everything works correctly.

I've also created a CloudFront distribution for the site. The origin is set to the generated DNS record for the elastic IP and there are only two behaviors - one for * and a higher priority one for the contact form only that allows POST verbs (the default behavior does not allow POST). The public DNS entry for the site points to the CloudFront distribution.

The Problem

Again, when I browse directly to http://ec2-<elastic-IP-address>.compute-1.amazonaws.com, everything works. When I browse to https://<custom domain>.com/about or /contact or any other page of the site, it also works. But, when I browse to just the URL with no page specified, i.e., just https://<custom domain>.com, I get a 404 page generated by Express.

What I've Tried

  • I've done a bunch of web searches and haven't even found any results related to the same problem.
  • I tried making a specific behavior in the CF distribution for / and sending that to a specific target for the home page, no change in result.
  • I wondered if somehow the default Express port of 3000 was somehow messing up how CF was retrieving the site from the origin so I did the work to make it so node could run on port 80 and changed that and the CF origin port. Site is still up but the problem remains.
  • I've reviewed the routing to look for problems and didn't see anything that seems like a problem. Also, since the site completely works if I bypass CF I can't come up with a theory about why direct browsing works and CF doesn't.

Details

The routing contents of my app.js are:

var indexRouter = require('./routes/index');
app.use('/', indexRouter);

Inside ./routes/index.js is:

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { homeactive: 'active' });
});

/* GET home page. */
router.get('/home', function(req, res, next) {
  res.render('index', { homeactive: 'active' });
});

The complete Express error is:

Not Found

404

NotFoundError: Not Found
    at /home/ec2-user/website/Express/app.js:28:8
    at Layer.handle [as handle_request] (/home/ec2-user/website/Express/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/home/ec2-user/website/Express/node_modules/express/lib/router/index.js:328:13)
    at /home/ec2-user/website/Express/node_modules/express/lib/router/index.js:286:9
    at Function.process_params (/home/ec2-user/website/Express/node_modules/express/lib/router/index.js:346:12)
    at next (/home/ec2-user/website/Express/node_modules/express/lib/router/index.js:280:10)
    at /home/ec2-user/website/Express/node_modules/express/lib/router/index.js:646:15
    at next (/home/ec2-user/website/Express/node_modules/express/lib/router/index.js:265:14)
    at Function.handle (/home/ec2-user/website/Express/node_modules/express/lib/router/index.js:175:3)
    at router (/home/ec2-user/website/Express/node_modules/express/lib/router/index.js:47:12)

I'm not sure what origin or behavior settings from CF would be helpful here. It's pretty much exactly what you'd expect, nothing fancy.

The origin is a "custom" origin (enter a URL instead of choosing an S3 bucket or ELB, etc.) with ec2-<elastic-IP-address>.compute-1.amazonaws.com as the URL, HTTP only, port 80, origin path blank, origin shield off, no advanced settings.

The behavior is path pattern *, the origin detailed above selected, compress set to yes, redirect HTTP to HTTPS, GET, HEAD allowed only, no viewer access restriction, CachingOptimized managed cache policy.


Disclaimer

I'm fully aware that some aspects of the current setup for this hosting are not at all professional. This is a personal web site and I'm teaching myself node, express, pug, and AMI Linux while building and deploying this web site. I'm trying to get a "minimum viable product" up before iterating on both site design and infrastructure/devops. I do plan to containerize eventually and may do a WAF if I can afford it, etc., etc. So I don't need to hear a lot about what I've done wrong in terms of security or reliability of the site, etc. I have done devops for a highly reliable, well-trafficked web app in AWS before, so I know what's involved and I also know how much it costs. When it's the client's money, they will get all the bells and whistles.


Edit: this might be a fix which I will try, can’t say I like it though.

https://exanubes.com/blog/fix-cloudfront-404-errors-when-visiting-direct-urls

Tim P avatar
af flag
I didn't see this in what you have checked, so double check that you haven't set a default root object in CloudFront. That will append a path to the root path [transparently] when making a request to the root path (i.e. "/"). Often people need this for things like index.html. If your back-end application does not need this it may be causing your problem.
Todd Wilcox avatar
in flag
@TimP There is a default path of `*` and there is **not** a path of `/`. Is that correct?
Todd Wilcox avatar
in flag
@TimP Re-reading your comment I'm not sure - are you talking about in the origin or behavior? Or both? I don't think I've made the mistake you're talking about. Again, every part of the site works except the direct URL. I think I'm having the same problem as this: https://exanubes.com/blog/fix-cloudfront-404-errors-when-visiting-direct-urls
Tim P avatar
af flag
It is in the distribution setup, not the behavior. Check out step 3 in this link. https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DefaultRootObject.html If you have a default root assigned AND your back-end is not expecting that then it could be causing the 404 errors when you use the "/" path (because CF is adding whatever you have set to the path).
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.