
Mount Folder SMB dari NAS
nanaan
sudo mkdir -p /mnt/nas/sandbox
Mount SMB Secara Otomatis
Agar mount tetap setelah reboot, edit sudo nano /etc/fstab
//192.168.2.8/Web/SANDBOX /mnt/nas/sandbox cifs username=USERNAME,password=YOUR_PASSWORD,vers=3.0,uid=www-data,gid=www-data,file_mode=0777,dir_mode=0777,mfsymlinks 0 0
Ubah Kepemilikan Folder
Jalankan perintah berikut agar Laravel (www-data
) bisa mengakses folder NAS:
sudo chown -R www-data:www-data /mnt/nas/sandbox
sudo chmod -R 775 /mnt/nas/sandbox
➔ chown -R www-data:www-data /mnt/nas/sandbox
: Mengubah kepemilikan folder ke user www-data
.
➔ chmod -R 775 /mnt/nas/sandbox
: Memberikan izin baca & tulis ke www-data
, serta baca ke grup lain.
Cek kembali.
ls -ld /mnt/nas/sandbox
Seharusnya keluar seperti ini.
drwxrwxr-x 2 www-data www-data 0 Feb 5 08:54 /mnt/nas/sandbox
Uji Mounting
Setelah mengedit /etc/fstab
, jalankan perintah berikut untuk memastikan mount berhasil.
sudo mount -a
ls -l /mnt/nas/sandbox
Jalankan perintah berikut untuk memastikan www-data
bisa membuat folder.
sudo -u www-data mkdir /mnt/nas/sandbox/test-folder
Konfigurasi Laravel
Edit config/filesystems.php
, tambahkan disk baru.
'disks' => [
'nas' => [
'driver' => 'local',
'root' => '/mnt/nas/sandbox',
],
],
Lalu di .env
, ubah.
FILESYSTEM_DISK=nas
Jalankan perintah.
php artisan config:clear
php artisan config:cache
Uji Coba Upload File ke NAS
Cara mengunggah file dari aplikasi Laravel ke SMB.
Route::get('/files', [SMBController::class, 'index'])->name('files.index');
Route::get('/files/view/{filename}', [SMBController::class, 'show'])->name('files.show');
Route::get('/upload', [SMBController::class, 'create'])->name('files.create');
Route::post('/upload', [SMBController::class, 'store'])->name('files.store');
Route::delete('/files/{filename}', [SMBController::class, 'delete'])
->where('filename', '.*')
->name('files.delete');
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class SMBController extends Controller
{
public function index()
{
$files = Storage::disk('nas')->files('test-folder');
return view('files.index', compact('files'));
}
public function create()
{
return view('files.create');
}
public function store(Request $request)
{
$request->validate([
'file' => 'required|file',
'id' => 'required|string' // ID manual yang digunakan sebagai nama file
]);
$file = $request->file('file');
$fileName = $request->id . '.' . $file->getClientOriginalExtension(); // Gunakan ID sebagai nama file
// Simpan file ke dalam 'test-folder' dengan nama berdasarkan ID
Storage::disk('nas')->putFileAs('test-folder', $file, $fileName);
return redirect()->route('files.index')->with('success', 'File berhasil diupload atau diperbarui.');
}
public function show($filename)
{
$filePath = "test-folder/$filename";
if (Storage::disk('nas')->exists($filePath)) {
$file = Storage::disk('nas')->get($filePath);
$mimeType = Storage::disk('nas')->mimeType($filePath);
return response($file)->header('Content-Type', $mimeType);
} else {
abort(404);
}
}
public function delete($filename)
{
$filePath = "test-folder/$filename";
if (Storage::disk('nas')->exists($filePath)) {
Storage::disk('nas')->delete($filePath);
return redirect()->route('files.index')->with('success', 'File berhasil dihapus.');
} else {
return redirect()->route('files.index')->with('error', 'File tidak ditemukan.');
}
}
}
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Daftar File di NAS</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container mt-5">
<h1 class="text-center mb-4">Daftar File di NAS</h1>
<a href="{{ route('files.create') }}" class="btn btn-success mb-3">Upload File</a>
<table class="table table-striped table-bordered">
<thead class="table-dark">
<tr>
<th>#</th>
<th>Gambar</th>
<th>Nama File</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
@forelse($files as $index => $file)
<tr>
<td>{{ $index + 1 }}</td>
<td>
<img src="{{ route('files.show', ['filename' => basename($file)]) }}"
alt="{{ basename($file) }}" class="img-thumbnail" width="100">
</td>
<td>{{ basename($file) }}</td>
<td>
<form action="{{ route('files.delete', ['filename' => basename($file)]) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm"
onclick="return confirm('Yakin ingin menghapus file ini?')">Hapus</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="4" class="text-center">Tidak ada file yang tersedia.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Upload atau Edit File</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
<div class="container mt-5">
<h1 class="text-center mb-4">Upload atau Edit File</h1>
@if(session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if(session('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
<div class="card shadow-sm p-4">
<form action="{{ route('files.store') }}" method="POST" enctype="multipart/form-data">
@csrf
<div class="mb-3">
<label for="id" class="form-label">ID (Nama File)</label>
<input type="text" class="form-control" name="id" required placeholder="Masukkan ID file (misal: 123)">
</div>
<div class="mb-3">
<label for="file" class="form-label">Pilih File</label>
<input type="file" class="form-control" name="file" required>
</div>
<button type="submit" class="btn btn-primary">Upload / Edit</button>
<a href="{{ route('files.index') }}" class="btn btn-secondary">Kembali</a>
</form>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>