Cara Koneksi Laravel dengan MinIO sebagai Storage

Pengantar

Dalam membangun aplikasi web, kita sering berhadapan dengan kebutuhan penyimpanan file: mulai dari foto profil, dokumen PDF, hingga video. Biasanya kita menyimpan file di server langsung, tapi cara ini cepat penuh, sulit diskalakan, dan rawan kalau server bermasalah. Di sinilah object storage hadir sebagai solusi. Salah satu teknologi yang populer adalah MinIO. MinIO adalah software penyimpanan objek (object storage) open-source yang sepenuhnya kompatibel dengan Amazon S3 API. Artinya, aplikasi yang biasanya menyimpan file ke Amazon S3 bisa dengan mudah diarahkan ke MinIO tanpa banyak perubahan kode.

Kelebihan MinIO:

  1. Self-hosted → bisa jalan di VPS milik kita sendiri.
  2. Cepat dan ringan → dirancang untuk performa tinggi.
  3. Kompatibel dengan S3 → integrasi mudah dengan banyak framework, termasuk Laravel.
  4. Mendukung skala besar → bisa dipakai untuk data pribadi sampai enterprise.
  5. Jadi, dengan MinIO kita bisa punya “S3 versi pribadi” di server sendiri, lebih hemat biaya, tapi tetap powerful.

Persyaratan

  1. VPS Linux (Ubuntu 22.04/24.04 oke) dengan akses root/SSH.
  2. Domain/subdomain untuk MinIO (opsional tapi direkomendasikan): misalnya minio.example.com.
  3. Laravel 9/10/11 berjalan di lokal (Windows/Mac/Linux).
  4. PHP 8.1+ di lokal.
  5. Composer di lokal.
  6. Akses firewall / reverse proxy (Nginx) untuk buka 80/443.

