Content delivery based on subdomains

Posted on Feb 19, 2025 • 7 min read

Dharmik Mashru

DevOps Engineer

Content delivery based on subdomains

This blog post explains how to configure a CloudFront distribution to deliver different objects from an S3 bucket based on the subdomain used in the request. By default, CloudFront will serve the same object for all alternate domain names associated with a distribution. However, you can customize this behavior using a Lambda@Edge function to modify requests based on the subdomain.

How CloudFront serves requests on different subdomains by default:

When you configure multiple alternate domain names for a CloudFront distribution that accesses objects from an S3 bucket, all specified alternate domains will retrieve the same objects from the origin bucket. This means that users will receive the same content from the designated object in the bucket regardless of the domain name used to access the CloudFront distribution.

For instance, if the index.html file is accessed by default with the domain configured in CloudFront, and the domains set up in CloudFront are a.example.com, b.example.com, and c.example.com, all these domains will retrieve the same index.html file.

Solution to access different objects based on subdomains:

To allow CloudFront to deliver different objects based on specific subdomains, you must set up a Lambda@Edge function in the “origin request” event of your CloudFront distribution’s cache behavior for the S3 origin. The origin request lambda will be executed before the request is forwarded to the origin this will help the function to modify requests before they reach the origin bucket and adjust the origin path accordingly.

Start by creating a Lambda@Edge function that triggers on the origin request event. In this function, you can use logic to determine which subdomain is being accessed and dynamically adjust the requested path to point to the appropriate resources. After configuring the function, deploy it to the CloudFront distribution associated with your subdomains. This setup will ensure that users receive the correct content based on the subdomain they access.

For instance, using the domain a.example.com retrieves the object from the a directory in the origin bucket. Meanwhile, b.example.com will retrieve the object from the b directory.

Architecture diagram:

test

Implementation:

  • Create a Lambda@Edge function:

- Open the Lambda console in us-east-1 region and click on the Create function.

test

- In permissions under Change default execution role select Create a new role from AWS policy templates.

test

- Set the role name and select Basic Lambda@Edge permissions (for CloudFront trigger). Click on the Create function button.

test

- Replace the code in the code source with the following code.

'use strict';

exports.handler = async (event, context, callback) => {
    const request = event.Records[0].cf.request;

    console.log("Event: " + JSON.stringify(event));

    const subDomain = request.headers.host[0].value.split(".")[0];
    const s3BucketRegionalDomainName = request.origin.s3.customHeaders["x-env-s3-bucket-regional-domain-name"][0].value

    request.headers['host'] = [{ key: 'host', value: s3BucketRegionalDomainName}];

    request.uri = "/" + subDomain + "/index.html";

    console.log("Request: " + JSON.stringify(request));

    try {
        callback(null, request);
    } catch (error) {
        console.error("Error processing request:", error);
        callback(error);
    }
};

- Click on the Versions tab and click on Publish new version.

test
  • Create an ACM certificate:

- Click on Request on the ACM console.

test

- Select Request a Public Certificate and click Next.

test

- Enter the Fully qualified domain name and select DNS validation for validation methods then click Request.

(Note: Please replace "example.com" with your domain.)

test
  • Create a CloudFront Distribution.

- Click on Create Distribution.

test

- Set the regional domain of the S3 bucket as the origin for CloudFront. Under Origin access, choose the Origin access control settings (recommended). Click on "Create new OAC" to establish an origin access control and choose it from the dropdown menu.

test

- Under Cache key and origin requests, select Legacy cache settings under Default cache behavior. In the Headers dropdown, select Include the following headers, and then add the Host header from the Add header dropdown. (Note: CloudFront changes the host header to the origin bucket’s regional domain name so caching the host header is important.)

- In Object caching, select Customize and set the following values:

Minimum TTL = 0

Maximum TTL = 31536000

Default TTL = 86400

test

- In Function association, select Lambda@Edge for Origin request and set function arn.

test

- In Setting add Alternate domain names like a.example.com, b.example.com, etc.. Then click on Create Distribution. (Note: You can use the * wildcard character instead of listing many subdomains.)

test
  • Create Route53 records for CloudFront domain:

- In Hosted zone console for example.com, click on Create record.

test

- Enter the record name, select Record type as A, check the Alias option, select Alias to CloudFront distribution, enter CloudFront distribution domain name, and click on Create records.

test

- Create a record for subdomain b in the same way.

Cost:

For 1 GB of storage and GET, SELECT, and all other requests from Cloudfront for a total of 10 million requests per month from all available regions with Lambda@Edge for edge computing:

(Note: The first 1024 GB/month of data transfer and 10 million requests/month are free in CloudFront therefore the request count for CloudFront is 20 million in total)

  • Data Storage in S3: 

1 GB of storage and 1 million GET, SELECT, and all other requests from Cloudfront to S3.

Cost: $0.42/month

  • Requests on CloudFront: 

20 million requests from each region with 1 GB of total data transferred to the internet in each region.

Cost: $126.50/month 

  • Lambda@Edge compute cost: 

512 MB of ephemeral storage, 128 MB of memory, and 1000000 requests/month.

Cost: $0.62/month

Total: $127.55/month

You can use the AWS pricing calculator to check the cost according to your usage

https://calculator.aws/#/

Here is the reference to content delivery based on subdomains using terraform

https://github.com/TechHoldingLLC/th-website-blogs-code-examples/tree/main/content-delivery-based-on-subdomains

References:

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-how-it-works-tutorial.html

More blogs

AI Agents: The Next Revolution

Dec 16, 2024 • 3 min read

Leadership in Downturn Economy

Jul 11, 2024 • 4 min read

AWS Certified Team

Tech Holding Team is a AWS Certified & validates cloud expertise to help professionals highlight in-demand skills and organizations build effective, innovative teams for cloud initiatives using AWS.

By using this site, you agree to thePrivacy Policy.