Create your own short link redirects using CloudFront + S3

Get branded short links under your own domain for dirt-cheap by self-hosting it on AWS using CloudFront + S3. It's a no-code server-less solution to get redirects on the cheap and in this guide, I'll detail how to set it up. If you're interested in some good reasons why - check out my first post on it here.

In this guide, I'll go over

  • what do our redirects/short links need to be able to do
  • how to set it up via the console if thats what you're comfortable with, or doing it via the AWS node SDK.
  • How to check that its working
  • A few things to check when it doesn't (it never really works the first time, doesn't it?)

What do we need out of our short links?

  • I need to be able to create custom links to redirect
  • I need to be able to change them later
  • I want to see traffic to the redirect, and how many times they've been clicked (this will be part of another post)

Technical Requirements:

  • Highly Available, Redundant (99.9% SLA)
  • Serve HTTPS 301 redirects
  • Serverless. Cloudfront + S3 means we don't have any servers to manage.

This is the architecture we're going to set up on AWS:

cloudcraft diagram showing cloudfront + s3 with replication

In short, we have...

  • a CloudFront CDN which gives us free HTTPS for our domain (courtesy of AWS Certificate Manager)
  • An S3 bucket with Cross-Replication enabled to another bucket in another region
  • Each redirect is stored as an object with the Website-Redirect-Location metadata pointing to our redirect

Setting it up via the console

Step 1: Set up Cloudfront + S3

I've set up this diagram for one of my domains - so I'll show you how I've set that up.

registered domains on Route53

I own using Route53 as my registrar. You don't need to have your domain on AWS Route53 if you want to host your short links on AWS - if you have one already via something like GoDaddy or Namecheap, thats fine too, you can use that.

Cloudfront will be providing an HTTPS URL that we can use using S3 as an origin which will serve our redirects. Cloudfront will have its logs piped to another bucket, and we can get some metrics out of that.
cloudfront properties

s3 origin properties

An S3 bucket will be used to store the actual redirects.

For an in-depth guide on setting up those 2 services, you can check out my post which walks you through setting up via the console or if you want to set it up with terraform.

Once you have Cloudfront deployed and connected to your S3 bucket, we can add our redirects.

Step 2: Add a redirect

Create an empty file and upload it to the console, with Website-Redirect-Location metadata pointing to the URL you want to redirect to. In this case, I've uploaded an empty file named not-a-rick-roll and added the metadata to point to a particular YouTube video.

You can use the default permissions, default storage type, and no need for encryption.

aws s3 upload file with metadata screen

In the screenshot, you'll see theres a warning under the Metadata header - You cannot modify object metadata after it is uploaded. I'm sure theres a reason this is included, but I've been able to just go into the object's metadata and change the values from the screen below.

s3 object and metadata

By default, S3 will add a Content-Type metadata to your object when you upload it. So you can see in the screenshot that the Content-Type has been set to binary/octet-stream which implies this link will return some file. Its worth noting in this case, that by adding the Website-Redirect-Location metadata to your object, S3 will serve up a HTTP 301 Redirect to your target redirect - a 301 response only needs to include a Location header specifying the redirect. So it doesn't quite matter what the Content-Type is on your object. You can leave it alone, or delete it.

Thats it! Assuming you have many more of these, you can even automate the creation of your redirects.

Step 3: Automating it

If you use the CLI, you can script it using the AWS CLI - aws s3 cp not-a-rick-roll s3:// --website-redirect ""

If you have your redirects stored in a CSV, you can parse it and upload it using the node aws-sdk - check out this example:

# redirects.csv

// redirects.js

const parse = require('csv-parse/lib/sync')
const fs = require('fs')
const AWS = require('aws-sdk')
const s3 = new AWS.S3();

const redirects = parse(fs.readFileSync('redirects.csv'))
redirects.forEach((redirect) => {
    console.log('Uploading ', redirect)
        Body: '',
        Bucket: '',
        Key: redirect[0],
        Metadata: {
            'Website-Redirect-Location': redirect[1]
    }, (err, data) => {
        if (err) return console.log(err)

Verify your redirects

You can check to see that its working by using good ol' curl to make a request to your site -, and verify that you get back a 301 redirect for that object. This is what the output of that command looks like:

☁  intricate-web  curl -i
HTTP/2 301
content-length: 0
date: Sun, 22 Sep 2019 01:52:57 GMT
server: AmazonS3
x-cache: Miss from cloudfront
via: 1.1 (CloudFront)
x-amz-cf-pop: EWR53-C1
x-amz-cf-id: rNwzh3rL-ErWpi0YuDrqQcCvvmbqa_ZWj7cPl71WrPPi1vlFbW0siA==

You now have URL redirects served out of your own domain so you can do things like (check it out - its totally not a rick roll 😎)


If you change a redirect and you don't see it taking effect, there might be one of two things happening:

  • If you're trying this in your browser, you might have a cached version of the redirect. Open an incognito window and try it there.
  • Cloudfront is still sending you back a cached version of the redirect. You'll have to use curl to inspect the request so you can see whats happening.
☁  intricate-web  curl -i
HTTP/2 301
content-length: 0
date: Sun, 22 Sep 2019 01:52:57 GMT
server: AmazonS3
x-cache: Hit from cloudfront
via: 1.1 (CloudFront)
x-amz-cf-pop: EWR53-C1
x-amz-cf-id: 7pDL0XgVjGmdMqcHf7tSsRILd0WfZpihpLF66SYVJLlzqfCJG2PMRg==
age: 4

In this example, we want to pay attention to the x-cache & age response header. In this case, it says Hit from cloudfront and the age == 4. The age is the time that object has been in the cache. If you've updated your redirect recently, and you're still seeing an old redirect in your response headers, then you'll need to invalidate your Cloudfront cache. You can do that from the Invalidations page

the Invalidations page

You'll know it updated when the age response header shows something recent.

There you have it! By this point, you should have your own domain sending you back redirects that you can monitor yourself. Now, this isn't the whole story because theres still a feature or two that we need to set up.

Tags: ,

You might be interested in…