2
votes

My goal is to host a version of a website for every branch we have in Git. I have the following setup, which seems to work mostly as expected:

  1. S3 Bucket with a directory for each build
  2. A GitHub Actions job that builds the application when files change, and deploys the code to the appropriate directory in the S3 bucket
  3. A CloudFront distribution for websites that sits on top of the S3 bucket. It uses a wildcard certificate and a Lambda@Edge Viewer Request function that converts the subdomain of the request to the URI path (https://branch.dev.company.com/ -> dev.company.com/branch/index.html). I needed to do this since the developers have written the application with redirects internally with absolute URIs.

Normally for a single page app, I would set a custom 403 response to direct to /index.html Since I have multiple index.html pages in different places, I don't know how do direct that to the appropriate index.html. It feels like I need an option to redirect to %SITE_URL%/index.html

1

1 Answers

2
votes

This is your lucky day!

https://github.com/marksteele/edge-rewrite

This project aims to provide a mechanism for running URI/URL rewriting capabilities leveraging Lambda@Edge. In the case where you are deploying your website behind CloudFront, you can now rewrite URLs at the CDN edge and avoid wasted CPU cycles on your backend servers.

The rule format is similar to the format used by mod_rewrite.

<REGEX> <OPTIONAL REPLACEMENT> [<FLAGS>]

The first part of a rule is a regular expression, followed by an optional new path or URL and optional flags.

In your case you want to URL Rewrite:
https://branch.dev.company.com/

Into this new URL:
https://dev.company.com/branch/index.html

So now comes the hard part, the RegEx! Fortunately the rule format by Edge-Rewrite is similar to the format used by mod_rewrite and I was able to find this mod-rewrite subdomain to path in primary domain

Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /

RewriteCond %{HTTP_HOST} ^sub\.company\.com$ [NC]
RewriteRule ^ http://company.com/sub%{REQUEST_URI} [R=301,L,NE]

The above should help to craft something like the example showed:

^/oldpath/(\\d*)/(.*)$ /newpath/$2/$1 [L]

Alternatively, a faster, easier, more readable and maintainable way is to write the redirect yourself. I customised this code for you based on this excellent article: https://faragta.com/aws-cloudfront/rewrite-url.html:

  'use strict';
    exports.handler = (event, context, callback) => {
        
        // Get request from CloudFront event  
        var request = event.Records[0].cf.request;
    
        // Extract the URI from the request
        var requestUrl = request.uri;
    
        // Rewrite the Subdomain to a Route to redirect to a different Branch
        var n = requestUrl.indexOf(".");  
        const protocolLen = 7;   //"https://"
        var branch = requestUrl.substring(protocolLen + 1, n - 1);  
        redirectUrl = requestUrl.substring(0, protocolLen) + requestUrl.substring(protocolLen + branch.length + 1) + branch + "/index.html";  

        // Replace the received URI with the URI that includes the index page
        request.uri = redirectUrl;
        
        // Return to CloudFront
        return callback(null, request);
    };