Mastering URL Redirections with AWS CloudFront Functions

Alexey Vidanov - Aug 29 - - Dev Community

Struggling with URL redirections for your AWS-hosted website? If you're using an S3 bucket as your origin, you might have noticed that S3 alone doesn’t support dynamic redirects via server-side rules. That's where AWS CloudFront Functions come in—offering a fast, simple, and cost-effective way to manage redirections. In this guide, we’ll show you how CloudFront can handle your URL redirections without requiring separate S3 buckets or CloudFront distributions, streamlining your architecture and improving your website’s SEO and user experience.

1. Introduction

URL redirection is essential for seamless navigation and improved SEO. When using S3 as a static website origin, implementing complex redirects directly through file configurations is not possible. AWS CloudFront Functions allow you to handle dynamic redirects at the edge, solving this limitation and removing the need for additional S3 buckets or separate CloudFront distributions just for redirection purposes.

Real-World Example: awsgem.com

A diagram illustrating an AWS architecture, with a client connected to Edge Locations, CloudFront Edge Caches, CloudFront Regional Edge Caches, CloudFront Functions, and an Origin S3 Bucket.

At awsgem.com, we faced challenges in managing URL redirections using S3 as the origin. We needed to efficiently handle traffic between www.awsgem.com and awsgem.com while maintaining clean URLs by redirecting paths like /canarycalc/ to /canarycalc/index.html without the need for multiple S3 buckets or CloudFront distributions.

By implementing CloudFront Functions, we achieved:

  • Efficient Subdomain Redirection: Redirected traffic between www and non-www domains without needing an extra S3 bucket or distribution.
  • Optimized Performance: Offloaded the redirection logic to CloudFront, reducing latency and server load.

2. The Challenges of URL Redirection

Common redirection challenges include:

  • Subdomain Redirection: Redirecting between www and non-www versions to avoid duplicate content, boost SEO, and maintain consistent branding.
  • Directory Handling: Redirecting paths like /canarycalc/ to /canarycalc/index.html to serve content correctly.

3. CloudFront Functions: Edge Computing Made Simple

CloudFront Functions, introduced by AWS in 2021, are a game-changer for handling lightweight edge computing tasks. They provide an efficient way to execute JavaScript code at the edge, closer to the end-user.

Key Advantages

  • Ultra-Low Latency: Executes in sub-millisecond timeframes
  • Cost-Effective: Pay only for the compute you use, with a generous free tier
  • Simplified Development: Write in JavaScript, deploy directly within CloudFront
  • Global Scale: Automatically deployed to all CloudFront edge locations worldwide
  • Stateless Execution: Designed for quick, contextual operations without need for external data

Use Cases

  • Implementing custom URL redirection logic
  • Normalizing query strings for improved caching
  • Adding or modifying HTTP headers for security or analytics purposes

Limitations

  • Limited to JavaScript
  • Maximum execution time of 1ms
  • No access to external services or databases

CloudFront Functions excel at tasks that require speed and simplicity, making them an ideal solution for many edge computing scenarios.

4. Breaking Down the CloudFront Functions Code

Below are two separate examples for managing non-www to www and www to non-www redirections, as well as handling clean URL redirection (e.g., /about/ to /about/index.html).

Example 1: Redirecting non-www to www

function handler(event) {
    var request = event.request;
    var headers = request.headers;
    var uri = request.uri;

    // Redirect non-www to www
    if (headers.host && !headers.host.value.startsWith('www.')) {
        var host = 'www.' + headers.host.value;  // Add 'www.'
        var location = 'https://' + host + uri;
        return {
            statusCode: 301,
            statusDescription: 'Moved Permanently',
            headers: {
                'location': { 'value': location },
                'strict-transport-security': { 'value': 'max-age=31536000; includeSubDomains; preload' },
                'x-content-type-options': { 'value': 'nosniff' },
                'x-frame-options': { 'value': 'DENY' },
                'x-xss-protection': { 'value': '1; mode=block' }
            }
        };
    }

    // Redirect to /index.html for directories
    if (uri.endsWith('/') || !uri.includes('.')) {
        request.uri = uri.replace(/\/?$/, '/index.html');
    }

    return request;
}
Enter fullscreen mode Exit fullscreen mode

Example 2: Redirecting www to non-www

function handler(event) {
    var request = event.request;
    var headers = request.headers;
    var uri = request.uri;

    // Redirect www to non-www
    if (headers.host && headers.host.value.startsWith('www.')) {
        var host = headers.host.value.substring(4);  // Remove 'www.'
        var location = 'https://' + host + uri;
        return {
            statusCode: 301,
            statusDescription: 'Moved Permanently',
            headers: {
                'location': { 'value': location },
                'strict-transport-security': { 'value': 'max-age=31536000; includeSubDomains; preload' },
                'x-content-type-options': { 'value': 'nosniff' },
                'x-frame-options': { 'value': 'DENY' },
                'x-xss-protection': { 'value': '1; mode=block' }
            }
        };
    }

    // Redirect to /index.html for directories
    if (uri.endsWith('/') || !uri.includes('.')) {
        request.uri = uri.replace(/\/?$/, '/index.html');
    }

    return request;
}
Enter fullscreen mode Exit fullscreen mode

