How to Fix S3 Website Redirect Location Not Working with CloudFront Distribution


2 views

When migrating from WordPress to S3 static hosting, many developers use S3's Website Redirect Location metadata for seamless 301 redirects. However, these redirects break when accessed through CloudFront, with empty files being downloaded instead.

S3 offers two distinct endpoint types:

1. REST API endpoint (bucket.s3.amazonaws.com)
2. Website endpoint (bucket.s3-website-region.amazonaws.com)

CloudFront by default uses the REST endpoint which doesn't process website redirect rules. The website endpoint is required for redirect metadata to function.

Update your CloudFront origin settings:

Origin Domain: [your-bucket].s3-website-[region].amazonaws.com
Origin Path: (leave empty)
Origin Type: Custom Origin (NOT S3 Origin)

Add these critical settings:

Protocol Policy: HTTP Only (S3 website endpoints don't support HTTPS)
HTTP Port: 80
HTTPS Port: 443

For advanced routing needs, consider this Lambda@Edge solution:

exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const uri = request.uri;
  
  // Custom redirect mapping
  const redirectMap = {
    '/solution': '/product.html',
    '/old-blog': '/new-articles'
  };
  
  if (redirectMap[uri]) {
    return {
      status: '301',
      headers: {
        'location': [{
          key: 'Location',
          value: redirectMap[uri]
        }]
      }
    };
  }
  
  return request;
};

For preserving SEO value:

  • Always use 301 (permanent) rather than 302 redirects
  • Maintain identical query parameters in redirects
  • Implement proper cache headers (recommended 24h for redirects)

Test your setup with:

curl -I https://your-distribution.cloudfront.net/solution
# Should return HTTP/301 with Location header

For existing distributions, remember to invalidate affected paths:

/solution
/product.html

When configuring S3 static website hosting with CloudFront, many developers encounter this specific issue:


# S3 object metadata (works when accessed directly)
Website Redirect Location = /product.html

This metadata creates a 301 redirect when accessed through S3 website endpoints (s3-website-[region].amazonaws.com), but fails when the same object is accessed through CloudFront, where the empty file gets downloaded instead.

The root cause lies in how CloudFront interacts with S3:

  • CloudFront treats S3 as an origin server, not a website endpoint
  • The x-amz-website-redirect-location header only works with S3 website endpoints
  • When using CloudFront, requests go to S3's REST API endpoint, not the website endpoint

Solution 1: Lambda@Edge for Redirect Handling

This is the most flexible approach:


exports.handler = async (event) => {
    const request = event.Records[0].cf.request;
    const uri = request.uri;
    
    // Create your redirect mapping
    const redirectMap = {
        '/solution': '/product.html',
        '/old-page': '/new-page.html'
    };
    
    if (redirectMap[uri]) {
        return {
            status: '301',
            statusDescription: 'Moved Permanently',
            headers: {
                'location': [{
                    key: 'Location',
                    value: redirectMap[uri]
                }]
            }
        };
    }
    
    return request;
};

Configure this Lambda@Edge function on Viewer Request event.

Solution 2: CloudFront Function (Lightweight Alternative)

For simpler cases with smaller redirect sets:


function handler(event) {
    var request = event.request;
    var uri = request.uri;
    
    var redirects = {
        '/solution': '/product.html',
        '/blog': '/articles.html'
    };
    
    if (redirects[uri]) {
        return {
            statusCode: 301,
            statusDescription: 'Moved Permanently',
            headers: {
                'location': { value: redirects[uri] }
            }
        };
    }
    
    return request;
}

Solution 3: S3 REST API Workaround

For those who prefer not to use Lambda:

  1. Create a dummy HTML file with meta refresh
  2. Set appropriate Cache-Control headers
  3. Use CloudFront behaviors to handle specific paths


<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="refresh" content="0; url=/product.html">
</head>
</html>

All three solutions maintain SEO value:

  • 301 redirects preserve link equity
  • No chain redirects that might dilute SEO value
  • Proper canonicalization of URLs
Solution Latency Impact Cost Maintenance
Lambda@Edge ~50-100ms $$ Medium
CloudFront Function ~1-2ms $ Low
S3 Workaround None $ High

For most production scenarios, we recommend:

  1. Start with CloudFront Functions for simple redirects
  2. Upgrade to Lambda@Edge when you need more complex logic
  3. Monitor redirects using CloudFront access logs