January 1, 2024 · 5 min read · 3,426 views
Are you on the hunt for a more affordable and efficient object storage solution than AWS S3? Look no further than Cloudflare R2, an S3-compatible storage service that boasts zero egress fees and a generous free tier, making it a wallet-friendly choice for developers and businesses alike. In this comprehensive guide, I'll take you through the process of integrating Cloudflare R2 with your Laravel application, ensuring a smooth transition and significant cost reductions. From installation to configuration, and even setting up public access, every step is covered to help you leverage Cloudflare R2's full potential with Laravel.
When comparing Cloudflare R2 and Amazon S3 for object storage, Cloudflare R2 offers a compelling free tier with 10 GB of storage and substantial operation allowances, as opposed to S3's 5 GB and fewer operations. R2's absence of egress fees can result in significant cost savings, especially for high data retrieval needs, while it strives to compete with S3's global reliability and speed.
Cloudflare R2 not only provides an S3-compatible API and migration tool for easy switching but also boasts lower storage and operation costs post-free tier, positioning it as a cost-effective solution for high-volume data users. Meanwhile, Amazon S3 is a reliable contender, particularly for those already invested in the AWS ecosystem, but users should consider both financial and technical factors to choose the service that best aligns with their requirements.
Since Cloudflare R2 offers a S3 Compatible API, we can seamlessly integrate the league/flysystem-aws-s3-v3
driver to work in tandem with it. We can install the driver with the following command:
composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies
Next, you'll need to update your disk configuration. In your Laravel project, locate and edit the config/filesystems.php
file to include a new r2
disk configuration as follows:
<?php
return [
/*
|--------------------------------------------------------------------------
| Default Filesystem Disk
|--------------------------------------------------------------------------
|
| Here you may specify the default filesystem disk that should be used
| by the framework. The "local" disk, as well as a variety of cloud
| based disks are available to your application. Just store away!
|
*/
'default' => env('FILESYSTEM_DISK', 'local'),
/*
|--------------------------------------------------------------------------
| Filesystem Disks
|--------------------------------------------------------------------------
|
| Here you may configure as many filesystem "disks" as you wish, and you
| may even configure multiple disks of the same driver. Defaults have
| been setup for each driver as an example of the required options.
|
| Supported Drivers: "local", "ftp", "sftp", "s3"
|
*/
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
'r2' => [
'driver' => 's3',
'key' => env('CLOUDFLARE_R2_ACCESS_KEY_ID'),
'secret' => env('CLOUDFLARE_R2_SECRET_ACCESS_KEY'),
'region' => 'us-east-1', // Cloudflare R2 doesn't have specific regions, so 'us-east-1' is fine.
'bucket' => env('CLOUDFLARE_R2_BUCKET'),
'url' => env('CLOUDFLARE_R2_URL'),
'visibility' => 'private',
'endpoint' => env('CLOUDFLARE_R2_ENDPOINT'),
'use_path_style_endpoint' => env('CLOUDFLARE_R2_USE_PATH_STYLE_ENDPOINT', false),
'throw' => false,
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
// 'visibility' => 'public', // https://statamic.dev/assets#visibility
],
'assets' => [
'driver' => 'local',
'root' => public_path('assets'),
'url' => '/assets',
'visibility' => 'public',
],
],
/*
|--------------------------------------------------------------------------
| Symbolic Links
|--------------------------------------------------------------------------
|
| Here you may configure the symbolic links that will be created when the
| `storage:link` Artisan command is executed. The array keys should be
| the locations of the links and the values should be their targets.
|
*/
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
Let's go ahead and update our environment file with the necessary variables. Remember, it's always a good practice to keep the .env.example
file in sync as well. By doing so, you'll be helping your fellow collaborators to set up their environments more efficiently.
CLOUDFLARE_R2_ACCESS_KEY_ID=
CLOUDFLARE_R2_SECRET_ACCESS_KEY=
CLOUDFLARE_R2_BUCKET=
CLOUDFLARE_R2_ENDPOINT=
CLOUDFLARE_R2_URL=
Let's get started with setting up your storage bucket on Cloudflare! First, log in to your Cloudflare dashboard. Look for the "R2" section in the sidebar and click on it. Once you're there, you'll see an option to "Create bucket" – go ahead and select that. For this guide, we'll name our new bucket images
.
Next up is deciding on the location for your bucket. If your application needs to comply with GDPR, we recommend using the Specify Jurisdiction
option and selecting the European Union
to ensure compliance. For everyone else, choosing Automatic
will let Cloudflare intelligently serve your assets from the location nearest to your users, optimizing for speed and efficiency.
To begin, navigate to the R2 page within your Cloudflare dashboard and click on Manage R2 API Tokens
. Here, you'll want to create a new token and grant it Object Read & Write
permissions, ensuring that it is specifically associated with the images
bucket we previously set up. It's important to avoid assigning full access to your API key, as this can lead to a security nightmare.
After you've successfully created the token, Cloudflare will provide you with an Access Key ID
and a Secret Access Key
. You must keep these credentials safe and secure, as they are the keys to accessing your Cloudflare resources programmatically. Treat them with the same level of security you would for your most confidential information.
If you need to keep your bucket private, skip this step!
To make your files publicly accessible, you'll need to activate the Public Access
feature for your bucket. The good news is that if you're using Cloudflare as your DNS provider, this process is simplified for you. All you need to do is specify the domain you wish to use. In our case, we've chosen assets.luckymedia.dev
as our domain.
Once you've linked a custom domain to your storage bucket, anyone can access the contents of your bucket through that domain. Moreover, your application can reap the advantages of Cloudflare, including bot management, the Access service, and enhanced caching capabilities.
When you attempt to upload files using the Storage
facade, you might encounter a CORS error. This happens because CORS policies require proper configuration to allow resource sharing between different origins. To ensure a smooth integration, it's essential to set up CORS correctly. Here's how you can do it step by step:
Head over to your bucket, go to the CORS Policy
and click on the Add CORS Policy
button.
You can add two origins ( local and production ):
The
.test
domain is our local Valet domain that we use for testing.
[
{
"AllowedOrigins": [
"http://luckymedia-api.test",
"https://www.luckymedia.dev"
],
"AllowedMethods": [
"GET",
"POST",
"DELETE",
"PUT",
"HEAD"
]
}
]
With the credentials that were shown to you in the previous step, we now need to update our env
file as shown below:
CLOUDFLARE_R2_ACCESS_KEY_ID=ACCESS_KEY
CLOUDFLARE_R2_SECRET_ACCESS_KEY=SECRET_KEY
CLOUDFLARE_R2_BUCKET=BUCKET_NAME
CLOUDFLARE_R2_ENDPOINT=ENDPOINT_URL
CLOUDFLARE_R2_URL=https://assets.luckym.dev
All set to go! You can now seamlessly integrate your R2 storage with the Laravel Storage facade. Here's a small example from the Laravel documentation:
use Illuminate\Support\Facades\Storage;
Storage::disk('r2')->put('example.txt', 'Contents');
For added convenience, you can set r2
as your default disk in your .env
file, eliminating the need to specify disk('r2')
each time:
FILESYSTEM_DISK=r2
There you have it—a step-by-step guide to integrating Cloudflare R2 with your Laravel application. Enjoy the savings and the seamless experience!
If you need help with a Laravel project let's get in touch.
Lucky Media is proud to be recognized as a Top Laravel Development Agency
Technologies:
Related Posts
Stay up to date
Be updated with all news, products and tips we share!