I’m hosting this blog on AWS S3 and Cloudfront. One disadvantage with S3 is that it doesn’t have a simple way of creating redirects — like Netlify, Firebase, or even Nginx.

But there is way; using the AWS CLI, put-object, and the x-amz-website-redirect-location metadata.

Here’s how 👇

Hugo

First we need to output all our aliases to a text file; so we define a new output in the Hugo configuration file — in my case config.toml:

[outputs]
  home = ["HTML", "RSS", "Aliases"]

[outputFormats.Aliases]
  baseName = "aliases"
  isPlainText = true
  mediaType = "text/plain"
  notAlternative = true

Then we create the layout file, layouts/index.aliases.txt:

{{- range $p := .Site.Pages -}}
{{- range .Aliases -}}
{{- printf "%s %s\n" . $p.RelPermalink -}}
{{- end -}}
{{- end -}}

Now when we generate our site, we get a aliases.txt file; listing all the aliases with source and target. This is how the file for this site looks:

/series/home-network-v2/ /2021/09/home-network-v2-plans/
/2021/01/optiplex-9010-sff-bios-battery/ /2021/01/optiplex-9010-sff-cmos-battery/
/rack-cabinet/ /2009/05/rack-box-project/
/rack-box/ /2009/05/rack-box-project/
/rss/ /feed/
/atom/ /feed/
/stats/ /sitemap/

Script and deployment

Now we need to “convert” these aliases into S3 redirects. I’m using a small bash script for that:

#!/bin/bash

export AWS_PAGER=""
export AWS_DEFAULT_OUTPUT="text"

BUCKET="s3-bucket"

while read p; do
    stringarray=($p)
    alias=${stringarray[0]}
    target=${stringarray[1]}

    echo "${alias} --> ${target}"
    aws s3api put-object \
	    --bucket $BUCKET \
	    --key ${alias:1}index.html \
	    --website-redirect-location "${target}"

done <public/aliases.txt

It reads the public/aliases.txt file, line by line; and creates a new empty object at the source (alias) key, with the x-amz-website-redirect-location metadata pointing to the target path.

This script requires that AWS CLI is installed, configured, and have PutObject permissions to the S3 bucket.
S3 metadata for /rack-box/index.html

To make this happen on every deployment; I’ve added it as a step in my Drone SSH pipeline:

- name: s3-aliases
  environment:
    AWS_ACCESS_KEY_ID:
      from_secret: AWS_ACCESS_KEY_ID
    AWS_SECRET_ACCESS_KEY:
      from_secret: AWS_SECRET_ACCESS_KEY
  commands:
  - ./aliases_s3.sh
Drone.io build screenshot

And done! Proper 301 redirects with AWS S3 👍

Last commit 2023-02-05, with message: Add some missing tags to posts.