Setup MinIO di VPS

  1. Login ke Console
    Buka https://console.minio.example.com (atau http://IP:9001 bila belum SSL).
    Login memakai kredensial awal (jika belum pernah set, MinIO akan meminta membuat root user & password saat pertama run melalui env MINIO_ROOT_USER/MINIO_ROOT_PASSWORD.

  2. Buat Bucket
    Masuk menu Buckets → Create Bucket, beri nama: mis. laravelbucket.

Setup Laravel

  1. Pasang dependensi S3 Flysystem
    Gunakan perintah berikut
    composer require league/flysystem-aws-s3-v3:^3.0 aws/aws-sdk-php:^3.0
  2. Konfigurasi config/filesystems.php
    return [
        'default' => env('FILESYSTEM_DISK', 'local'),
    
        'disks' => [
    
            's3' => [
                'driver' => 's3',
                'key' => env('AWS_ACCESS_KEY_ID'),
                'secret' => env('AWS_SECRET_ACCESS_KEY'),
                'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), 
                'bucket' => env('AWS_BUCKET', 'laravelbucket'),
                'url' => env('AWS_URL'),
                'endpoint' => env('AWS_ENDPOINT'),
                'use_path_style_endpoint' => env('AWS_PATH_STYLE_ENDPOINT', true),
                'throw' => false,
            ],
    
        ],
    ];
  3. Isi variabel di .env
    FILESYSTEM_DISK=s3
    
    AWS_ACCESS_KEY_ID=username minio
    AWS_SECRET_ACCESS_KEY=password minio
    AWS_DEFAULT_REGION=us-east-1
    AWS_BUCKET=laravel-media
    
    # Jika pakai domain + SSL (via reverse proxy)
    AWS_ENDPOINT=https://minio.example.com
    
    # WAJIB untuk MinIO
    AWS_PATH_STYLE_ENDPOINT=true

    Jika belum pakai domain dan akses IP: AWS_ENDPOINT=http://IP_VPS:9000

Ujicoba Koneksi dari Laravel Menggunakan php artisan tinker

Gunakan perintah berikut di cmd 

php artisan tinker
>>> use Illuminate\Support\Facades\Storage;
>>> Storage::disk('s3')->put('test/hello.txt', 'Halo dari Laravel!');

Jika hasilnya =>true berarti laravel anda sudah terhubung dengan minio dan file akan muncul di bucket MinIO.

Buat Form di Laravel

  1. Controller 
    Buka terminal dan buat file ini MediaController lalu isi seperti di bawah:
    validate([
                'file' => ['required', 'file', 'max:10240'], // 10MB
            ]);
    
            // Simpan privat (default). Folder 'uploads' bisa anda ganti.
            $path = $request->file('file')->store('uploads', 's3');
    
            // Presigned URL (aman, expired 15 menit)
            $url = Storage::disk('s3')->temporaryUrl($path, now()->addMinutes(15));
    
            return back()->with([
                'ok'  => "Upload OK: {$path}",
                'url' => $url,
            ]);
        }
    
        // Generate presigned URL untuk path tertentu (opsional)
        public function sign(Request $request)
        {
            $request->validate([
                'path' => ['required', 'string'],
                'ttl'  => ['nullable', 'integer', 'min:1', 'max:1440'], // menit
            ]);
    
            $path = $request->string('path');
            abort_unless(Storage::disk('s3')->exists($path), Response::HTTP_NOT_FOUND);
    
            $minutes = (int) ($request->ttl ?? 10);
            $url = Storage::disk('s3')->temporaryUrl(
                $path,
                now()->addMinutes($minutes),
                ['ResponseCacheControl' => 'private, max-age=300']
            );
    
            return response()->json(['url' => $url]);
        }
    
        // Proxy download tanpa mengekspos domain MinIO (opsional)
        public function download(string $path)
        {
            abort_unless(Storage::disk('s3')->exists($path), 404);
    
            $mime = Storage::disk('s3')->mimeType($path) ?? 'application/octet-stream';
            $filename = basename($path);
    
            return new StreamedResponse(function () use ($path) {
                $stream = Storage::disk('s3')->readStream($path);
                fpassthru($stream);
                if (is_resource($stream)) {
                    fclose($stream);
                }
            }, 200, [
                'Content-Type'        => $mime,
                'Content-Disposition' => "inline; filename=\"{$filename}\"",
                'Cache-Control'       => 'private, max-age=300',
            ]);
        }
    }
    

  2. Route
    Buka routes/web.php dan tambahkan kode seperti dibawah
    use App\Http\Controllers\MediaController;
    
    Route::get('/media/form',   [MediaController::class, 'uploadForm'])->name('media.form');
    Route::post('/media/upload',[MediaController::class, 'upload'])->name('media.upload');
    Route::get('/media/sign',   [MediaController::class, 'sign'])->name('media.sign');
    Route::get('/media/d/{path}', [MediaController::class, 'download'])
         ->where('path', '.*')
         ->name('media.download');
    

  3. Buka kembali terminal dan jalankan perintah berikut
    php artisan serve

     

     

  4. Buka browser dan akses halaman berikut 
    127.0.0.1:8000/media/form

     

     

  5. Klik Choose File, kemudian klik Upload

  6. Jika berhasil maka file akan tersimpan di MinIO

Kesimpulan

Dengan MinIO, kita bisa memiliki object storage privat yang powerful seperti Amazon S3, tapi berjalan di VPS milik kita sendiri. Integrasi dengan Laravel pun mudah karena sudah ada driver S3 bawaan.

Beberapa hal penting:

  1. Gunakan Service Account khusus, jangan root user MinIO.
  2. Set .env Laravel dengan AWS_USE_PATH_STYLE_ENDPOINT=true.
  3. Karena bucket private, gunakan temporaryUrl() atau proxy route untuk akses file.
  4. Pastikan VPS sudah diamankan dengan reverse proxy + SSL.

Hasil akhirnya aplikasi Laravel lokal bisa menyimpan, membaca, dan membagikan file dari MinIO di VPS dengan cara yang aman, efisien, dan hemat biaya


Artikel Lain

WhatsApp Kami

Support : +6282138153600

Admin Finance : +6285191239466