Laravel Podman

S3

S3 Buckets

podman:s3-setup creates the S3 buckets your app needs and applies a CORS policy to the ones browsers access directly. It talks to S3 over the API, so it needs no aws CLI or extra container.

Requirement: the AWS SDK

You need aws/aws-sdk-php, which isn't required by default — many apps don't use S3, and the SDK is large:

composer require aws/aws-sdk-php

Without it, podman:s3-setup fails with a clear error instead of a crash. Other commands are unaffected.

Credentials

This reuses your app's existing s3 disk config in config/filesystems.php (key, secret, region, endpoint, use_path_style_endpoint), so there's no second credential config to keep in sync. It works with AWS S3 and with S3-compatible services that support signed URLs (MinIO, RustFS, Garage, and others).

Configuring buckets

Both lists are empty by default, so podman:s3-setup is a no-op until you list buckets:

's3_buckets' => env('PODMAN_S3_BUCKETS', [
    'local', 'conversions', 'segments', 'secrets',
]),

's3_cors_buckets' => env('PODMAN_S3_CORS_BUCKETS', [
    'conversions', 'segments', 'secrets',
]),
Key Purpose
s3_buckets Every bucket to create. This is idempotent — existing buckets still count as success.
s3_cors_buckets Which of those buckets get the CORS policy. Must be a subset of s3_buckets.

Both accept a plain PHP array or a comma-separated string.

The CORS policy

This is read from the s3 preset's cors.json (containers/stubs/s3/ if published, otherwise the package's own copy). There's no quadlets//runtimes/ involved, and no podman:generate step either:

php artisan podman:publish s3
php artisan podman:s3-setup

Edit containers/stubs/s3/cors.json, which follows the standard S3 CORS JSON format:

{
    "CORSRules": [
        {
            "AllowedOrigins": ["*"],
            "AllowedMethods": ["GET", "HEAD"],
            "AllowedHeaders": ["*"],
            "ExposeHeaders": ["Content-Length", "Content-Range", "Accept-Ranges", "ETag"],
            "MaxAgeSeconds": 7200
        }
    ]
}

Any bucket read directly by <img>, <video>, or fetch() needs this. Buckets only ever touched server-side (e.g. by queued jobs) usually don't.

Usage

php artisan podman:s3-setup

This creates every s3_buckets entry, then applies CORS to s3_cors_buckets:

Creating buckets...
  -> local
  -> conversions
  -> segments
  -> secrets
Applying CORS policy...
  -> conversions
  -> segments
  -> secrets
Done.