Get expert guidance in a few days with a Laravel code review

Using S3 with Laravel

Published on by

Using S3 with Laravel image

AWS S3 provides a place for us to store files off of our servers. There are some big benefits to this:

  1. Backup/redundancy - S3 and similar have built-in backups and redundancy
  2. Scaling - Savings files off-server becomes necessary in modern hosting, such as serverless or containerized environments, as well as in traditional load-balanced environments
  3. Disk usage - You won't need as much disk space when storing files in the cloud
  4. Features - S3 (and other clouds) have some great features, such as versioning support for files, lifecycle rules for deleting old files (or storing them in a cheaper way), deletion protection, and more

Using S3 now (even in single-server setups) can reduce headaches in the long run. Here's what you should know!

Configuration

There's two places to configure things for S3:

  1. Within Laravel - usually via .env but potentially also within config/filesystem.php
  2. Within your AWS account

Laravel Config

If you check your config/filesystem.php file, you'll see that s3 is an option already. It's setup to use environment variables from your .env file!

Unless you need to customize this, then you can likely leave it alone and just set values in the .env file:

# Optionally Set the default filesystem driver to S3
FILESYSTEM_DISK=s3
# Or if using Laravel < 9
FILESYSTEM_DRIVER=s3
 
# Add items needed for S3-based filesystem to work
AWS_ACCESS_KEY_ID=xxxzzz
AWS_SECRET_ACCESS_KEY=xxxyyy
AWS_DEFAULT_REGION=us-east-2
AWS_BUCKET=my-awesome-bucket
AWS_USE_PATH_STYLE_ENDPOINT=false

The config/filesystem.php file contains options like the following:

return [
'disks' => [
// 'local' and 'public' ommitted...
 
'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),
],
],
];

There's a few options there we didn't use in the .env file. For example, the AWS_URL can be set, which is useful for using other file storage clouds that have an S3 compatible API such as CloudFlare's R2 or Digital Ocean's Spaces.

AWS Configuration

Within AWS, you need to do 2 things:

  1. Create a bucket within the S3 service
  2. Create an IAM User to get a Key/Secret Key, and then attach a Policy to that user that allows access to the S3 API.

Like anything in AWS, creating a bucket in S3 involves looking at a ton of configuration options and wondering if you need any of them. For most use cases, you don't!

Head to the S3 console, create a bucket name (it has to be globally unique, not just unique to your AWS account), choose the region you operate in, and leave all the defaults (including the ones that labeled "Block Public Access settings for this bucket").

Yes, some of these options are ones you may want to use, but you can choose them later.

After creating a bucket, we need permission to do things to it. Let's pretend we created a bucket named "my-awesome-bucket".

We can create an IAM User, select "programmatic access", but don't attach any policies or setup anything else. Make sure to record the secret access key, as they'll only show it once.

I've created a video showing the process of creating a bucket and setting up IAM permissions here: https://www.youtube.com/watch?v=FLIp6BLtwjk

The Access Key and Secret Access Key should be put into your .env file.

Next, click into the IAM User and add an Inline Policy. Edit it using the JSON editor, and add the following (straight from the Flysystem docs):

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1420044805001",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:PutObject",
"s3:PutObjectAcl",
"s3:ReplicateObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::my-awesome-bucket",
"arn:aws:s3:::my-awesome-bucket/*"
]
}
]
}

This allows us to perform the needed S3 API actions on our new bucket.

Laravel Usage

Within Laravel, you can use the file storage like so:

# If you set S3 as your default:
$contents = Storage::get('path/to/file.ext');
Storage::put('path/to/file.ext', 'some-content');
 
# If you do not have S3 as your default:
$contents = Storage::disk('s3')->get('path/to/file.ext');
Storage::disk('s3')->put('path/to/file.ext', 'some-content');

The path to the file (within S3) gets appended to the bucket name, so a file named path/to/file.ext will exist in s3://my-awesome-bucket/path/to/file.ext.

Directories technically do not exist within S3. Within S3, a file is called an "object" and the file path + name is the "object key". So, within bucket my-awesome-bucket, we just created an object with key path/to/file.ext.

Be sure to check out the Storage area of the Laravel docs to find more useful ways to use Storage, including file streaming and temporary URL's.

Pricing

S3 is fairly cheap - most of us will spend pennies to a few dollars a month. This is especially true if you delete files from S3 after you're done with them, or setup Lifecycle rules to delete files after a set period of time.

