Cloudflare R2 as img hosting even with localhost

Sun May 26 2024

I struggled a lot to set my instance of R2 to work with my astro http://localhost:4321 dev domain here is how I solved it.

Recently for this portfolio project, I started thinking that it would be a better idea to store the images outside of the project’s folder, the main reasons that lead me to this conclusion was that though Astro provides great utilities to optimize images sizes, it only does it to reduce initial load times of pages, it will not really save you any money depending on the hosting services you are using, you could end up having an unpayable bill if your site faces an attack, I have seen on social media horror cases of this happening with Netlify and Vercel.

Since I started my journey on cloud services with Cloudflare, I researched a little bit about solutions to store static files and ran into R2, which allows you to create a bucket to put the resources there either via API calls or directly from the dashboard using your browser.

Everything was looking good, until I got to the implementation and found out that my images were not public out of the box, I needed to configure the bucket a little bit. So, here is a little bit of context.

I have my own domain for this site “alan-s-malagon.com”, inside Cloudflare too but you can have it anywhere else, then also once I created my bucket and uploaded the files, in order to make them public, I needed to configure a custom domain for the R2 bucket, which I set as “assets.alan-s-malagon.com”, directly configurable from the bucket settings.

After doing that it worked… kind of, the images were now available via internet by typing the domain, slash, and the name of the file, so you could go to the browser and type “assets.alan-s-malagon.com/both-buttons.jpg” in the search bar and it will take you to the image. All good so far, but while running the project in dev mode, it will run under the “localhost:4321” hostname and as you can expect the CORS policy was preventing the assets to be loaded in a site that is not the same where the images are stored.

Thankfully the bucket comes with a tool in the dashboard to configure the CORS policy applied to it, to save you a lot of back and forth I went through, I can tell you this is what worked for me in order to make the assests accessible from anywhere.

[
  {
    "AllowedOrigins": ["*"],
    "AllowedMethods": ["GET"],
    "AllowedHeaders": ["Content-Type", "Access-Control-Allow-Origin"]
  }
]

This CORS policy is basically saying, let the resources be accessible from any domain, let them ONLY use the HTTP GET method, let the responses use the headers Content-Type and Access-Control-Allow-Origin.

But also, this won’t do the trick alone, combine it with the referrerpolicy=“no-referrer” attribute in your img tags like this

<img
  src="assets.alan-s-malagon.com/both-buttons.jpg"
  alt="descriptive message of the img"
  referrerpolicy="no-referrer"
/>

And voilá, that should be enough to make it work even in your “localhost:4321” or whatever port you want to have: 3000, 8080, etc.