0% прочитано

MinIO in Laradock: Local S3-Compatible Storage for Laravel

I start this MinIO series with the foundation: why a local Laravel project benefits from S3-compatible storage, what Laradock already provides, and why this is more convenient than testing file workflows directly against AWS.

7 жовтня 2026 р. 8 хв читанняLaradock

When a Laravel project uses only a local disk, file storage looks simple: files are written into storage and read from the same filesystem.

Production storage often behaves differently. Files may live in S3 or another S3-compatible object store, remain private, upload directly from the browser, and be accessed through temporary URLs.

If local development uses only the local disk, some important production behavior is never exercised.

This is where MinIO became useful for me.

MinIO provides local S3-compatible object storage. Laravel can use it through the same Filesystem S3 driver used for external S3 storage.

Why I Use MinIO Locally

My goal is not to reproduce all of AWS on a laptop.

I need an environment where Laravel talks to object storage through an S3-compatible API instead of a local directory.

This allows me to exercise behavior that differs from a normal local disk:

  • private files;
  • buckets instead of local directories;
  • temporary URLs;
  • direct uploads;
  • S3 endpoints;
  • Laravel Filesystem using the s3 driver.

Local Development Should Not Depend on Real AWS

Technically, a local project could connect directly to AWS.

I do not want that for everyday development.

Local tests should not create accidental files in a real bucket, depend on internet access, or require production-like credentials just to verify an ordinary upload flow.

MinIO keeps that entire cycle inside the Docker environment.

Laradock Already Included a MinIO Service

MinIO is already part of the Laradock structure
laradock/├── docker-compose.yml└── minio/    ├── compose.yml    └── defaults.env

My first step was not to write a new Dockerfile or another Compose service.

I inspected Laradock first.

It already contained a minio service with its own compose.yml and defaults.env.

This is a useful practical rule: before adding another container, check whether the environment already provides the integration.

MinIO Uses Separate Ports for the API and Web Console

Two different MinIO entry points
9000-> S3-compatible API  9001-> MinIO web console

In our Laradock setup, the MinIO API runs on port 9000 and the web console on 9001.

The ports have different purposes.

Laravel talks to the S3-compatible API on 9000.

Port 9001 is useful for development: opening the console, inspecting buckets, checking objects, and reviewing configuration.

localhost Inside a Container Is Not MinIO

The host and Docker network reach MinIO differently
Host browser http://localhost:9001        |        vMinIO console  Laravel / PHP container http://minio:9000        |        vMinIO API

This is an easy detail to miss.

In a browser on my host machine, localhost:9001 refers to the exposed MinIO port.

Inside the PHP container, however, localhost means the PHP container itself.

The application therefore reaches MinIO through the Docker service name:

http://minio:9000

I Start MinIO as a Regular Laradock Service

Start and inspect the container
cd ~/Projects/laradock docker compose up -d minio docker compose ps minio

Because the service already exists in Laradock, I do not need a separate stack just for MinIO.

It runs alongside the other local services and uses the same Docker network.

I Verify MinIO from the PHP Container, Not Only from the Browser

Check from the application container
curl -i \  http://minio:9000/minio/health/live

An accessible web console does not prove that the Laravel container can reach MinIO.

I therefore also checked http://minio:9000/minio/health/live from the PHP environment.

A 200 OK response confirms the same network path the application will later use.

Laravel Still Treats MinIO as S3-Compatible Storage

Example local environment variables
AWS_ACCESS_KEY_ID=laradockAWS_SECRET_ACCESS_KEY=laradockAWS_DEFAULT_REGION=us-east-1AWS_BUCKET=local-files AWS_ENDPOINT=http://minio:9000AWS_USE_PATH_STYLE_ENDPOINT=true

One reason I like this approach is that I do not create a separate MinIO filesystem implementation.

Laravel already works with S3 through Filesystem. For the local environment, credentials, bucket, and endpoint change.

Application code can keep using Storage without knowing whether MinIO or an external S3-compatible service is behind it.

Path-Style Access Matters for Local MinIO

For local MinIO I use AWS_USE_PATH_STYLE_ENDPOINT=true.

The bucket then appears in the request path, which works well with a local endpoint based on the Docker service name.

This avoids requiring separate local DNS names for every bucket.

I Start with a Private Bucket

If files are not meant to be public, I do not make the bucket public merely to simplify local development.

Doing so would hide an important part of production behavior.

A private bucket forces the application to model file access correctly from the beginning.

Why a Normal Local Disk Is Not Enough for This

Different storage models
local disk Laravel  |  vfilesystem path  |  vlocal file  MinIO Laravel  |  v

For a simple Storage::put(), both options may look almost identical.

Behavior diverges as soon as storage requirements become more advanced.

Object storage introduces endpoints, buckets, HTTP access, visibility rules, and signed URL mechanisms.

That is why I want this model present during local development.

What This Enables Next

This is only the first step
MinIO + Laravel Filesystem         |        +--> private files        |        +--> temporary URLs        |        +--> direct browser uploads        |        +--> Range requests        |        +--> local S3 testing

The MinIO container alone does not solve application file handling.

But it gives me a local foundation for testing Laravel Filesystem, private access, temporaryUrl(), direct uploads, and other S3 workflows separately.

Those next steps are what I want to cover in the rest of the series.

What I Check After Connecting MinIO

My basic checklist:

  • Does Laradock already contain a MinIO service?
  • Is the container running?
  • Is the web console available on port 9001?
  • Can the PHP container reach http://minio:9000?
  • Does the health check pass?
  • Does the required bucket exist?
  • Does Laravel use the S3 driver rather than a separate MinIO implementation?
  • Does the Docker-side endpoint use the service name instead of localhost?
  • Do private files remain private?

MinIO Is Not Useful Just Because It Is Another Container

MinIO itself is not the goal.

Its value is that a local Laravel project can work with the same storage model required by S3-compatible production storage.

I can develop without depending on real AWS while still avoiding the oversimplification of a plain local directory.

Laradock makes the first step especially convenient because MinIO is already available as one of its services.

For me, local MinIO is not a replacement for AWS. It is a way to exercise S3 behavior before the code reaches production.

If production relies on object storage, I want to exercise that model locally rather than for the first time after deployment.