Lab / 5 steps
One CloudFront domain, two S3 buckets.
Requests under /maps/ go to a second bucket, and a Lambda@Edge function strips the prefix so the object keys stay clean.
- Step 01 · Console · CloudFront Wrong key on B
Two buckets, two behaviors
One distribution, two origins: /maps/* goes to Bucket B, everything else to Bucket A. Without a rewrite, Bucket B would be asked for a key that starts with maps/.
Behavior /maps/* → Bucket BBehavior * → Bucket A (default) - Step 02 · Lambda · us-east-1 Function ready
Write the rewrite
A Lambda@Edge function in us-east-1 (Node.js 18) removes the /maps prefix from the request URI and logs both versions.
export const handler = async (event) => {const request = event.Records[0].cf.request;const uri = request.uri;console.log('Incoming URI:', uri);if (uri.startsWith('/maps/')) {request.uri = uri.substring(5); // drop '/maps'console.log('Modified URI:', request.uri);}return request;}; - Step 03 · Lambda · Deploy to Lambda@Edge Deployed
Attach it at Origin Request
Deploy to Lambda@Edge on the /maps/* behavior, at the Origin Request event, so the URI changes just before CloudFront calls Bucket B.
Distribution: your CloudFront distributionCache behavior: /maps/*Event: Origin RequestInclude body: no - Step 04 · Request path 200 from Bucket B
Follow one request
A request for /maps/images/01.jpg matches the /maps/* behavior, the function turns it into /images/01.jpg, and Bucket B serves that object.
GET https://example.com/maps/images/01.jpg→ behavior /maps/*→ Lambda@Edge: /maps/images/01.jpg → /images/01.jpg→ s3://bucketB/images/01.jpg - Step 05 · CloudWatch Logs Verified
Check the logs
Each run logs the incoming and modified URI to CloudWatch, which is the quickest way to see the rewrite happen.
START RequestId: abc123xyzINFO Incoming URI: /maps/images/01.jpgINFO Modified URI: /images/01.jpgEND RequestId: abc123xyz