Introduction

When trying to host Cantaloupe (an IIIF image server) on AWS App Runner with CloudFront placed in front of it, I encountered a problem where all requests returned 404 errors when accessed through CloudFront.

This article records the investigation of the cause, the solutions I tried, and the conclusion.

Environment

  • Application: Cantaloupe 5.0.5 (IIIF image server)
  • Hosting: AWS App Runner
  • CDN: Amazon CloudFront
  • Region: ap-northeast-1 (Tokyo)

Problem Overview

Symptoms

Access MethodResult
Direct access to App Runner200 OK
Access via CloudFront404 Not Found

What Was Confirmed

When 404 was returned via CloudFront, the response header contained server: envoy. This indicates that the request was reaching App Runner’s internal proxy (Envoy).

$HsxTe-cTrcuPar/ecl2rh:e-4:I0e4nEhvrtortyoprs:f/r/oxmxxcxlxo.ucdlforuodnftront.net/

In other words, the communication from CloudFront to App Runner was successful, but the request was not being forwarded to the application (Cantaloupe) inside App Runner.

Cause

Host Header Issue

Inside App Runner, Envoy operates as a reverse proxy. Envoy routes requests based on the Host header.

DViirHaHeoocsECsEttnltn:vo:vaouocxydxycxFxex"rx"sxIoxIsxnx:.kt.dan:copoln-wo'nutotdrhfktirnhsooenwaHtso.ttsnh-tei1"ts.aHwosFsaotpr"pwraurndRneettrou.rcanopmp4042w0i0thOoKutforwarding

Why the Host Header Becomes the CloudFront Domain

When CloudFront forwards requests to the origin (App Runner), by default the viewer’s Host header is forwarded as-is.

Solutions Tried

1. Origin Request Policy “AllViewerExceptHostHeader”

This is the policy recommended by AWS for App Runner. This policy excludes the Host header, and CloudFront should automatically set the origin’s domain name as the Host header.

Result: Failed (still 404)

2. Origin Request Policy “None”

A setting that doesn’t forward any viewer headers.

Result: Failed (still 404)

3. Custom Origin Request Policy

I created a custom policy that explicitly set “Headers: None”.

HCQeouaoedkreiyresss::trNAiolnnlges:All

Result: Failed (still 404)

4. Rewriting Host Header with CloudFront Functions

I tried to rewrite the Host header to the App Runner domain during the viewer request.

f}unctvrriaeeorqtnuurerhesnaqtnu.rdehelseqetaurde(=esertves;ev[ne'tnh)to.s{rte'q]ue=st{;value:'xxxxx.ap-northeast-1.awsapprunner.com'};

Result: Failed

502ERROR:TheCloudFrontfunctiontriedtoadd,delete,orchangearead-onlyheader.

In CloudFront Functions, the Host header is read-only in the viewer request event and cannot be modified.

5. Rewriting Host Header with Lambda@Edge

Lambda@Edge can run on origin request events and can modify more headers.

e}x;porcrrtoeesnqt.suuhterasnnrtde.rlqheeueqreausde=tesrta=s;s[ye'nvhceons(tte.'vR]eenc=to)r[d{=s>[k0e{]y.:cf'.Hroesqtu'e,stv;alue:'xxxxx.ap-northeast-1.awsapprunner.com'}];

Result: Failed

502ERROR:TheLambdafunctionresultfailedvalidation:Thefunctiontriedtoadd,delete,orchangearead-onlyheader.

The Host header was also read-only in Lambda@Edge origin request events.

6. Creating New App Runner Service and CloudFront Distribution

Considering the possibility that the existing configuration had issues, I created entirely new resources.

  • New App Runner service (no custom domain)
  • New CloudFront distribution
  • Origin request policy “AllViewerExceptHostHeader”

Result: Failed (still 404)

What the Investigation Revealed

App Runner Log Check

Logs when accessing App Runner directly:

Hos2t0:0xOxKxxx.ap-northeast-1.awsapprunner.com

When accessing via CloudFront:

  • The request was not logged in Cantaloupe’s logs
  • In other words, Envoy was returning 404 before forwarding the request to the application

Testing with curl by Changing the Host Header

When accessing App Runner directly, changing the Host header to the CloudFront domain:

$HsTecTruPr/el1r.:-1Ie4n-0vH4oy"NHootstF:ouxnxdxxx.cloudfront.net"https://xxxxx.ap-northeast-1.awsapprunner.com/

The 404 was reproduced. This confirmed that the problem was with the Host header.

Conclusion

Root Cause

The 404 error with the CloudFront + App Runner combination is caused by App Runner’s Envoy routing based on the Host header.

If the “AllViewerExceptHostHeader” policy doesn’t resolve the issue, it is considered to be a problem on the App Runner side.

  1. Contact AWS Support

    • Report the issue as a 404 error occurring with App Runner + CloudFront
  2. Consider Alternative Architectures

    • ECS Fargate + ALB: Proven track record of integration with CloudFront
    • EC2 + Nginx: Most flexible configuration
    • Cloudflare: Easy Host header rewriting

Reference Information

Articles Reporting Similar Issues

These articles report that “AllViewerExceptHostHeader” resolved the issue, but it did not work in this case.

AWS Documentation

Summary

Method TriedResult
AllViewerExceptHostHeaderFailed
Origin request policy “None”Failed
Custom policy (no headers)Failed
CloudFront FunctionsFailed (Host is read-only)
Lambda@EdgeFailed (Host is read-only)
New resource creationFailed

Despite all settings being correct, it did not work, suggesting the problem is related to App Runner’s internal behavior. If you are considering the CloudFront + App Runner combination, please keep in mind that you may encounter this issue.