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