Code Breakdown:

  • Subdomain Redirection: Each function example separately handles redirection between www and non-www domains. This eliminates the need for creating extra S3 buckets or distributions, simplifying your architecture while ensuring consistency for users and search engines.
  • Directory Handling: Automatically appends /index.html to directory requests like /about/ so content is served correctly.

Advanced Use Cases:

  • Retain Query Parameters: If query parameters (e.g., ?utm_source=google) are present, ensure they are retained during redirection:
  var querystring = request.querystring ? '?' + request.querystring : '';
  var location = 'https://' + host + uri + querystring;
Enter fullscreen mode Exit fullscreen mode
  • Path-Based Redirects: Implement custom path-based redirects by checking for specific URIs:
  if (uri.startsWith('/old-path')) {
      return {
          statusCode: 301,
          statusDescription: 'Moved Permanently',
          headers: {
              'location': { 'value': 'https://' + host + '/new-path' }
          }
      };
  }
Enter fullscreen mode Exit fullscreen mode

5. Step-by-Step Implementation

  1. Create an S3 Bucket as the Origin: Store your website files in an S3 bucket with static web hosting enabled.
  2. Set Up CloudFront: Create a CloudFront distribution with your S3 bucket as the origin.
  3. Add a CloudFront Function: Create separate CloudFront Functions for either non-www to www or www to non-www redirection, depending on your preference. Paste the respective code into each function. A screenshot of the AWS CloudFront console, showing a specific function named
  4. Deploy: Associate the function with the "Viewer request" event in your CloudFront distribution.

6. Testing and Validation

Test your redirections:

  • Visit yourdomain.com to confirm it redirects to www.yourdomain.com, or vice versa depending on your setup.

  • Access www.yourdomain.com/about/ and verify that /about/index.html is served correctly.

  • Test with various paths and query parameters to ensure they're handled correctly.

  • Use online redirect checkers to verify your setup from different locations.
    for example: https://www.redirect-checker.org/

  • Or using curl

curl -I -L http://example.com

A terminal window displaying the output of a curl command, showing HTTP requests and responses with details like status codes, headers, and content information. The response indicates that the request was redirected from the root URL to the / URL and then served a static HTML page from CloudFront.

7. Troubleshooting

Redirect Loops:

  • Issue: Endless redirection between www and non-www versions.
  • Solution: Ensure your origin (S3 or web server) isn't also performing conflicting redirects. Check your S3 bucket settings and any .htaccess files if applicable.

Function Errors (HTTP 500):

  • Issue: CloudFront returns a 500 error when the function is triggered.
  • Solution:
    1. Check the CloudFront console for logs and error messages.
    2. Use the "Test" feature in the CloudFront Functions console to debug your code.
    3. Adjust the logic, especially around headers or query parameters.

Cache Invalidation:

  • Issue: CloudFront caches incorrect redirects.
  • Solution:
    1. Use cache invalidation to refresh edge nodes.
    2. Adjust cache-control headers if necessary to avoid unintended caching.
    3. Consider setting a low TTL for your distribution during testing.

8. CloudFront and Cost Considerations

CloudFront Functions are highly economical, especially with the free tier covering 2,000,000 invocations monthly. Beyond the free tier, the cost remains minimal at $0.01 per 1,000,000 invocations. This makes CloudFront Functions an excellent choice for handling URL redirections and reducing server load without the need for extra resources.

9. SEO Impact of Proper Redirection

Proper URL redirection helps:

  • Avoid Duplicate Content: Ensures that search engines don't penalize your site for having duplicate content across www and non-www versions.
  • Preserve Link Equity: Redirecting outdated URLs preserves the SEO value of incoming links.
  • Enhance Crawl Efficiency: Search engines can better understand your website’s structure, leading to faster indexing and ranking improvements.

10. Comparison with Alternative Solutions

Feature CloudFront Functions Lambda@Edge Traditional Server-Side Redirects (Not Applicable with S3 Origin)
Execution Speed < 1ms 5-50ms Variable (typically slower)
Cost Very Low Low-Medium Depends on server resources
Complexity Low Medium Varies
Customization Limited High High
Scalability Automatic
10,000,000 requests per second or more
Automatic
Up to 10,000 requests per second per Region
Manual
Depends on server resources
Can build and test entirely within CloudFront Yes No No
Cold Starts No Yes N/A

11. Conclusion

CloudFront Functions provide a fast, cost-effective solution for handling URL redirections without needing additional S3 buckets or CloudFront distributions. This approach enhances your site's performance, simplifies architecture, and improves SEO. By implementing the strategies outlined in this guide, you can efficiently manage redirections, improve user experience, and optimize your AWS-hosted website.

12. Further Reading

Have you implemented this solution? We'd love to hear about your experiences or any unique challenges you've faced. Drop a comment below or reach out on Linkedin!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .