Skip to content

New Example: Enforce a domain name with redirects #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ CloudFront functions are ideal for lightweight computation tasks on web requests
|[Verify JSON Web Tokens](verify-jwt/)| This function performs a lightweight security token validation using JSON Web Tokens. You can use this type of tokenization to give a user of your site a URL that is time-bound. Once the predetermined expiration time has occurred, the user can no longer access the content at that URL.|
|[Add CORS headers if missing](add-cors-header/)| This function adds an `Access-Control-Allow-Origin` response header if it is not present on the outgoing response from CloudFront.|
|[Add a `Cache-Control` header](add-cache-control-header/)| This function adds a `Cache-Control` response header to the outgoing response from CloudFront for browser caching.|
|[URL redirect to enforce a domain name](enforce-domain-redirect/)| This function will redirect any request for a domain name other than the enforced domain to the enforced domain. The most common use is redirecting the apex or naked domain to the `www` subdomain.|

## Deploying a CloudFront function using the AWS CLI
We will use the example that adds cache control headers to responses as our function, but the same process can be used for all the functions with only minor changes.
Expand Down
85 changes: 85 additions & 0 deletions enforce-domain-redirect/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
## Redirect any host that is not the enforced domain

**CloudFront Functions event type: viewer request**

This function redirects all users to an enforced domain name. This ensures that all users are using your preferred domain name when accessing your site. The most common example of this is to automatically redirect the *apex* or *naked* domain to the *www* domain. When accessing through the enforced domain, this function does not perform any action.

**Important: Set the `enforceDomainName` constant to an appropriate value for your specific needs.**

**Testing the function**

To validate that the function is working as expected, you can use the JSON test objects in the `test-objects` directory. To test, use the `test-function` CLI command as shown in the following examples:

**Apex or naked domain redirect**

This test validates that a request to the `example.com` domain will be redirected to the `www.example.com` domain.

```shell
# Get the current ETag value
$ aws cloudfront describe-function --name enforce-domain-redirect
# Run the test
$ aws cloudfront test-function --if-match EXXXXXXXXXXXX --name enforce-domain-redirect --event-object fileb://enforce-domain-redirect/test-objects/apex-domain.json
```

If the function has been set up correctly, you should see a result similar to the following with the redirect being issued (`location` header being returned) in the `FunctionOutput` JSON object. Notice that the `value` is the `enforceDomainName` value:

```json
{
"TestResult": {
"FunctionSummary": {
"Name": "enforce-domain-redirect",
"Status": "UNASSOCIATED",
"FunctionConfig": {
"Comment": "",
"Runtime": "cloudfront-js-2.0"
},
"FunctionMetadata": {
"FunctionARN": "arn:aws:cloudfront::060232822672:function/enforce-domain-redirect",
"Stage": "DEVELOPMENT",
"CreatedTime": "2024-10-01T14:36:47.121000+00:00",
"LastModifiedTime": "2024-10-01T14:37:08.199000+00:00"
}
},
"ComputeUtilization": "6",
"FunctionExecutionLogs": [],
"FunctionErrorMessage": "",
"FunctionOutput": "{\"response\":{\"headers\":{\"location\":{\"value\":\"https://www.example.com\"}},\"statusDescription\":\"Moved Permanently\",\"cookies\":{},\"statusCode\":301}}"
}
}
```

**No redirect when using enforced domain**

```shell
# Get the current ETag value
$ aws cloudfront describe-function --name enforce-domain-redirect
# Run the test
$ aws cloudfront test-function --if-match EXXXXXXXXXXXX --name enforce-domain-redirect --event-object fileb://enforce-domain-redirect/test-objects/apex-domain.json
```

If the function has been set up correctly, you should see the `request` being returned as part of the `FunctionOutput` JSON object meaning that no action was taken.:

```json
{
"TestResult": {
"FunctionSummary": {
"Name": "enforce-domain-redirect",
"Status": "UNASSOCIATED",
"FunctionConfig": {
"Comment": "",
"Runtime": "cloudfront-js-2.0"
},
"FunctionMetadata": {
"FunctionARN": "arn:aws:cloudfront::060232822672:function/enforce-domain-redirect",
"Stage": "DEVELOPMENT",
"CreatedTime": "2024-10-01T14:36:47.121000+00:00",
"LastModifiedTime": "2024-10-01T14:37:08.199000+00:00"
}
},
"ComputeUtilization": "6",
"FunctionExecutionLogs": [],
"FunctionErrorMessage": "",
"FunctionOutput": "{\"request\":{\"headers\":{\"host\":{\"value\":\"www.example.com\"},\"accept\":{\"value\":\"text/html\"}},\"method\":\"GET\",\"querystring\":{},\"uri\":\"/index.html\",\"cookies\":{}}}"
}
}
```
20 changes: 20 additions & 0 deletions enforce-domain-redirect/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
function handler(event) {
const request = event.request;
const host = request.headers.host.value;
const enforceDomainName = "www.example.com";

if (host !== enforceDomainName) {
const response = {
statusCode: 301,
statusDescription: 'Moved Permanently',
headers:
{
location: { value: `https://${enforceDomainName}` },
}
}

return response;
}

return request;
}
17 changes: 17 additions & 0 deletions enforce-domain-redirect/test-objects/apex-domain.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"version": "1.0",
"context": {
"eventType": "viewer-request"
},
"viewer": {
"ip": "0.0.0.0"
},
"request": {
"method": "GET",
"uri": "/index.html",
"headers": {
"host": { "value": "example.com" },
"accept": { "value": "text/html", "multivalue": [ { "value": "text/html" }, { "value": "application/xhtml+xml" } ] }
}
}
}
17 changes: 17 additions & 0 deletions enforce-domain-redirect/test-objects/enforced-domain.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"version": "1.0",
"context": {
"eventType": "viewer-request"
},
"viewer": {
"ip": "0.0.0.0"
},
"request": {
"method": "GET",
"uri": "/index.html",
"headers": {
"host": { "value": "www.example.com" },
"accept": { "value": "text/html", "multivalue": [ { "value": "text/html" }, { "value": "application/xhtml+xml" } ] }
}
}
}