Using Lambda to rewrite URLs for Hugo

Jenn - Aug 18 '20 - - Dev Community

Hugo by default uses pretty URLs which work out of the box in most hosting environments. Using AWS Cloudfront in front of S3 causes it to not automatically translate pretty urls.

Instead of setting uglyurls = true in your site config, use AWS Lambda to translate for you.

There are example Lambda@Edge functions out there, I used this Medium post and an old AWS Compute Blog to build my function.

'use strict';
const path = require('path')
exports.handler = (event, context, callback) => {
    // Extract the request from the CloudFront event that is sent to Lambda@Edge 
    var request = event.Records[0].cf.request;
    // Extract the URI from the request
    var olduri = request.uri;
    // If last element of old uri doesn't contain a .html extension, assume it's a directory and append a '/'
    if (!olduri.match(/\/$/) && path.basename(olduri).match(/^[^\.]+$/)){
        olduri = olduri + '/';
    }
    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');
    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);
    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;
    // Return to CloudFront
    return callback(null, request);
};

The main gotcha is you may get this weird looking error when publishing the function if you are using the web interface.

Your function's execution role must be assumable by the edgelambda.amazonaws.com service principal.

Lambda can create an IAM role for you, but you still have to go into the newly created role and edit the Trust relationships policy document to allow Lambda@Edge access.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "lambda.amazonaws.com",
          "edgelambda.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

After editing the policy document for trust relationships, REFRESH the tab/window you are publishing the function from to force it to see the new permissions.

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