Skip to content
~/ blog / / make-minio-temporaryUrl-work-in-laravel

How to Make MinIO `temporaryUrl()` Work in Laravel

MinIO's temporaryUrl() doesn't work out of the box with Docker. Here's the minimal config that fixes it.

· 3 min read ·
Laravel MinIO S3 Docker

How to Make MinIO temporaryUrl() Work in Laravel

Laravel’s Storage::disk(‘s3’)->temporaryUrl() generates signed URLs for private files in MinIO. Sounds simple. But if you’re running MinIO inside Docker, the URLs it generates will point to the container’s internal hostname and break in your browser.

Here’s the minimal config that actually works.


Step 1: Set a Stable Container Name

Modify your MinIO service in docker-compose.yml to set a fixed container name:

minio:
  image: "minio/minio:latest"
  ports:
    - "9000:9000"
    - "8900:8900"
  container_name: dev.minio.example.com
  environment:
    MINIO_ROOT_USER: "example"
    MINIO_ROOT_PASSWORD: "password"
  volumes:
    - "example-minio:/data/minio"
  networks:
    - example-network
  command: minio server /data/minio --console-address ":8900"

Why this works

The container name doubles as the hostname. Laravel uses it to reach MinIO inside Docker, and you’ll map it to 127.0.0.1 on your machine (next step) so your browser can reach it too. No VIRTUAL_HOST, no network aliases needed.


Step 2: Update /etc/hosts for Local Access

On your local machine, add the following entry to /etc/hosts (Linux/macOS) or C:\Windows\System32\drivers\etc\hosts (Windows):

127.0.0.1 dev.minio.example.com

Now http://dev.minio.example.com resolves to your local machine. The signed URLs will work in your browser.


Step 3: Generate MinIO Credentials

Don’t use the root credentials in your app. Generate a dedicated access key from the MinIO console:

  1. Open the MinIO Console: http://localhost:8900
  2. Log in with:
    • Username: example
    • Password: password
  3. Navigate to Identity > Users.
  4. Click “Create User” and generate:
    • AWS_ACCESS_KEY_ID
    • AWS_SECRET_ACCESS_KEY
  5. Assign read and write policies to the user.

Step 4: Configure Laravel

Update your .env with the credentials you just created:

AWS_ACCESS_KEY_ID=your_generated_access_key
AWS_SECRET_ACCESS_KEY=your_generated_secret_key
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=test-storage
AWS_URL=http://dev.marketplace-api.example.com:9000/test-storage
AWS_ENDPOINT=http://dev.minio.example.com:9000
AWS_USE_PATH_STYLE_ENDPOINT=true

What each field does:

FieldDescription
AWS_URLYour Laravel app’s URL followed by :minio-port/bucketname.
AWS_ENDPOINTPoints to the MinIO container name with port 9000.
AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEYCredentials generated in MinIO Console.

After updating the .env file, clear Laravel’s configuration and cache:

php artisan config:clear
php artisan cache:clear

Step 5: Generate a Temporary URL in Laravel

That’s it. Generate a signed URL:

use Illuminate\Support\Facades\Storage;
use Carbon\Carbon;

$filePath = 'documents/sample.pdf';
$expiration = Carbon::now()->addMinutes(60); // URL expires in 1 hour

$url = Storage::disk('s3')->temporaryUrl($filePath, $expiration);

return response()->json(['temporary_url' => $url]);

The whole trick

The core problem is hostname resolution. Docker containers use internal hostnames, but your browser needs to reach the same hostname from outside Docker. Setting the container name to a domain and mapping it in /etc/hosts solves both sides at once.

Five minutes of config. No nginx proxy, no network aliases, no custom middleware.