Create your own short link redirects using CloudFront + S3 
Tags: aws, webdev
Published: 2019-10-01 19:14:17

---
title: Create your own short link redirects using CloudFront + S3 
published: true
description: An in-depth guide on setting up your own world-class redirects for cheap using AWS CloudFront + S3
tags: aws, webdev
cover_image: https://thepracticaldev.s3.amazonaws.com/i/jllen5aqchkgvl7edauu.png
canonical_url: https://www.intricatecloud.io/2019/09/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](https://www.intricatecloud.io/2019/09/that-time-i-needed-to-create-20k-shortlinks-and-how-to-create-them-on-aws/).

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](https://s3.amazonaws.com/intricatecloud-content/wp-content/uploads/2019/09/08062438/shortlinks-on-aws-11.png)

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 - gotothat.link so I'll show you how I've set that up.

![registered domains on Route53](https://s3.amazonaws.com/intricatecloud-content/wp-content/uploads/2019/09/22012412/r53-gotothatlink-image.png)

I own gotothat.link 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](https://s3.amazonaws.com/intricatecloud-content/wp-content/uploads/2019/09/22012918/cloudfront-gotothatlink.png)

![s3 origin properties](https://s3.amazonaws.com/intricatecloud-content/wp-content/uploads/2019/09/22013108/s3-origin-cloudfront.png)

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](https://www.intricatecloud.io/2018/04/creating-a-serverless-static-website/) or [ if you want to set it up with terraform](https://www.intricatecloud.io/2018/04/creating-your-serverless-website-in-terraform-part-2/).

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](https://s3.amazonaws.com/intricatecloud-content/wp-content/uploads/2019/09/29204247/s3-upload-metadata.png)

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](https://s3.amazonaws.com/intricatecloud-content/wp-content/uploads/2019/09/22013916/object-metadata-redirect.png)

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://gotothat.link/not-a-rick-roll --website-redirect "https://www.youtube.com/watch?v=dQw4w9WgXcQ"`

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

notarickroll,https://youtube.com/video
no/really/not/a/rickroll/video, https://youtube.com/video
```

```js
// 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)
    s3.putObject({
        Body: '',
        Bucket: 'gotothat.link',
        Key: redirect[0],
        Metadata: {
            'Website-Redirect-Location': redirect[1]
        }
    }, (err, data) => {
        if (err) return console.log(err)
        console.log('done')
    })
})
```

## Verify your redirects

You can check to see that its working by using good ol' `curl` to make a request to your site - gotothat.link, 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 https://gotothat.link/not-a-rick-roll
HTTP/2 301
content-length: 0
location: https://www.youtube.com/watch?v=dQw4w9WgXcQ
date: Sun, 22 Sep 2019 01:52:57 GMT
server: AmazonS3
x-cache: Miss from cloudfront
via: 1.1 96b6c9282feceea8aa00c25902322bb6.cloudfront.net (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 gotothat.link/not-a-rick-roll (check it out - its totally not a rick roll 😎)

## Troubleshooting

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 https://gotothat.link/not-a-rick-roll
HTTP/2 301
content-length: 0
location: https://www.youtube.com/watch?v=dQw4w9WgXcQ
date: Sun, 22 Sep 2019 01:52:57 GMT
server: AmazonS3
x-cache: Hit from cloudfront
via: 1.1 c67ae9899d89f9402837da3a0ead9442.cloudfront.net (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](https://s3.amazonaws.com/intricatecloud-content/wp-content/uploads/2019/09/22015855/invalidations-cloudfront.png)

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


## Wrapping up

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. So two posts coming up next:

- how to do this if you use an infrastructure-as-code tool like terraform
- how to tell when specific links are getting clicked by monitoring your CloudFront logs

If you try out this setup, leave me a :heart: or a comment to let me know how it went - feedback welcome! Stay tuned for the next post and follow me here on dev.to :smile: