Local and Public Disks

The Local Disk and the Public Disk

Both use the local driver. local roots at storage/app/private, for files no visitor may fetch; public roots at storage/app/public, with a url base of APP_URL/storage. Run through php artisan tinker --execute:

Writing to the private local disk and the public diskPHP
Storage::put('invoices/1.pdf', file_get_contents(base_path('samples/invoice-1.pdf')));
Storage::disk('public')->put('banners/autumn.txt', 'Autumn sale: 20% off SQL titles');
echo Storage::path('invoices/1.pdf'), PHP_EOL;
echo Storage::disk('public')->url('banners/autumn.txt'), PHP_EOL;
var_dump(Storage::exists('invoices/1.pdf'), Storage::disk('public')->exists('invoices/1.pdf'));
Output
/var/www/bookshop/storage/app/private/invoices/1.pdf
http://127.0.0.1:8317/storage/banners/autumn.txt
bool(true)
bool(false)

Disks are separate namespaces. The URL first answered 403: the web root is public/, so the request fell through to Laravel 2,157 , where the local disk's 'serve' => true route at /storage/{path} admits only signed URLs (File URLs). php artisan storage:link replied The [public/storage] link has been connected to [storage/app/public], and the same URL then returned the banner with 200, served as a static file without starting PHP. .gitignore excludes the link, so run storage:link on every deployment, and let Apache follow it with Options FollowSymLinks or SymLinksIfOwnerMatch.