1

Background

I have a big repository that uses CRA React, and I need an SEO Feature in SSR. So I created a new NextJS 13 Repo and put only the page that needed the SEO Feature such as the Landing page in the NextJS. I want to implement an incremental adoption using the rewrite url so the user won't even notice the migration process.

What do I want to achieve?

I want to do a simple external URL rewrite: https://my-domain.com/company -> https://my-domain-legacy.com/company

Repositories and Infrastructure

So I'm creating an empty NextJS 13 with only index routing and deploying the NextJS with SST. I'm aware that NextJS provides a rewrites feature, but the external URL rewrite is not supported in SST currently, only the internal URL rewrites is supported.

Question

Do you have any suggestions as to what I can do to achieve what I want? Maybe an alternative to the SST library? Or how I can achieve this in LambdaEdge/CloudFront function?

What I have done so far?

I tried creating a simple internal URL rewrite in the LambdaEdge function:

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

    request.uri = request.uri
        .replace(/\/company$/,'/');

    return callback(null, request);
};

But I always get AccessDenied as a result when trying to access a page that isn't in the NextJS routing.

Edit 1:

Hi Dennis, this is my current function:

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

    // request.uri = request.uri
    //     .replace(/\/company$/,'/');
    request.origin.custom.domainName = "https://my-domain-legacy.com"
    

    return callback(null, request);
};

enter image description here

I tried to use the above code for my lambda function, but I get this error.

Current Lambda@Edge permission: enter image description here

Michael Harley
  • 831
  • 1
  • 9
  • 20

2 Answers2

0

Double-check the following line in your Lambda@Edge function:

request.uri = request.uri.replace(/\/company$/,'/');

Your current function replaces the path, not the domain. https://my-domain.com/company becomes https://my-domain.com/, while, according to your question, you want it to be https://my-domain-legacy.com/company.

Having that said, you can implement a proper redirect, including the HTTP code. There's an example in the AWS Networking & Content Delivery blog.

Dennis Traub
  • 50,557
  • 7
  • 93
  • 108
  • 1
    Ah yes, for the starter I want to try the internal rewrite, but I still getting AccessDenied. I tried to figure out how to show my `console.log(event)`, but I seem to have a hard time. I would love to try changing the domain directly, but since I don't know the `event` structure for the domain part I can't change the domain. But after you point that out, I just remembered that I can see the event structure from https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html. I will try to look into your shared article, thanks! – Michael Harley Aug 11 '23 at 11:41
  • Sounds good. Let me know if you still don't get it to work. – Dennis Traub Aug 11 '23 at 11:46
  • I just read the article that you shared. The example is for Redirection, and I don't want to redirect to a new URL. What I want to achieve is a URL rewrite to an external URL. Do you have any suggestions as to how to achieve that? Maybe with a code example? :bows: – Michael Harley Aug 11 '23 at 11:46
  • I just updated my answer and gave the updated snippet code, hopefully, this could work! Can I ask about the cache for Origin Request as well? Does the cache behaviour reset whenever I deploy a new CloudFront? – Michael Harley Aug 11 '23 at 11:53
  • Thanks for the update. It looks like there's an issue with the Lambda function's IAM permissions. Here's a good starting point: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-permissions.html – Dennis Traub Aug 11 '23 at 12:17
  • I will look into that, thanks! Just saw that my lambda permission is only for logging purposes. I'm not sure what permission should I get for the code above to work tho. – Michael Harley Aug 11 '23 at 12:20
  • I tried adding `"lambda:GetFunction", "lambda:EnableReplication*", "iam:CreateServiceLinkedRole"`, but still getting the same error. Checked on the lambda that the permission is already attached. The trust relationship is already added as well. – Michael Harley Aug 11 '23 at 12:34
  • This is hard to troubleshoot without being able to have a look at the specific configuration. If you have a look at the Lambda function in the AWS Management Console, does it have CloudFront as a trigger? If yes, can you try to manually remove the trigger and add it again? – Dennis Traub Aug 11 '23 at 12:50
  • No, I can't, but I can re-deploy it and it will show up again. Will try to manually remove that after it shows up and re-adding it again. – Michael Harley Aug 11 '23 at 13:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/254889/discussion-between-michael-harley-and-dennis-traub). – Michael Harley Aug 11 '23 at 13:13
0

I have successfully done a rewrite to an external URL (different domain).

This is my lambda@edge function:

const domainName = "my-domain-legacy.com";

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;
    const newRequest = rewriteRequest(request);
    return callback(null, newRequest);
};

function rewriteRequest(request) {
    const newRequest = JSON.parse(JSON.stringify(request));
    newRequest.headers["host"] = [
        {
            "key": "Host",
            "value": domainName
        }
    ];
    newRequest.origin = {
        "custom": {
            "customHeaders": {},
            "domainName": domainName,
            "keepaliveTimeout": 5,
            "path": "",
            "port": 443,
            "protocol": "https",
            "readTimeout": 30,
            "sslProtocols": [
                "TLSv1",
                "TLSv1.1",
                "TLSv1.2"
            ]   
        }
    };
    return newRequest;
}

reference: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-examples.html#lambda-examples-content-based-custom-origin-request-trigger

Michael Harley
  • 831
  • 1
  • 9
  • 20