Static web sites are awesome. They are fast, scale well, and are cheap to host. One unfortunate drawback is the necessity of using HTML to redirect to another URL.
However, this limitation can be overcome if the site is hosted on S3.
TL;DR Create an object in an S3 bucket with a Key that corresponds to the desired source URL and set the Website-Redirect-Location
metadata property on the object to the target URL.
Requests for the object will be redirected to the configured URL (works with or without CloudFront assuming static website hosting is enabled).
Use parse-refresh-redirect with s3-publish to set Website-Redirect-Location
automatically as files are uploaded.
The Problem
Static site generators like Hugo will output a file similar to the one below in order to redirect one page to another.
public/page/1/index.html
|
|
This works well enough when visiting the site in a browser, but the redirect does not occur when accessing the site via other means (curl
for example).
For this and other reasons (SEO, etc.) it’s better for the server to return a proper 301 or 302 response when a redirect is intended (as opposed to a 200 response with an HTML body that contains a <meta http-equiv="refresh">
element).
The Solution
Setting the Website-Redirect-Location
metadata property of an S3 object will cause requests for that object to return a 302 redirect response.
See configuring a webpage redirect for how to manually set this for individual files.
Note: This solution leaves the file content unchanged, so the redirects also work as they normally do when running the site locally for development.
Automation
s3-publish and parse-refresh-redirect were purpose-built (by me) to make this sort of thing easier.
Requirements
- Node.js LTS (includes
npm
andnpx
)
Getting Started
If your project does not already have a package.json file, create one:
npm init -y
Install s3-publish
and parse-refresh-redirect
as development dependencies:
npm install -D s3-publish parse-refresh-redirect
Creating a Config File
Create a .s3p.config.js file in your project root:
npx s3p init
The example below will upload all (non-hidden) changed/missing files in the ./public directory to the S3 bucket named blog.atj.me and set the Website-Redirect-Location
metadata (via the WebsiteRedirectLocation
param) if the file has the extension .html and it contains a <meta http-equiv="refresh" content="..." />
element.
.s3p.config.js
|
|
Uploading Files
Use the following command to upload all changed files from the origin to the target and delete any files found in the target not present in origin:
npx s3p sync
You will be prompted before any operations are performed.
Use -y
to skip prompt and proceed or -n
for a dry run.
Updating an Existing Site
Nothing to do
When you run npx s3p sync
and the origin files already match the target files, you will be greeted with a “Nothing to do” message.
To force files to be re-uploaded (for the purposes of setting metadata, etc),
use the -c
argument to skip the comparison and assume all files have changed.
First Run
npx s3p sync -c -i '**/*.*' -i '!**/*.html' --no-delete
Running the command with the above options will upload all HTML files (that are not otherwise ignored) without comparing the MD5 hashes to determine if the files have changed (to ensure the metadata is set).
Note: Files are not deleted by default; the --no-delete
argument is included in the example in case delete: true
is set in the config file. There are no negative effects to passing --no-delete
unnecessarily.