Hexo Serverless (part cinq)

This document is a continuation of Putting the Hexo CMS into a Serverless world, part 2, part 3 and part 4.


So far we can securely visit our website, but all of the links except the homepage are broken.

The issue that that CloudFront does not pass the default object root of “index.html” beyond the root level domain. This means that when you request a subdomain, it is looking for that object in S3 as defined and does not append “/index.html” to the request. We need AWS Lambda@Edge on our AWS CloudFront Distribution to fix this.

First, let’s create an execution role that can run our code as well as log for us in iam.tf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
resource "aws_iam_role" "lambda_edge_execution" {
name = "lambda_edge_execution"

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

resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
role = "${aws_iam_role.lambda_edge_execution.name}"
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy" "lambda_edge_execution" {
name = "lambda_edge_execution"
role = "${aws_iam_role.lambda_edge_execution.id}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:*:*:*"
]
},
{
"Effect": "Allow",
"Action": [
"lambda:GetFunction",
"lambda:InvokeFunction",
"lambda:EnableReplication*"
],
"Resource": [
"${aws_lambda_function.cloudfront_rewrite.arn}:*"
]
},
{
"Effect": "Allow",
"Action": [
"cloudfront:UpdateDistribution"
],
"Resource": [
"${aws_cloudfront_distribution.serverless_hexo.arn}"
]
}
]
}
EOF
}

We’ll also need the lambda function via the archive provider using the archive_file resource. Add the following content to a new file named lambda.tf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
data "archive_file" "rewrite" {
type = "zip"
output_path = "${path.module}/.zip/rewrite.zip"
source {
filename = "lambda.js"
content = "${file("${path.module}/lambda.js")}"
}
}

resource "aws_lambda_function" "cloudfront_rewrite" {
filename = "${path.module}/.zip/rewrite.zip"
function_name = "cloudfront-rewrite"
role = "${aws_iam_role.lambda_edge_execution.arn}"
handler = "lambda.handler"
source_code_hash = "${data.archive_file.rewrite.output_base64sha256}"
runtime = "nodejs8.10"
publish = true
}

Create a file for the code AWS Lambda will execute called exports.js with the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
'use strict';

const path = require('path');

exports.handler = (event, context, callback) => {
const { request } = event.Records[0].cf;
if (!path.extname(request.uri)) {
console.log(`Received ${request.uri}`);
if (!request.uri.endsWith('/')) {
request.uri += '/';
}
request.uri += 'index.html';
console.log(`Rewriting to ${request.uri}`);
}
return callback(null, request);
};

Run a final terraform apply and grab something to eat. This will take about 15 minutes.

Now you can use Hexo to generate content for your web site, store it in AWS S3, secure it via AWS ACM and serve it from AWS CloudFront. No servers involved and you only pay for what you use! Win.

For more information about Hexo and how to generate new content for your website, visit the official Hexo website. An example of the commands needed to generate a new page and update it on AWS S3 would be:

1
2
3
hexo new post "My new serverless website!"
hexo generate
aws s3 sync public/ s3://mydomain.com/

It will take some time to update throughout the internet as we are serving the content from a Content Distribution Network via AWS CloudFront.

I hope this document has proved useful for managing your serverless environment in code.

A quick start without Terraform Remote State, KMS or CloudFront (follow the tutorial if you needed) is located at https://github.com/Spechal/aws-serverless-hexo

-Travis