The pricing is (mostly) driven by 3 dimensions. The prices vary by region and usage. Here's an example based on usage for a real application in a given month for Chipper CI (my CI for Laravel application), which stores a lot of data in S3:

  1. Storage: $0.023 per GB, ~992GB ~= $22.82
  2. Number of API Calls: ~7 million requests ~= $12
  3. Bandwidth usage: This is super imprecise. Data transfer for this was about $23, but this excludes EC2 based bandwidth charges.

Useful Bits about S3

  1. If your AWS setup has servers in a private network, and uses NAT Gateways, be sure to create an S3 Endpoint (type of Gateway). This is done within the Endpoints section in the VPC service. This allows calls to/from S3 to bypass the NAT Gateway and thus get around extra bandwidth charges. It doesn't cost extra to use this.
  2. Considering enabling Versioning in your S3 bucket if you're worried about files being overwritten or deleted
  3. Consider enabling Intelligent Tiering in your S3 bucket to help save on storage costs of files you likely won't interact with again after they are old
  4. Be aware that deleting large buckets (lots of files) can cost money! This is due to the number of API calls you'd have to make to delete files.
Chris Fidao photo

Teaching coding and servers at CloudCasts and Servers for Hackers. Co-founder of Chipper CI.

Cube

Laravel Newsletter

Join 40k+ other developers and never miss out on new tips, tutorials, and more.

image
Jump24 - UK Laravel Agency

Laravel Developers that Click into Place. Never outsourced. Never offshored. Always exceptional.

Visit Jump24 - UK Laravel Agency
Bacancy logo

Bacancy

Supercharge your project with a seasoned Laravel developer with 4-6 years of experience for just $3200/month. Get 160 hours of dedicated expertise & a risk-free 15-day trial. Schedule a call now!

Bacancy
Tinkerwell logo

Tinkerwell

The must-have code runner for Laravel developers. Tinker with AI, autocompletion and instant feedback on local and production environments.

Tinkerwell
Get expert guidance in a few days with a Laravel code review logo

Get expert guidance in a few days with a Laravel code review

Expert code review! Get clear, practical feedback from two Laravel devs with 10+ years of experience helping teams build better apps.

Get expert guidance in a few days with a Laravel code review
PhpStorm logo

PhpStorm

The go-to PHP IDE with extensive out-of-the-box support for Laravel and its ecosystem.

PhpStorm
Laravel Cloud logo

Laravel Cloud

Easily create and manage your servers and deploy your Laravel applications in seconds.

Laravel Cloud
Acquaint Softtech logo

Acquaint Softtech

Acquaint Softtech offers AI-ready Laravel developers who onboard in 48 hours at $3000/Month with no lengthy sales process and a 100 percent money-back guarantee.

Acquaint Softtech
Kirschbaum logo

Kirschbaum

Providing innovation and stability to ensure your web application succeeds.

Kirschbaum
Shift logo

Shift

Running an old Laravel version? Instant, automated Laravel upgrades and code modernization to keep your applications fresh.

Shift
Harpoon: Next generation time tracking and invoicing logo

Harpoon: Next generation time tracking and invoicing

The next generation time-tracking and billing software that helps your agency plan and forecast a profitable future.

Harpoon: Next generation time tracking and invoicing
Lucky Media logo

Lucky Media

Get Lucky Now - the ideal choice for Laravel Development, with over a decade of experience!

Lucky Media
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS Starter Kit

SaaSykit is a Multi-tenant Laravel SaaS Starter Kit that comes with all features required to run a modern SaaS. Payments, Beautiful Checkout, Admin Panel, User dashboard, Auth, Ready Components, Stats, Blog, Docs and more.

SaaSykit: Laravel SaaS Starter Kit

The latest

View all →
The Inertia v3 Beta is Here image

The Inertia v3 Beta is Here

Read article
Polyscope Is an Ai-First Dev Environment for Orchestrating Agents image

Polyscope Is an Ai-First Dev Environment for Orchestrating Agents

Read article
Filament v5.3.0 Released with Deferred Tab Badges and Column Manager Improvements image

Filament v5.3.0 Released with Deferred Tab Badges and Column Manager Improvements

Read article
Ward: A Security Scanner for Laravel image

Ward: A Security Scanner for Laravel

Read article
Kit: An Opinionated API Starter Kit for Laravel image

Kit: An Opinionated API Starter Kit for Laravel

Read article
Livewire v4.2.0 Released with Security Hardening and Laravel 13 Support image

Livewire v4.2.0 Released with Security Hardening and Laravel 13 Support

Read article