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:
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:
- URI Path -> equals -> /
- AND
- Hostname -> equals -> blog.tmk.name
Then...
- Rewrite to -> Static -> index.html
... 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.