Host your Content on a Private CDN to be Used in NextJS, with AWS S3 and CloudFront

Embedded Nature
6 min readDec 14, 2022
Photo by Saad Chaudhry on Unsplash

Overview

When developing web applications, you may want to use scripts to support the functionality and styles of your site; or add 3rd party scripts for analytics, ads, and widgets.

In this guide, I will show you how to leverage scripts in NextJS and teach you how to serve content from a self-managed CDN on Amazon Web Services.

If you aren’t using NextJS, you will still benefit from the AWS steps; I’ll show you how to build a CDN for multiple use cases.

Assumptions

I assume you have a basic understanding of web apps and AWS.

What is a CDN

A content delivery network or CDN is a network of edge servers in multiple geographical locations at once; CDNs are used to deliver digital content to users as fast as possible. To minimize the distance between the visitors and your website’s server, a CDN stores a cached version of its content and allows for the quick transfer of assets needed for loading content like HTML pages, javascript files, stylesheets, images, and videos.

Illustration of Edge Servers

What is S3

Amazon S3 is an object storage service that stores data as objects within buckets. S3 stands for Simple Storage Service due to its scalability, data availability, security, and performance. Amazon S3 also provides management features to help optimize, organize, and configure access to your data based on your requirements. Industry use cases of S3 include; data meshes, data lakes, mobile apps, websites, backup and restore, archive, Internet of Things, and big data analytics.

What is CloudFront

Amazon CloudFront is an AWS version of a content delivery network (CDN). CloudFront ensures that data is distributed globally with the highest performance possible. CloudFront adds AWS built-in features to your CDN to put you in control. Features include; real-time reporting and monitoring of CDN metrics, layered security perimeter, blue and green deployments, lambda@edge for a wide range of uses, and access control with Signed URLs and Signed Cookies.

Setup Scripts in NextJS

Adding scripts to your web application can decrease loading performance and impact your users experience. With NextJS, you can load scripts in a single route or for all routes.

Sometimes it can be tough to know where to load scripts in your application without impacting page performance. With NextJS, scripts will load and execute when any route in your application is accessed; it is smart enough to load once, even if your user navigates between multiple pages.

Import

Within a specific page or at the application level, import the next/script component:

import Script from 'next/script'

Usage

next/script supports added functionality to load your script before page hydration, after page hydration, later during browser idle time, or in a web worker.

import Script from 'next/script'

export default function MyApp({ Component, pageProps }) {
return (
<>
<Script src="https://code.jquery.com/jquery-3.6.0.min.js" strategy='beforeInteractive' />
<Script src="https://my.cloudfront.net/js/plugins.js" strategy='beforeInteractive' />
<Component {...pageProps} />
</>
)
}

Head over to the next/script documentation to learn more about each strategy.

You can reference any number of scripts within your NextJS application; now, I’ll show you how to create a private CDN on AWS.

Creating a CDN on AWS

To create a distribution on AWS it involves a few steps;

Create an S3 Bucket

On the S3 management console, create an AWS S3 bucket with the CDN name of your choice(e.g. cdn.myname.com) and select a region; I’d recommend the location closest to your web application.

As of writing, AWS should now block all public access but double-check to ensure you disable all public access.

Create a s3 bucket in AWS

You can configure the other settings or leave them as default, then scroll down to create the bucket.

S3 Bucket Policy

With the bucket created, navigate to the permissions tab of your bucket to view the bucket policy.

S3 Permissions Screen

With CloudFront your permissions will look similar to this:

{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::cdn.mydomain.com/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::5990006:distribution/EF489KLS0K"
}
}
}
]
}

In the steps below, I’ll show you how CloudFront auto-generates this policy for you, but first, lets add some files to your s3 bucket.

Side Note: If you plan to allow users to navigate to your pages. You will need to enable static website hosting under the properties tab.

Add Files to S3

On the Objects tab, you can upload files to your bucket. I recommend starting with a basic index.html. Additionally, you can add subfolders for things like assets and JS scripts.

S3 Object Upload Screen

After the file has been uploaded, click on one to view the object details, navigate to the Object URL and verify you can not access it from the web browser.

Access Denied to S3 Object

Next, we will set up our CloudFront Distribution and lock down access to your s3 bucket only through CloudFront.

Create a CloudFront distributions

On the S3 management console, head over to CloudFront and click “Create Distribution”. In the dropdown, you will see your bucket; select it.

Side Note: you may want to add a load balancer to cache requests.

Under Origin Access, select Origin access control settings (recommended) to restrict bucket access to only the CloudFront URLs; this will disable access via the s3 origin URL.

Redirect HTTP to HTTPS should be enabled by default; this will ensure all your requests are over SSL.

CloudFront Settigs

You can configure additional settings based on your requirements; at the bottom of the page, click “create a distribution”; it will take some time to finish.

Test your Endpoint

CloudFront will auto-create the policy with the access identity needed to get your s3 objects. (You can validate this by checking the s3 permission policy)

Under CloudFront distribution, it will give you an endpoint domain name to access your file. (e.g. mynewurl.com/file.html)

CloudFront Distribution Settings

And that’s it 🎉! You have a CloudFront distribution for your s3 content.

Add Your URL to NextJS

The path of your object becomes the source in your next/jsscript.

<Script src="https://my.cloudfront.net/js/plugins.js"/>

Own your URLs

One last thing. If you want to use your domain for your assets, you can add an alternative domain name to AWS CloudFront, but it requires you to register the domain name first.

In the AWS Management Console and open the CloudFront console

  1. Choose the ID for the distribution that you want to update.
  2. On the General tab, choose Edit.
  3. Under Alternate domain name (CNAME) — optional. Add your alternate domain names. Separate domain names with commas, or type each domain name on a new line.

Alternative Approach

Head over to your domain providers DNS setting and add a CNAME record:

name = s3 bucket | target = s3 object domain name

You will need to update the policy to allow the s3 bucket to be accessed from the origin URL. I recommend you lock down your s3 bucket policy to specific IP addresses. Your policy would look like this:

{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.example.com/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"192.2.0.1"(example IP address),
"192.2.0.2"(example IP address),
(add all IPs required)
]
}
}
}
]
}

Wrap Up 🎉

I hope this guide has helped you understand how to leverage scripts in NextJS and how to serve content from a self-managed CDN on Amazon Web Services.

If you found this guide helpful, I’d appreciate applause 👏😃.

I’d enjoy hearing about your experience on social media or in the comments below.

Feel free to reach out if you’d like some help.

Twitter | Instagram | Discord

--

--

Embedded Nature

Through the web 🌍 I strives to positively influence 🔋 and empower lifestyles 🦾 via emerging technologies.