Blog | Tristan Kernan

“That some of us should venture to embark on a synthesis of facts and theories, albeit with second-hand and incomplete knowledge of some of them – and at the risk of making fools of ourselves” (Erwin Schrödinger)

Migrating a Static Site from S3 to R2

I host a few static sites (including this blog!), and have journeyed from self hosting on a raspberry pi through to cloud hosting. I migrated to S3 static site hosting, which besides the arcane setup steps is otherwise cheap and easy to maintain. Using cloudflare for dns, though, I had to downgrade the SSL/TSL encryption level, as S3 and cloudflare do not "play nice" together when fronting a bucket with a domain. I decided to move my static sites to R2, cloudflare's object storage offering to restore the encryption level.

Creating a bucket in R2 is simple enough (once one finds the feature in cloudflare's confusing dashboards). From there, head to settings and add a custom domain. Cloudflare will automatically create or convert the relevant DNS record.

For upload, the aws cli supports an --endpoint-url <url> param to interface with other providers (e.g. minio, garage, backblaze, R2, etc.). The makefile command to publish this blog is:

Bash
aws s3 sync "$(OUTPUTDIR)"/ s3://$(R2_BUCKET) --endpoint-url $(R2_URL) --delete

where R2_BUCKET is the bucket name and R2_URL is your S3 compatible URL (it'll look like https://...long string....r2.cloudflarestorage.com). In the R2 dashboard, I generated S3 API keys for use with aws cli; I use direnv to dynamically populate my shell environment variables, there I configured AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

With the bucket created, dns setup, and content uploaded, your public site should be accessible. The first thing you may notice is that root traffic errors out, e.g. blog.tmk.name/ does not serve the blog. It turns out that R2 does not support a "bucket root" item like S3 static site hosting, in other words there's no built-in feature to use index.html as the root page.

Not to worry, cloudflare has a rules feature that solves this pain point. Create a new rule, specifying a custom filter expression:

Then...

... and save. This will implicitly redirect traffic to blog.tmk.name/ to serve index.html. For nested static sites, it's possible to configure the page rule to dynamically serve each folder's index.html - see this helpful community post for details.

All in all, it took me about 30 minutes to migrate from S3 to R2, and upgrade my SSL/TSL encryption.