Hosting static assets on AWS

4/15/2022 9 minutes

How to set up a free CDN for your self-hosted website?

Why would you want to do this?

As you may, or may not, know, this website is self-hosted on my home kubernetes cluster (as of December 2022) which is underpowered to say the least. While the home cluster has been an amazing learning opportunity, and I have intentionally avoided service providers to not give myself the easy way out, there are still something that’s better handled by them to keep the user experience enjoyable and snappy.

For example, pictures!

drawing of the Abarat Archipelago

I love this picture, I don’t even know what it really is, other than what I gather from a Google image search ( It’s from a manga series called ‘One Piece’ and that it’s publicly available for fair use under the CC license). If I wanted to share this photo, I could store it in the database or somewhere behind a web server like NGINX, and have my k8 cluster serve it up everytime I want to look at the photo. Sure, but there’s a couple problems with that.

  1. My home cluster is not beefy.
  • It’s 5 Pine64 Rock64’s I got for $20 a pop a long time ago, each with only 2Gb of precious RAM.
  1. My home cluster is just that, in my home.
  • Someone looking at my site (unlikely) on the West Coast will likely sprout a couple gray hairs before this picture loads.
  1. Life is too short to not try new things.

The Solution, Amazon Web Services.

So instead of rocking the roll-your-own method, for once we’re going to try AWS by creating a free CDN for our website.

By the end of this, we’ll have a fast, distributed method to deliver static content to support our site.

*BEWARE! AWS operates on a pay-as-you-go model, you could be left with a big bill if you don’t

monitor your usage and set up a budget through the AWS console*

How to

1. Register with AWS

head over to https://aws.amazon.com/console/ and sign up for an account.

  • Heads up, you’ll need a credit card to associate with account during the registration process.

2. Activate MFA (optional)

To protect your account, I recommend setting up multifactor authentication (MFA) via the security credentials page.

activating multi facot authentication

3. Create an S3 bucket

Amazon described their Simple Storage Service (S3) as such

an object storage service that offers industry-leading scalability, data availability, security, and performance.

To over simplify, just think of S3 as the place we’ll actually store our content. that’s its only job.

  • From the AWS console homepage, bring up the Services menu from the top left. Scroll down to Storage, and select S3. activating multi facot authentication

  • Click Create Bucket and enter a Bucket Name. The name must be unique amongst all of AWS, and you should choose a DNS-compliant name since this name will be part of the URI to access the bucket.

  • Choose a region that’s close to you for now.

  • Scroll down to the card titled Block Public Access settings for this bucket

    • Uncheck block all public access
    • Check the acknowledgement
    • ponder the risks

activating multi facot authentication

4. Setup AWS CloudFront

At this point, we’ve created a way to store or static content, but we don’t have a good way to access it.

Enter AWS CloudFront

  • From the AWS console homepage again,
    • Select the Services dropdown
    • Scroll down to Networking & Content Delivery
    • Click CloudFront

activating multi facot authentication

  • On the next page, take a moment to read the AWS free tier limits and select Create a CloudFront Distribution
    • From the Origin domain select your recently made s3 bucket
    • Scroll down, click the radio boxes next to…
      • redirect HTTP to HTTPS
    • You can leave the remaining defaults for now.
    • Scroll to the bottom to Create Distribution
    • Copy the Distribution domain name to your new CloudFront and save it for later.

activating multi facot authentication

5. Create an IAM User/Group

At this point, our CDN is set up, but we need to create a way to access our content via AWS’ Identity and Access Management (IAM) service.

To quote AWS…

AWS Identity and Access Management (IAM) is a web service that helps you securely control access to AWS resources. You use IAM to control who is authenticated (signed in) and authorized (has permissions) to use resources.

  • From the AWS console homepage again,
    • Select the Services dropdown
    • Scroll down to Security, Identity, & Compliance in the left menu.
    • Click IAM

activating multi facot authentication

  • After page load, select user from the left menu, and click Add User
  • Create a new IAM user
    • Add a username
    • Click the check next to Access key - programatic access
    • click next

activating multi facot authentication

  • Create a new group and add our new IAM user
    • If you’re familiar with *nix groups, these act just like that.
    • give the group a descriptive name
    • use the filter bar to add two security policies to your new group AmazonS3FullAccess & CloudFrontFullAccess
    • Add the new user to the group and create the user

activating multi facot authentication

  • After you successfully create the user, a page will show your new user’s Access ID and Key.
    • Copy these and store them in a safe place. They will not be visible after leaving this page.

6. Install the AWS CLI

Before we add content to our freshly configured S3 bucket, we are going to install the AWS Command Line Interface.

Check out the AWS CLI documentation for the most up-to-date instructions on installing the AWS CLI on your OS.

Check the cli installation

$ aws --version

Next, we need to log in our CLI client using the Access key and Private key we copied earlier. To do this, we’ll run aws configure:

$ aws configureAWS Access Key ID [None]: YOUR_ACCESS_KEYAWS Secret Access Key [None]: YOUR_SECRET_KEY Default region name [None]: e.g: us-east-1 Default output format [None]: LEAVE_BLANK

If nothing goes wrong, you should be logged in as your new IAM user with access to your swanky new S3 bucket.

7. Sync your Images

It’s time to upload our content, lets sync a local directory to our S3 bucket.

We can use the aws s3 sync to keep a local directory synced with our s3 bucket

$ aws s3 sync /path/to/dir/with/images/ s3://[YOUR_S3_BUCKET_NAME]/images --delete --exclude ".*"

Replace the path to your directory and the name of you s3 bucket followed by the path you’d like to be to access the content (e.g., /images).

8. Congrats

That’s it! You should now be able to access* your content at the cloudfront URL that we copied earlier. For us, it was https://d1738nvaauqo1n.cloudfront.net, so if we wanted to access our images/floating_nature.jpg from our fresh CDN, we would navigate to https://d1738nvaauqo1n.cloudfront.net/images/floating_nature.jpg

9. Troubleshooting AccessDenied errors

After initially creating my CDN, I received an AccessDenied Error in XML format. To get around this, navigate to your new S3 bucket, go to the Permissions Tab, and scroll down to the Bucket Policy section and create a new policy in JSON format.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::dpgraham-sss-test/*"
    }
  ]
}

replacing dpgraham-sss-test with your bucket’s name.

*Note, it may take some time before you can actually view your content. I’ve heard as short as 25 minutes, but it may take longer.